project_files/frontlib/ipcconn.c
changeset 7162 fe76d24a25d7
parent 7160 c42949cfdd92
child 7171 906e72caea7b
equal deleted inserted replaced
7160:c42949cfdd92 7162:fe76d24a25d7
     2 #include "logging.h"
     2 #include "logging.h"
     3 #include "nonblocksockets.h"
     3 #include "nonblocksockets.h"
     4 
     4 
     5 #include <SDL_net.h>
     5 #include <SDL_net.h>
     6 #include <time.h>
     6 #include <time.h>
       
     7 #include <string.h>
       
     8 #include <stdbool.h>
       
     9 
     7 static TCPsocket ipcListenSocket;
    10 static TCPsocket ipcListenSocket;
     8 static NonBlockSocket ipcConnSocket;
    11 static NonBlockSocket ipcConnSocket;
     9 
    12 
    10 static uint8_t ipcReadBuffer[256];
    13 static uint8_t ipcReadBuffer[256];
    11 static int ipcReadBufferSize;
    14 static int ipcReadBufferSize;
       
    15 
       
    16 static flib_vector demoBuffer;
       
    17 static char localPlayerName[255];
    12 
    18 
    13 void flib_ipcconn_init() {
    19 void flib_ipcconn_init() {
    14 	ipcListenSocket = NULL;
    20 	ipcListenSocket = NULL;
    15 	ipcConnSocket = NULL;
    21 	ipcConnSocket = NULL;
    16 	ipcReadBufferSize = 0;
    22 	ipcReadBufferSize = 0;
       
    23 	demoBuffer=NULL;
       
    24 	strncpy(localPlayerName, "Local Player", 255);
    17 }
    25 }
    18 
    26 
    19 void flib_ipcconn_quit() {
    27 void flib_ipcconn_quit() {
       
    28 	flib_vector_destroy(&demoBuffer);
    20 	flib_ipcconn_close();
    29 	flib_ipcconn_close();
    21 }
    30 }
    22 
    31 
    23 int flib_ipcconn_listen() {
    32 int flib_ipcconn_start(bool recordDemo) {
    24 	if(ipcListenSocket || ipcConnSocket) {
    33 	if(ipcListenSocket || ipcConnSocket) {
    25 		flib_log_e("flib_ipcconn_listen: Already listening or connected.");
    34 		flib_log_e("flib_ipcconn_listen: Already listening or connected.");
    26 		return -1;
    35 		return -1;
    27 	}
    36 	}
    28 	IPaddress addr;
    37 	IPaddress addr;
    40 		ipcListenSocket = SDLNet_TCP_Open(&addr);
    49 		ipcListenSocket = SDLNet_TCP_Open(&addr);
    41 		if(!ipcListenSocket) {
    50 		if(!ipcListenSocket) {
    42 			flib_log_w("Failed to start an IPC listening socket on port %i: %s", ipcPort, SDLNet_GetError());
    51 			flib_log_w("Failed to start an IPC listening socket on port %i: %s", ipcPort, SDLNet_GetError());
    43 		} else {
    52 		} else {
    44 			flib_log_i("Listening for IPC connections on port %i.", ipcPort);
    53 			flib_log_i("Listening for IPC connections on port %i.", ipcPort);
       
    54 			if(recordDemo) {
       
    55 				flib_vector_destroy(&demoBuffer);
       
    56 				demoBuffer = flib_vector_create();
       
    57 			}
    45 			return ipcPort;
    58 			return ipcPort;
    46 		}
    59 		}
    47 	}
    60 	}
    48 	flib_log_e("Unable to find a free port for IPC.");
    61 	flib_log_e("Unable to find a free port for IPC.");
    49 	return -1;
    62 	return -1;
    63 		return IPC_CONNECTED;
    76 		return IPC_CONNECTED;
    64 	} else if(ipcListenSocket) {
    77 	} else if(ipcListenSocket) {
    65 		return IPC_LISTENING;
    78 		return IPC_LISTENING;
    66 	} else {
    79 	} else {
    67 		return IPC_NOT_CONNECTED;
    80 		return IPC_NOT_CONNECTED;
       
    81 	}
       
    82 }
       
    83 
       
    84 static void demo_record(const void *data, size_t len) {
       
    85 	if(demoBuffer) {
       
    86 		if(flib_vector_append(demoBuffer, data, len) < len) {
       
    87 			// Out of memory, fail demo recording
       
    88 			flib_vector_destroy(&demoBuffer);
       
    89 		}
       
    90 	}
       
    91 }
       
    92 
       
    93 static void demo_record_from_engine(const uint8_t *message) {
       
    94 	if(!demoBuffer || message[0]==0) {
       
    95 		return;
       
    96 	}
       
    97 	if(strchr("?CEiQqHb", message[1])) {
       
    98 		// Those message types are not recorded in a demo.
       
    99 		return;
       
   100 	}
       
   101 
       
   102 	if(message[1] == 's') {
       
   103 		if(message[0] >= 3) {
       
   104 			// Chat messages get a special once-over to make them look as if they were received, not sent.
       
   105 			// Get the actual chat message as c string
       
   106 			char chatMsg[256];
       
   107 			memcpy(chatMsg, message+2, message[0]-3);
       
   108 			chatMsg[message[0]-3] = 0;
       
   109 
       
   110 			char converted[257];
       
   111 			bool memessage = message[0] >= 7 && !memcmp(message+2, "/me ", 4);
       
   112 			const char *template = memessage ? "s\x02* %s %s  " : "s\x01%s: %s  ";
       
   113 			int size = snprintf(converted+1, 256, template, localPlayerName, chatMsg);
       
   114 			converted[0] = size>255 ? 255 : size;
       
   115 			demo_record(converted, converted[0]+1);
       
   116 		}
       
   117 	} else {
       
   118 		demo_record(message, message[0]+1);
    68 	}
   119 	}
    69 }
   120 }
    70 
   121 
    71 /**
   122 /**
    72  * Receive a single message and copy it into the data buffer.
   123  * Receive a single message and copy it into the data buffer.
    84 		}
   135 		}
    85 	}
   136 	}
    86 
   137 
    87 	int msgsize = ipcReadBuffer[0];
   138 	int msgsize = ipcReadBuffer[0];
    88 	if(ipcReadBufferSize > msgsize) {
   139 	if(ipcReadBufferSize > msgsize) {
       
   140 		demo_record_from_engine(ipcReadBuffer);
    89 		memcpy(data, ipcReadBuffer+1, msgsize);
   141 		memcpy(data, ipcReadBuffer+1, msgsize);
    90 		memmove(ipcReadBuffer, ipcReadBuffer+msgsize+1, ipcReadBufferSize-(msgsize+1));
   142 		memmove(ipcReadBuffer, ipcReadBuffer+msgsize+1, ipcReadBufferSize-(msgsize+1));
    91 		ipcReadBufferSize -= (msgsize+1);
   143 		ipcReadBufferSize -= (msgsize+1);
    92 		return msgsize;
   144 		return msgsize;
    93 	} else if(!ipcConnSocket && ipcReadBufferSize>0) {
   145 	} else if(!ipcConnSocket && ipcReadBufferSize>0) {
   112 	}
   164 	}
   113 
   165 
   114 	uint8_t sendbuf[256];
   166 	uint8_t sendbuf[256];
   115 	sendbuf[0] = len;
   167 	sendbuf[0] = len;
   116 	memcpy(sendbuf+1, data, len);
   168 	memcpy(sendbuf+1, data, len);
   117 	if(flib_nbsocket_blocksend(ipcConnSocket, sendbuf, len+1) < len+1) {
   169 	if(flib_nbsocket_blocksend(ipcConnSocket, sendbuf, len+1) == len+1) {
       
   170 		demo_record(sendbuf, len+1);
       
   171 		return 0;
       
   172 	} else {
   118 		flib_log_w("Failed or incomplete ICP write: engine connection lost.");
   173 		flib_log_w("Failed or incomplete ICP write: engine connection lost.");
   119 		flib_nbsocket_close(&ipcConnSocket);
   174 		flib_nbsocket_close(&ipcConnSocket);
   120 		return -1;
   175 		return -1;
   121 	} else {
   176 	}
   122 		return 0;
   177 }
   123 	}
   178 
       
   179 int flib_ipcconn_send_messagestr(char *data) {
       
   180 	return flib_ipcconn_send_message(data, strlen(data));
   124 }
   181 }
   125 
   182 
   126 void flib_ipcconn_tick() {
   183 void flib_ipcconn_tick() {
   127 	if(!ipcConnSocket && ipcListenSocket) {
   184 	if(!ipcConnSocket && ipcListenSocket) {
   128 		ipcConnSocket = flib_nbsocket_accept(ipcListenSocket, true);
   185 		ipcConnSocket = flib_nbsocket_accept(ipcListenSocket, true);
   130 			SDLNet_TCP_Close(ipcListenSocket);
   187 			SDLNet_TCP_Close(ipcListenSocket);
   131 			ipcListenSocket = NULL;
   188 			ipcListenSocket = NULL;
   132 		}
   189 		}
   133 	}
   190 	}
   134 }
   191 }
       
   192 
       
   193 static void replace_gamemode(flib_buffer buf, char gamemode) {
       
   194 	size_t msgStart = 0;
       
   195 	char *data = (char*)buf.data;
       
   196 	while(msgStart+2 < buf.size) {
       
   197 		if(!memcmp(data+msgStart, "\x02T", 2)) {
       
   198 			data[msgStart+2] = gamemode;
       
   199 		}
       
   200 		msgStart += (uint8_t)data[msgStart]+1;
       
   201 	}
       
   202 }
       
   203 
       
   204 flib_constbuffer flib_ipcconn_getdemo() {
       
   205 	if(!demoBuffer) {
       
   206 		flib_constbuffer result = {NULL, 0};
       
   207 		return result;
       
   208 	}
       
   209 	replace_gamemode(flib_vector_as_buffer(demoBuffer), 'D');
       
   210 	return flib_vector_as_constbuffer(demoBuffer);
       
   211 }
       
   212 
       
   213 flib_constbuffer flib_ipcconn_getsave() {
       
   214 	if(!demoBuffer) {
       
   215 		flib_constbuffer result = {NULL, 0};
       
   216 		return result;
       
   217 	}
       
   218 	replace_gamemode(flib_vector_as_buffer(demoBuffer), 'S');
       
   219 	return flib_vector_as_constbuffer(demoBuffer);
       
   220 }