|
1 #include "ipcconn.h" |
|
2 #include "../logging.h" |
|
3 #include "../socket.h" |
|
4 #include "demo.h" |
|
5 |
|
6 #include <string.h> |
|
7 #include <stdbool.h> |
|
8 #include <stdlib.h> |
|
9 #include <stdio.h> |
|
10 |
|
11 /* |
|
12 * The receive buffer has to be able to hold any message that might be received. Normally |
|
13 * the messages are at most 256 bytes, but the map preview contains 4097 bytes (4096 for a |
|
14 * bitmap, 1 for the number of hogs which fit on the map). |
|
15 * |
|
16 * We don't need to worry about wasting a few kb though, and I like powers of two... |
|
17 */ |
|
18 typedef struct _flib_ipcconn { |
|
19 uint8_t readBuffer[8192]; |
|
20 char playerName[256]; |
|
21 |
|
22 int readBufferSize; |
|
23 |
|
24 flib_acceptor acceptor; |
|
25 uint16_t port; |
|
26 |
|
27 flib_tcpsocket sock; |
|
28 flib_vector demoBuffer; |
|
29 } _flib_ipcconn; |
|
30 |
|
31 flib_ipcconn flib_ipcconn_create(bool recordDemo, const char *localPlayerName) { |
|
32 flib_ipcconn result = malloc(sizeof(_flib_ipcconn)); |
|
33 flib_acceptor acceptor = flib_acceptor_create(0); |
|
34 |
|
35 if(!result || !acceptor) { |
|
36 flib_log_e("Can't create ipcconn."); |
|
37 free(result); |
|
38 flib_acceptor_close(&acceptor); |
|
39 return NULL; |
|
40 } |
|
41 |
|
42 result->acceptor = acceptor; |
|
43 result->sock = NULL; |
|
44 result->readBufferSize = 0; |
|
45 result->port = flib_acceptor_listenport(acceptor); |
|
46 |
|
47 if(localPlayerName) { |
|
48 strncpy(result->playerName, localPlayerName, 255); |
|
49 } else { |
|
50 strncpy(result->playerName, "Player", 255); |
|
51 } |
|
52 |
|
53 if(recordDemo) { |
|
54 result->demoBuffer = flib_vector_create(); |
|
55 } |
|
56 |
|
57 flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port); |
|
58 return result; |
|
59 } |
|
60 |
|
61 uint16_t flib_ipcconn_port(flib_ipcconn ipc) { |
|
62 if(!ipc) { |
|
63 flib_log_e("Call to flib_ipcconn_port with ipc==null"); |
|
64 return 0; |
|
65 } |
|
66 return ipc->port; |
|
67 } |
|
68 |
|
69 void flib_ipcconn_destroy(flib_ipcconn *ipcptr) { |
|
70 if(!ipcptr) { |
|
71 flib_log_e("Call to flib_ipcconn_destroy with ipcptr==null"); |
|
72 } else if(*ipcptr) { |
|
73 flib_ipcconn ipc = *ipcptr; |
|
74 flib_acceptor_close(&ipc->acceptor); |
|
75 flib_socket_close(&ipc->sock); |
|
76 flib_vector_destroy(&ipc->demoBuffer); |
|
77 free(ipc); |
|
78 *ipcptr = NULL; |
|
79 } |
|
80 } |
|
81 |
|
82 IpcConnState flib_ipcconn_state(flib_ipcconn ipc) { |
|
83 if(!ipc) { |
|
84 flib_log_e("Call to flib_ipcconn_state with ipc==null"); |
|
85 return IPC_NOT_CONNECTED; |
|
86 } else if(ipc->sock) { |
|
87 return IPC_CONNECTED; |
|
88 } else if(ipc->acceptor) { |
|
89 return IPC_LISTENING; |
|
90 } else { |
|
91 return IPC_NOT_CONNECTED; |
|
92 } |
|
93 } |
|
94 |
|
95 static bool isMessageReady(flib_ipcconn ipc) { |
|
96 return ipc->readBufferSize >= ipc->readBuffer[0]+1; |
|
97 } |
|
98 |
|
99 static void receiveToBuffer(flib_ipcconn ipc) { |
|
100 if(ipc->sock) { |
|
101 int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize); |
|
102 if(size>=0) { |
|
103 ipc->readBufferSize += size; |
|
104 } else { |
|
105 flib_socket_close(&ipc->sock); |
|
106 } |
|
107 } |
|
108 } |
|
109 |
|
110 int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data) { |
|
111 if(!ipc || !data) { |
|
112 flib_log_e("Call to flib_ipcconn_recv_message with ipc==null or data==null"); |
|
113 return -1; |
|
114 } |
|
115 |
|
116 if(!isMessageReady(ipc)) { |
|
117 receiveToBuffer(ipc); |
|
118 } |
|
119 |
|
120 if(isMessageReady(ipc)) { |
|
121 if(ipc->demoBuffer) { |
|
122 if(flib_demo_record_from_engine(ipc->demoBuffer, ipc->readBuffer, ipc->playerName) < 0) { |
|
123 flib_log_w("Stopping demo recording due to an error."); |
|
124 flib_vector_destroy(&ipc->demoBuffer); |
|
125 } |
|
126 } |
|
127 int msgsize = ipc->readBuffer[0]+1; |
|
128 memcpy(data, ipc->readBuffer, msgsize); |
|
129 memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize); |
|
130 ipc->readBufferSize -= msgsize; |
|
131 return msgsize; |
|
132 } else if(!ipc->sock && ipc->readBufferSize>0) { |
|
133 flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", (unsigned)ipc->readBufferSize, (unsigned)(ipc->readBuffer[0])+1); |
|
134 ipc->readBufferSize = 0; |
|
135 return -1; |
|
136 } else { |
|
137 return -1; |
|
138 } |
|
139 } |
|
140 |
|
141 int flib_ipcconn_recv_map(flib_ipcconn ipc, void *data) { |
|
142 if(!ipc || !data) { |
|
143 flib_log_e("Call to flib_ipcconn_recv_map with ipc==null or data==null"); |
|
144 return -1; |
|
145 } |
|
146 |
|
147 receiveToBuffer(ipc); |
|
148 |
|
149 if(ipc->readBufferSize >= IPCCONN_MAPMSG_BYTES) { |
|
150 memcpy(data, ipc->readBuffer, IPCCONN_MAPMSG_BYTES); |
|
151 memmove(ipc->readBuffer, ipc->readBuffer+IPCCONN_MAPMSG_BYTES, ipc->readBufferSize-IPCCONN_MAPMSG_BYTES); |
|
152 return IPCCONN_MAPMSG_BYTES; |
|
153 } else { |
|
154 return -1; |
|
155 } |
|
156 } |
|
157 |
|
158 int flib_ipcconn_send_raw(flib_ipcconn ipc, const void *data, size_t len) { |
|
159 if(!ipc || (!data && len>0)) { |
|
160 flib_log_e("Call to flib_ipcconn_send_raw with ipc==null or data==null"); |
|
161 return -1; |
|
162 } |
|
163 if(!ipc->sock) { |
|
164 flib_log_w("flib_ipcconn_send_raw: Not connected."); |
|
165 return -1; |
|
166 } |
|
167 |
|
168 if(flib_socket_send(ipc->sock, data, len) == len) { |
|
169 if(ipc->demoBuffer) { |
|
170 if(flib_demo_record_to_engine(ipc->demoBuffer, data, len) < 0) { |
|
171 flib_log_w("Stopping demo recording due to an error."); |
|
172 flib_vector_destroy(&ipc->demoBuffer); |
|
173 } |
|
174 } |
|
175 return 0; |
|
176 } else { |
|
177 flib_log_w("Failed or incomplete ICP write: engine connection lost."); |
|
178 flib_socket_close(&ipc->sock); |
|
179 return -1; |
|
180 } |
|
181 } |
|
182 |
|
183 int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len) { |
|
184 if(!ipc || (!data && len>0) || len>255) { |
|
185 flib_log_e("Call to flib_ipcconn_send_message with ipc==null or data==null or len>255"); |
|
186 return -1; |
|
187 } |
|
188 |
|
189 uint8_t sendbuf[256]; |
|
190 sendbuf[0] = len; |
|
191 memcpy(sendbuf+1, data, len); |
|
192 |
|
193 return flib_ipcconn_send_raw(ipc, sendbuf, len+1); |
|
194 } |
|
195 |
|
196 int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data) { |
|
197 return flib_ipcconn_send_message(ipc, data, strlen(data)); |
|
198 } |
|
199 |
|
200 void flib_ipcconn_accept(flib_ipcconn ipc) { |
|
201 if(!ipc) { |
|
202 flib_log_e("Call to flib_ipcconn_accept with ipc==null"); |
|
203 } else if(!ipc->sock && ipc->acceptor) { |
|
204 ipc->sock = flib_socket_accept(ipc->acceptor, true); |
|
205 if(ipc->sock) { |
|
206 flib_acceptor_close(&ipc->acceptor); |
|
207 } |
|
208 } |
|
209 } |
|
210 |
|
211 flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save) { |
|
212 if(!ipc) { |
|
213 flib_log_e("Call to flib_ipcconn_getrecord with ipc==null"); |
|
214 } |
|
215 if(!ipc || !ipc->demoBuffer) { |
|
216 flib_constbuffer result = {NULL, 0}; |
|
217 return result; |
|
218 } |
|
219 flib_demo_replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), save ? 'S' : 'D'); |
|
220 return flib_vector_as_constbuffer(ipc->demoBuffer); |
|
221 } |