Learning the AsmBB source code

0
#
(ツ) admin
Last edited: 02.03.2023 by admin
3149
03.12.2022

Well, I can help by shortly describing the structure of the project. But notice that because of using FastCGI protocol, AsmBB is a little bit more complex than usual for beginner assembly programmer.

The simple CGI web application (for example my CMS MiniMagAsm) works by short living CGI processes. They are started by the web server, receive the HTTP request by reading STDIN, write the response (e.g. HTML) to STDOUT and terminate.

The FastCGI application works a little bit different. At first it works all the time and listens for connections on some socket. The web server connects to this socket and sends the request. Then the FastCGI application sends back the response using the same connection. Serving multiply requests on the same connection and multiply connections are possible. Also, the web server can start several instances of the FastCGI application. It is all about a performance. So, the structure of AsmBB:

Everything starts in engine.asm, line:123 - the label start:. Here the engine initializes its environments and opens the SQLite database with the forum data. Then it calls the procedure Listen (line: 163) that is the main loop of the program. It returns only when the engine terminates. After retuning from Listen, the program closes the database, finalizes its works and exits.

The procedure Listen is defined in the source file fcgi.asm:166. This is the code, that handles FastCGI protocol. It simply listens for connections from the web server and on connection creates a thread that to serve the request and continues to listen. The thread is started in the procedure procServeRequest in fcgi.asm:347.

This thread, receives the request information on the socket and collects it for future processing.

Once the whole information is collected - i.e. the HTTP reques, the POST data (if any) and the environment parameters, the procedure ServeOneRequest is called. It is actually the "business logic" code that makes the application to act as a web forum.

ServeOneRequest returns the response (e.g. HTML code, images, etc.) that is returned to the web server, according to FastCGI protocol. After completing the request, the thread terminates or stays waiting for another request. It depends on how the web server can multiplex the requests on the FastCGI connection.

ServeOneRequest is located in the file commands.asm:127. It analyzes the request URL and the request type (GET, POST) and decides how to serve it. For example, it can return some file directly, or read the information from the database, or store some information in the database.

The URL analyze is important and located on commands.asm:427 - it dispatches the control depending on the URL elements. The addresses of the different procedures are loaded to ECX and later called (label .exec_command, line: 598).

Later you can browse these procedures. They are located in different files, serving different aspects of forum engine. For example, the procedure ListThreads threadlist.asm creates the list of threads on the front page of the forum.

The procedure ShowThread showthread.asm displays one thread. And so on.

Notice, that AsmBB widely uses the library FreshLib. You can read more in FreshLib reference and FreshLib user guide, but unfortunately the documentation is far from perfect.

In order to better browse the big code, scattered across multiply files, I would suggest using Fresh IDE code browsing features. Read more in the following article: Tips and tricks. Especially useful if the feature "Goto definition" (Ctrl+D) that will jump you at the line where some label is defined. The cross reference is also useful (Ctrl+R).

FreshLib user guide

Attached files:
FileSizeUploadedDownloadsMD5 hash
matrix.png25084 bytes02.03.202372336e343bc25314f54ffcf4d982063c167
(ツ) Guest
Last edited: 24.11.2025 by Guest
272
22.10.2025

This assembly file, engine.asm, is the main entry point and core engine for AsmBoard, a message board (forum) written entirely in x86 assembly language. It uses the FreshLib library to abstract operating system differences and SQLite for its database.

It's designed to run as a backend service using the FastCGI protocol, which means a web server (like Nginx or Apache) forwards web requests to this running application.

Here is a detailed breakdown of how it works.


Core Functionality

The file's primary responsibilities are:

  • Initialization: Setting up the application, signal handlers, and the SQLite database.

  • Service Threads: Launching background threads, specifically for Server-Sent Events (SSE) to handle real-time updates (like chat or new post notifications).

  • Main Loop: Entering the main FastCGI Listen loop, where it waits for and processes incoming web requests.

  • Debug System: Providing a comprehensive, built-in debugging system to track SQLite resource leaks and system status. This is a major feature of this specific file, enabled by options.DebugSQLite = 1.

  • Shutdown: Handling graceful shutdown signals (like SIGTERM) to close the database and clean up resources properly.

The include directives at the top show the full scope of the AsmBoard project, pulling in modules for every feature, including:

  • Forum Features: threadlist.asm, showthread.asm, edit.asm, delete.asm, search.asm

  • User Features: accounts.asm, userinfo.asm, users_online.asm

  • Real-time: chat.asm, realtime.asm, sse_service.asm

  • Core: http.asm, fcgi.asm, sqlite3.asm


    Program Flow (The start: label)

    This is the main execution path when the application is launched.

    1. FreshLib Init: InitializeAll sets up the FreshLib environment.

  1. SQLite Debugger Setup:

    • The code checks the options.DebugSQLite flag, which is set to 1 (on) in this file.

    • Because it's on, it calls InitSQLStmtDebugger. This "hooks" the standard SQLite functions.

    • Global function pointers sqlitePrepare_v2 and sqliteFinalize are set to point to the custom wrappers my_sqlitePrepare_v2 and my_sqliteFinalize. This is done to track every SQLite statement that is created and destroyed.

  1. Signal Handlers:

    • SetSegmentationFaultHandler: Catches crashes (like SIGSEGV) and routes them to the OnException procedure.

    • SetForcedTerminateHandler: Catches graceful shutdown signals (like SIGTERM) and routes them to the OnForcedTerminate procedure.

  1. SQLite Initialization:

    • sqliteConfig, SQLITE_CONFIG_SERIALIZED: Configures SQLite to be thread-safe.

    • sqliteInitialize: Loads the SQLite library.

    • OpenOrCreate: This custom function attempts to open the database file (./board.sqlite). If the file doesn't exist, it uses the SQL code from create.sql (loaded into sqlCreateDB) to create the entire database schema.

  1. Encryption Check:

    • The OpenOrCreate function returns 1 in eax if the database is encrypted and needs a key.

    • If so, it sets the fNeedKey flag.

  1. Database Configuration:

    • SQLiteRegisterFunctions: Registers custom functions (defined in sqlite3.asm) so they can be called from within SQL queries.

    • SetDatabaseMode: This procedure is called to set optimal PRAGMAs (settings) for the database.

  1. IPC and Background Threads:

    • InitEventsIPC: Initializes the Inter-Process Communication system, which is used to coordinate between threads.

    • ThreadCreate, sseServiceThread, 0: Starts the Server-Sent Events (SSE) service in a new thread. This thread manages real-time push notifications to clients.

  1. Main Loop:

    • stdcall Listen: This is the heart of the application. It's the main FastCGI loop. The program's execution stops here and waits for the web server to send a request.

    • When a request comes in, this function (or a new thread it spawns) handles it. It only exits this loop when a shutdown is triggered.

  1. Shutdown Sequence (start.terminate):

    • This code block is jumped to when Listen exits or when a signal handler forces a shutdown.

    • Database Close Retry Loop: It tries to close the SQLite database (sqliteClose). This might fail with SQLITE_BUSY if other threads are still finishing queries.

    • The code will Sleep for 10ms and retry up to 30 times (300ms total).

    • If it still can't close the database, it prints an error message to STDERR.

    • sqliteShutdown: Shuts down the SQLite library.

    • FinalizeAll / TerminateAll: Cleans up FreshLib and exits the process.


      Key Procedures

      SetDatabaseMode

      This procedure is critical for performance. It sets several SQLite PRAGMAs:

  2. sqliteBusyTimeout, 5000: If the database is locked, wait up to 5 seconds before giving up.

  3. PRAGMA foreign_keys = TRUE: Enforces data integrity.

  4. PRAGMA journal_mode = WAL: Write-Ahead Logging. This allows "readers" (users browsing) and "writers" (users posting) to run concurrently.

  5. PRAGMA synchronous = OFF: Disables "full sync" on writes for maximum performance.

Shutdown Handlers (OnForcedTerminate, OnException)

These procedures handle system signals for shutting down.

  1. They both call __ForceTerminate.

  2. They set the process exit code (0 for normal, 1 for exception).

  3. They jmp directly to the start.terminate cleanup block.

__ForceTerminate is the function that does the real work:

  • lock inc [fEventsTerminate]: Atomically sets a global flag to signal all threads to terminate.

  • stdcall SignalNewEvent: Wakes up any sleeping threads so they can check the termination flag.

  • stdcall SocketClose, [STDIN]: In FastCGI, STDIN is the socket for receiving requests. Closing it tells the web server this backend process is dead.


    SQLite Debugging System

    Because options.DebugSQLite is enabled, a large portion of this file is dedicated to a powerful debug system for finding resource leaks.

    How it works:

    1. Hooking: InitSQLStmtDebugger makes the program call my_sqlitePrepare_v2 and my_sqliteFinalize instead of the real SQLite functions.

    2. Tracking:

      • my_sqlitePrepare_v2: Every time an SQL query is "prepared," this wrapper function logs the new statement handle and the code address of the caller into a global array (ptrSQList).

      • my_sqliteFinalize: Every time a statement is "finalized," this wrapper removes that statement handle from the ptrSQList array before calling the real _sqliteFinalize.

    3. Reporting (DebugInfo / ListSQLiteStatus):

      • The DebugInfo procedure is a special page for admins that calls ListSQLiteStatus.

      • ListSQLiteStatus builds an HTML debug page that shows:

        • Not finalized SQLite statements: It iterates through the ptrSQList. Any statements still in this list are leaks. It prints the statement handle and the caller's address.

        • SSE listeners: Shows how many users are currently connected to the real-time event service.

        • Engine overload: Checks the current thread count.

        • StrLib statistics: Dumps the string-memory manager, including a list of allocated strings.

Learning the AsmBB source code

0
#