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 } |