project_files/frontlib/ipc/mapconn.c
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7576 65d29988fd3d
child 10017 de822cd3df3a
equal deleted inserted replaced
7855:ddcdedd3330b 7857:2bc61f8841a1
       
     1 /*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU General Public License
       
     7  * as published by the Free Software Foundation; either version 2
       
     8  * of the License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13  * GNU General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License
       
    16  * along with this program; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    18  */
       
    19 
       
    20 #include "mapconn.h"
       
    21 #include "ipcbase.h"
       
    22 #include "ipcprotocol.h"
       
    23 
       
    24 #include "../util/logging.h"
       
    25 #include "../util/buffer.h"
       
    26 #include "../util/util.h"
       
    27 
       
    28 #include <stdlib.h>
       
    29 
       
    30 typedef enum {
       
    31 	AWAIT_CONNECTION,
       
    32 	AWAIT_REPLY,
       
    33 	AWAIT_CLOSE,
       
    34 	FINISHED
       
    35 } mapconn_state;
       
    36 
       
    37 struct _flib_mapconn {
       
    38 	uint8_t mapBuffer[IPCBASE_MAPMSG_BYTES];
       
    39 	flib_ipcbase *ipcBase;
       
    40 	flib_vector *configBuffer;
       
    41 
       
    42 	mapconn_state progress;
       
    43 
       
    44 	void (*onSuccessCb)(void*, const uint8_t*, int);
       
    45 	void *onSuccessCtx;
       
    46 
       
    47 	void (*onFailureCb)(void*, const char*);
       
    48 	void *onFailureCtx;
       
    49 
       
    50 	bool running;
       
    51 	bool destroyRequested;
       
    52 };
       
    53 
       
    54 static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {}
       
    55 static void noop_handleFailure(void *context, const char *errormessage) {}
       
    56 
       
    57 static void clearCallbacks(flib_mapconn *conn) {
       
    58 	conn->onSuccessCb = &noop_handleSuccess;
       
    59 	conn->onFailureCb = &noop_handleFailure;
       
    60 }
       
    61 
       
    62 static flib_vector *createConfigBuffer(const flib_map *mapdesc) {
       
    63 	flib_vector *result = NULL;
       
    64 	flib_vector *tempbuffer = flib_vector_create();
       
    65 	if(tempbuffer) {
       
    66 		bool error = false;
       
    67 		error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true);
       
    68 		error |= flib_ipc_append_message(tempbuffer, "!");
       
    69 		if(!error) {
       
    70 			result = tempbuffer;
       
    71 			tempbuffer = NULL;
       
    72 		}
       
    73 	}
       
    74 	flib_vector_destroy(tempbuffer);
       
    75 	return result;
       
    76 }
       
    77 
       
    78 flib_mapconn *flib_mapconn_create(const flib_map *mapdesc) {
       
    79 	if(log_badargs_if(mapdesc==NULL)) {
       
    80 		return NULL;
       
    81 	}
       
    82 	flib_mapconn *result = NULL;
       
    83 	flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn));
       
    84 	if(tempConn) {
       
    85 		tempConn->ipcBase = flib_ipcbase_create();
       
    86 		tempConn->configBuffer = createConfigBuffer(mapdesc);
       
    87 		if(tempConn->ipcBase && tempConn->configBuffer) {
       
    88 			tempConn->progress = AWAIT_CONNECTION;
       
    89 			clearCallbacks(tempConn);
       
    90 			result = tempConn;
       
    91 			tempConn = NULL;
       
    92 		}
       
    93 	}
       
    94 	flib_mapconn_destroy(tempConn);
       
    95 	return result;
       
    96 }
       
    97 
       
    98 void flib_mapconn_destroy(flib_mapconn *conn) {
       
    99 	if(conn) {
       
   100 		if(conn->running) {
       
   101 			/*
       
   102 			 * The function was called from a callback, so the tick function is still running
       
   103 			 * and we delay the actual destruction. We ensure no further callbacks will be
       
   104 			 * sent to prevent surprises.
       
   105 			 */
       
   106 			clearCallbacks(conn);
       
   107 			conn->destroyRequested = true;
       
   108 		} else {
       
   109 			flib_ipcbase_destroy(conn->ipcBase);
       
   110 			flib_vector_destroy(conn->configBuffer);
       
   111 			free(conn);
       
   112 		}
       
   113 	}
       
   114 }
       
   115 
       
   116 int flib_mapconn_getport(flib_mapconn *conn) {
       
   117 	if(log_badargs_if(conn==NULL)) {
       
   118 		return 0;
       
   119 	}
       
   120 	return flib_ipcbase_port(conn->ipcBase);
       
   121 }
       
   122 
       
   123 void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context) {
       
   124 	if(!log_badargs_if(conn==NULL)) {
       
   125 		conn->onSuccessCb = callback ? callback : &noop_handleSuccess;
       
   126 		conn->onSuccessCtx = context;
       
   127 	}
       
   128 }
       
   129 
       
   130 void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) {
       
   131 	if(!log_badargs_if(conn==NULL)) {
       
   132 		conn->onFailureCb = callback ? callback : &noop_handleFailure;
       
   133 		conn->onFailureCtx = context;
       
   134 	}
       
   135 }
       
   136 
       
   137 static void flib_mapconn_wrappedtick(flib_mapconn *conn) {
       
   138 	if(conn->progress == AWAIT_CONNECTION) {
       
   139 		flib_ipcbase_accept(conn->ipcBase);
       
   140 		switch(flib_ipcbase_state(conn->ipcBase)) {
       
   141 		case IPC_CONNECTED:
       
   142 			{
       
   143 				flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer);
       
   144 				if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) {
       
   145 					conn->progress = FINISHED;
       
   146 					conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine.");
       
   147 					return;
       
   148 				} else {
       
   149 					conn->progress = AWAIT_REPLY;
       
   150 				}
       
   151 			}
       
   152 			break;
       
   153 		case IPC_NOT_CONNECTED:
       
   154 			conn->progress = FINISHED;
       
   155 			conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly.");
       
   156 			return;
       
   157 		default:
       
   158 			break;
       
   159 		}
       
   160 	}
       
   161 
       
   162 	if(conn->progress == AWAIT_REPLY) {
       
   163 		if(flib_ipcbase_recv_map(conn->ipcBase, conn->mapBuffer) >= 0) {
       
   164 			conn->progress = AWAIT_CLOSE;
       
   165 		} else if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) {
       
   166 			conn->progress = FINISHED;
       
   167 			conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly.");
       
   168 			return;
       
   169 		}
       
   170 	}
       
   171 
       
   172 	if(conn->progress == AWAIT_CLOSE) {
       
   173 		// Just do throwaway reads so we find out when the engine disconnects
       
   174 		uint8_t buf[256];
       
   175 		flib_ipcbase_recv_message(conn->ipcBase, buf);
       
   176 		if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) {
       
   177 			conn->progress = FINISHED;
       
   178 			conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCBASE_MAPMSG_BYTES-1]);
       
   179 			return;
       
   180 		}
       
   181 	}
       
   182 }
       
   183 
       
   184 void flib_mapconn_tick(flib_mapconn *conn) {
       
   185 	if(!log_badargs_if(conn==NULL)
       
   186 			&& !log_w_if(conn->running, "Call to flib_mapconn_tick from a callback")
       
   187 			&& !log_w_if(conn->progress == FINISHED, "We are already done.")) {
       
   188 		conn->running = true;
       
   189 		flib_mapconn_wrappedtick(conn);
       
   190 		conn->running = false;
       
   191 
       
   192 		if(conn->destroyRequested) {
       
   193 			flib_mapconn_destroy(conn);
       
   194 		}
       
   195 	}
       
   196 }