NAME

mpx_session -- run a multiplexed network service on a given port


SYNOPSIS

   #include <afblib/mpx_session.h>
   typedef struct session {
      void* handle;
      stralloc request;
      stralloc response;
   } session;
   typedef void (*request_handler)(session* s);
   typedef void (*hangup_handler)(session* s);
   void send_response(session* s);
   void close_session(session* s);
   void run_mpx_service(in_port_t port,
      request_handler rhandler, hangup_handler hhandler);


DESCRIPTION

run_mpx_service creates a socket that listens on port, accepts all incoming connections, invokes rhandler for every newline-terminated input line from any of the network connections, and calls hhandler whenever a network connection terminates.

Request handlers get a session reference with following fields:

handle

This field is initially null and may be freely used to maintain a pointer to a custom session object.

request

This stralloc object contains one input line from the given connection. The terminating line-feed, and a possibly preceding carriage-return are already removed.

response

This stralloc object is initially empty whenever a request handler gets called. This string object may be filled (without terminating null-bytes, carriage-returns or line-feeds) to create a response packet. If this field remains empty, no response is sent back. Instead, a delayed reponse may be sent any time later on by using send_response.

close_session may be called to initiate the shutdown of a session, i.e. no further input packets will be processed, just the pending response packets will be taken care of.

run_mpx_service runs normally infinitely and returns in error cases only.


EXAMPLE

Following example implements a network service that allows to increment whole numbers. Usually, every session has its own number that gets incremented. But, by adding the keyword global to an increment, a global counter that is shared over all sessions gets incremented.

   #include <afblib/mpx_session.h>
   #include <afblib/tokenizer.h>
   #include <stralloc.h>
   #include <stdlib.h>
   #include <stdio.h>
   #include <string.h>
   struct status {
      int count; // per-session counter
   };
   int global_counter = 0; // global counter, shared by all sessions
   void handle_request(session* s) {
      if (s->handle == 0) {
         // new network connection, create a new status object for it
         struct status* sp = (struct status*) malloc(sizeof(struct status));
         if (sp == 0) return;
         sp->count = 0;
         s->handle = (void*) sp;
      }
      struct status* sp = (struct status*) s->handle;
      strlist tokens = {0};
      stralloc_0(&s->request); // 0-termination required by tokenizer
      if (!tokenizer(&s->request, &tokens)) return;
      int value = 0;
      if (tokens.len > 0) {
         int increment;
         if (sscanf(tokens.list[0], "%d", &increment) == 1) {
            if (tokens.len == 2 && strcmp(tokens.list[1], "global") == 0) {
               global_counter += increment;
               value = global_counter;
            } else {
               sp->count += increment; 
               value = sp->count;
            }
         }
      }
      // return current value of the chosen counter as response
      stralloc_catint(&s->response, value);
   }
   void handle_close(session* s) {
      if (s->handle) {
         free(s->handle);
      }
   }
   int main() {
      run_mpx_service(47110, handle_request, handle_close);
   }


AUTHOR

Andreas F. Borchert