/* Copyright (C) 2008 Andreas Baumann This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Trying to implement a simplistic asynch I/O system using the Proactor Connector/Acceptor pattern. Unix-only at the moment. Trying to get the C APIs right */ /* INTERFACE */ #include "errors.h" #include "port/unused.h" #include "network/network.h" #include /* for size_t */ typedef struct wolf_asio_proc_t *wolf_asio_proc_p; typedef struct wolf_asio_completion_dispatcher_t *wolf_asio_completion_dispatcher_p; /* Completion Handler: they are implemented in the Proactive Initiator, in * this case: * - the Acceptor: accepts new connections arsynchronously * - the Protocol Handler: handles all the communication with the * other peer, it should never do long synchronous work! * - per operation there is one specialized handler, so we can pass * aynchronous request data to it */ typedef void(*wolf_asio_write_completion_handler_f)( void ); typedef void(*wolf_asio_read_completion_handler_f)( void ); typedef void(*wolf_asio_accept_completion_handler_f)( void ); typedef void(*wolf_asio_connect_completion_handler_f)( void ); /* Asynchronous Operation Processor (asio_proc): * - performs the asynchronous opreation on behalf of the application, * usually with a lot of help from the operating system * - must NOT seize control of the callers thread! * - if we miss asynchronous OS calls, we must emulate them with a * pool of dedicated threads which poll the OS */ typedef struct wolf_asio_proc_t { wolf_asio_completion_dispatcher_p completion_dispatcher; } wolf_asio_proc_t; wolf_asio_proc_p wolf_asio_proc_new( wolf_asio_completion_dispatcher_p completion_dispatcher, wolf_error_t *error ); wolf_error_t wolf_asio_proc_free( wolf_asio_proc_p proc ); /* * The main event loop of the asio processor. We can run it were we want, even with * a dedicated pool of threads, if we like */ wolf_error_t wolf_asio_proc_event_loop( wolf_asio_proc_p proc ); /* * Asynchronous Operations: * - the asynchronous operation must be performed without using * the applications thread! * - when an asynchronous operations completes (as compared to the * reactor pattern, where the actual OS operation is still done * by the application!), the asio_proc deletegates the notification * of the appliation to the Completion Distpatcher */ wolf_error_t wolf_asio_proc_write( wolf_asio_proc_p proc, char *buf, size_t buflen, wolf_asio_write_completion_handler_f completion_handler ); wolf_error_t wolf_asio_proc_read( wolf_asio_proc_p proc, char *buf, size_t buflen, wolf_asio_read_completion_handler_f completion_handler ); wolf_error_t wolf_asio_proc_accept( wolf_asio_proc_p proc, wolf_asio_accept_completion_handler_f completion_handler ); wolf_error_t wolf_asio_proc_connect( wolf_asio_proc_p proc, wolf_asio_connect_completion_handler_f completion_handler ); /** * Acceptor * - decouples normal operation in active connections from new * connections * - asks the async operation processor */ /* Asynchronous Completion Token: * - stores state information to complete the asynchronous request, partial * reads/writes (filehandle, position) */ /* TODO: opening files and pipes should be immediate, what about connect/accept? */ /* Completion Dispatcher: * - on completion it has to call the registerd completion_handler * - dispatch concurrency strategy: * - signal the completion as conditional/event to the rendevous point of the * application thread * - borrow the thread * - pool of dedicated threads * - there is a notification queue which gets processed by the completion * dispatcher */ typedef struct wolf_asio_completion_dispatcher_t { int dummy; } wolf_asio_completion_dispatcher_t; wolf_asio_completion_dispatcher_p wolf_asio_completion_dispatcher_new( wolf_error_t *error ); wolf_error_t wolf_asio_completion_dispatcher_free( wolf_asio_completion_dispatcher_p dispatcher ); wolf_error_t wolf_asio_completion_dispatcher_dispatch( wolf_asio_completion_dispatcher_p dispatcher ); /* IMPLEMENTATION */ #include "port/stdlib.h" /* for EXIT_XX, NULL, malloc, free */ wolf_asio_proc_p wolf_asio_proc_new( wolf_asio_completion_dispatcher_p completion_dispatcher, wolf_error_t *error ) { wolf_asio_proc_p proc; proc = (wolf_asio_proc_p)malloc( sizeof( struct wolf_asio_proc_t ) ); if( proc == NULL ) { *error = WOLF_ERR_OUT_OF_MEMORY; return NULL; } proc->completion_dispatcher = completion_dispatcher; return proc; } wolf_error_t wolf_asio_proc_free( wolf_asio_proc_p proc ) { if( proc == NULL ) { return WOLF_ERR_INVALID_STATE; } free( proc ); proc = NULL; return WOLF_OK; } wolf_error_t wolf_asio_proc_accept( wolf_asio_proc_p proc, wolf_asio_accept_completion_handler_f completion_handler ) { WOLF_UNUSED( proc ); WOLF_UNUSED( completion_handler ); /* start an aynchronous accept */ /* call completion_handler in the contect of the completion_dispatcher on completion */ return WOLF_OK; } wolf_error_t wolf_asio_proc_event_loop( wolf_asio_proc_p proc ) { WOLF_UNUSED( proc ); return WOLF_OK; } wolf_asio_completion_dispatcher_p wolf_asio_completion_dispatcher_new( wolf_error_t *error ) { wolf_asio_completion_dispatcher_p dispatcher; dispatcher = (wolf_asio_completion_dispatcher_p)malloc( sizeof( struct wolf_asio_completion_dispatcher_t ) ); if( dispatcher == NULL ) { *error = WOLF_ERR_OUT_OF_MEMORY; return NULL; } return dispatcher; } wolf_error_t wolf_asio_completion_dispatcher_free( wolf_asio_completion_dispatcher_p dispatcher ) { if( dispatcher == NULL ) { return WOLF_ERR_INVALID_STATE; } free( dispatcher ); dispatcher = NULL; return WOLF_OK; } /* completion handlers */ static void accept_handler( void ) { } /* MAIN, the proactive initiator * */ int main( void ) { wolf_asio_proc_p proc; wolf_asio_completion_dispatcher_p dispatcher; wolf_error_t error; dispatcher = wolf_asio_completion_dispatcher_new( &error ); if( dispatcher == NULL ) { return EXIT_FAILURE; } proc = wolf_asio_proc_new( dispatcher, &error ); if( proc == NULL ) { (void)wolf_asio_completion_dispatcher_free( dispatcher ); return EXIT_FAILURE; } error = wolf_asio_proc_accept( proc, accept_handler ); if( error != WOLF_OK ) { (void)wolf_asio_completion_dispatcher_free( dispatcher ); (void)wolf_asio_proc_free( proc ); return EXIT_FAILURE; } /* loop and wait for clients connecting */ while( 1 ) { error = wolf_asio_proc_event_loop( proc ); if( error != WOLF_OK ) { (void)wolf_asio_completion_dispatcher_free( dispatcher ); (void)wolf_asio_proc_free( proc ); return EXIT_FAILURE; } } if( wolf_asio_proc_free( proc ) != WOLF_OK ) { return EXIT_FAILURE; } if( wolf_asio_completion_dispatcher_free( dispatcher ) != WOLF_OK ) { return EXIT_FAILURE; } return EXIT_SUCCESS; }