diff -r 038e3415100a -r bf6cf4dd847a project_files/frontlib/ipc/mapconn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/ipc/mapconn.c Fri Jun 08 19:52:24 2012 +0200 @@ -0,0 +1,174 @@ +#include "mapconn.h" +#include "ipcconn.h" +#include "ipcprotocol.h" + +#include "../logging.h" +#include "../buffer.h" + +#include + +typedef enum { + AWAIT_CONNECTION, + AWAIT_REPLY, + FINISHED +} mapconn_progress; + +struct _flib_mapconn { + uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES]; + flib_ipcconn connection; + flib_vector configBuffer; + + mapconn_progress progress; + + void (*onSuccessCb)(void*, const uint8_t*, int); + void *onSuccessCtx; + + void (*onFailureCb)(void*, const char*); + void *onFailureCtx; + + bool running; + bool destroyRequested; +}; + +static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {} +static void noop_handleFailure(void *context, const char *errormessage) {} + +static void clearCallbacks(flib_mapconn *conn) { + conn->onSuccessCb = &noop_handleSuccess; + conn->onFailureCb = &noop_handleFailure; +} + +static flib_vector createConfigBuffer(char *seed, flib_map *mapdesc) { + flib_vector result = NULL; + flib_vector tempbuffer = flib_vector_create(); + if(tempbuffer) { + bool error = false; + error |= flib_ipc_append_seed(tempbuffer, seed); + error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true); + error |= flib_ipc_append_message(tempbuffer, "!"); + if(!error) { + result = tempbuffer; + tempbuffer = NULL; + } + } + flib_vector_destroy(&tempbuffer); + return result; +} + +flib_mapconn *flib_mapconn_create(char *seed, flib_map *mapdesc) { + flib_mapconn *result = NULL; + flib_mapconn *tempConn = calloc(1, sizeof(flib_mapconn)); + if(tempConn) { + tempConn->connection = flib_ipcconn_create(false, "Player"); + tempConn->configBuffer = createConfigBuffer(seed, mapdesc); + if(tempConn->connection && tempConn->configBuffer) { + tempConn->progress = AWAIT_CONNECTION; + clearCallbacks(tempConn); + result = tempConn; + tempConn = NULL; + } + } + flib_mapconn_destroy(tempConn); + return result; +} + +void flib_mapconn_destroy(flib_mapconn *conn) { + if(conn) { + if(conn->running) { + /* + * The function was called from a callback, so the tick function is still running + * and we delay the actual destruction. We ensure no further callbacks will be + * sent to prevent surprises. + */ + clearCallbacks(conn); + conn->destroyRequested = true; + } else { + flib_ipcconn_destroy(&conn->connection); + flib_vector_destroy(&conn->configBuffer); + free(conn); + } + } +} + +int flib_mapconn_getport(flib_mapconn *conn) { + if(!conn) { + flib_log_e("null parameter in flib_mapconn_getport"); + return 0; + } else { + return flib_ipcconn_port(conn->connection); + } +} + +void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_mapconn_onSuccess"); + } else { + conn->onSuccessCb = callback ? callback : &noop_handleSuccess; + conn->onSuccessCtx = context; + } +} + +void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_mapconn_onError"); + } else { + conn->onFailureCb = callback ? callback : &noop_handleFailure; + conn->onFailureCtx = context; + } +} + +static void flib_mapconn_wrappedtick(flib_mapconn *conn) { + if(conn->progress == AWAIT_CONNECTION) { + flib_ipcconn_accept(conn->connection); + switch(flib_ipcconn_state(conn->connection)) { + case IPC_CONNECTED: + { + flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer); + if(flib_ipcconn_send_raw(conn->connection, configBuffer.data, configBuffer.size)) { + conn->progress = FINISHED; + conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine."); + return; + } else { + conn->progress = AWAIT_REPLY; + } + } + break; + case IPC_NOT_CONNECTED: + conn->progress = FINISHED; + conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly."); + return; + default: + break; + } + } + + if(conn->progress == AWAIT_REPLY) { + if(flib_ipcconn_recv_map(conn->connection, conn->mapBuffer) >= 0) { + conn->progress = FINISHED; + conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCCONN_MAPMSG_BYTES-1]); + return; + } else if(flib_ipcconn_state(conn->connection) != IPC_CONNECTED) { + conn->progress = FINISHED; + conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly."); + return; + } + } +} + +void flib_mapconn_tick(flib_mapconn *conn) { + if(!conn) { + flib_log_e("null parameter in flib_mapconn_tick"); + } else if(conn->running) { + flib_log_w("Call to flib_mapconn_tick from a callback"); + } else if(conn->progress == FINISHED) { + flib_log_w("Call to flib_mapconn_tick, but we are already done. Best destroy your flib_mapconn object in the callbacks."); + } else { + conn->running = true; + flib_mapconn_wrappedtick(conn); + conn->running = false; + + if(conn->destroyRequested) { + flib_mapconn_destroy(conn); + } + } +}