48 flib_log_i("Started listening for IPC connections on port %u", result->port); |
57 flib_log_i("Started listening for IPC connections on port %u", result->port); |
49 return result; |
58 return result; |
50 } |
59 } |
51 |
60 |
52 uint16_t flib_ipcconn_port(flib_ipcconn ipc) { |
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 } |
53 return ipc->port; |
66 return ipc->port; |
54 } |
67 } |
55 |
68 |
56 void flib_ipcconn_destroy(flib_ipcconn *ipcptr) { |
69 void flib_ipcconn_destroy(flib_ipcconn *ipcptr) { |
57 if(!ipcptr || !*ipcptr) { |
70 if(!ipcptr) { |
58 return; |
71 flib_log_e("Call to flib_ipcconn_destroy with ipcptr==null"); |
59 } |
72 } else if(*ipcptr) { |
60 flib_ipcconn ipc = *ipcptr; |
73 flib_ipcconn ipc = *ipcptr; |
61 flib_acceptor_close(&ipc->acceptor); |
74 flib_acceptor_close(&ipc->acceptor); |
62 flib_socket_close(&ipc->sock); |
75 flib_socket_close(&ipc->sock); |
63 flib_vector_destroy(&ipc->demoBuffer); |
76 flib_vector_destroy(&ipc->demoBuffer); |
64 free(ipc); |
77 free(ipc); |
65 *ipcptr = NULL; |
78 *ipcptr = NULL; |
|
79 } |
66 } |
80 } |
67 |
81 |
68 IpcConnState flib_ipcconn_state(flib_ipcconn ipc) { |
82 IpcConnState flib_ipcconn_state(flib_ipcconn ipc) { |
69 if(ipc && ipc->sock) { |
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) { |
70 return IPC_CONNECTED; |
87 return IPC_CONNECTED; |
71 } else if(ipc && ipc->acceptor) { |
88 } else if(ipc->acceptor) { |
72 return IPC_LISTENING; |
89 return IPC_LISTENING; |
73 } else { |
90 } else { |
74 return IPC_NOT_CONNECTED; |
91 return IPC_NOT_CONNECTED; |
75 } |
92 } |
76 } |
93 } |
77 |
94 |
78 static void demo_record(flib_ipcconn ipc, const void *data, size_t len) { |
95 static bool isMessageReady(flib_ipcconn ipc) { |
79 if(ipc->demoBuffer) { |
96 return ipc->readBufferSize >= ipc->readBuffer[0]+1; |
80 if(flib_vector_append(ipc->demoBuffer, data, len) < len) { |
97 } |
81 // Out of memory, fail demo recording |
98 |
82 flib_vector_destroy(&ipc->demoBuffer); |
99 static void receiveToBuffer(flib_ipcconn ipc) { |
83 } |
|
84 } |
|
85 } |
|
86 |
|
87 static void demo_record_from_engine(flib_ipcconn ipc, const uint8_t *message) { |
|
88 if(!ipc->demoBuffer || message[0]==0) { |
|
89 return; |
|
90 } |
|
91 if(strchr("?CEiQqHb", message[1])) { |
|
92 // Those message types are not recorded in a demo. |
|
93 return; |
|
94 } |
|
95 |
|
96 if(message[1] == 's') { |
|
97 if(message[0] >= 3) { |
|
98 // Chat messages get a special once-over to make them look as if they were received, not sent. |
|
99 // Get the actual chat message as c string |
|
100 char chatMsg[256]; |
|
101 memcpy(chatMsg, message+2, message[0]-3); |
|
102 chatMsg[message[0]-3] = 0; |
|
103 |
|
104 // If the message starts with /me, it will be displayed differently. |
|
105 char converted[257]; |
|
106 bool memessage = message[0] >= 7 && !memcmp(message+2, "/me ", 4); |
|
107 const char *template = memessage ? "s\x02* %s %s " : "s\x01%s: %s "; |
|
108 int size = snprintf(converted+1, 256, template, ipc->playerName, chatMsg); |
|
109 converted[0] = size>255 ? 255 : size; |
|
110 demo_record(ipc, converted, converted[0]+1); |
|
111 } |
|
112 } else { |
|
113 demo_record(ipc, message, message[0]+1); |
|
114 } |
|
115 } |
|
116 |
|
117 int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data) { |
|
118 flib_ipcconn_tick(ipc); |
|
119 |
|
120 if(ipc->sock) { |
100 if(ipc->sock) { |
121 int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize); |
101 int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize); |
122 if(size>=0) { |
102 if(size>=0) { |
123 ipc->readBufferSize += size; |
103 ipc->readBufferSize += size; |
124 } else { |
104 } else { |
125 flib_socket_close(&ipc->sock); |
105 flib_socket_close(&ipc->sock); |
126 } |
106 } |
127 } |
107 } |
128 |
108 } |
129 int msgsize = ipc->readBuffer[0]+1; |
109 |
130 if(ipc->readBufferSize >= msgsize) { |
110 int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data) { |
131 demo_record_from_engine(ipc, ipc->readBuffer); |
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; |
132 memcpy(data, ipc->readBuffer, msgsize); |
128 memcpy(data, ipc->readBuffer, msgsize); |
133 memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize); |
129 memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize); |
134 ipc->readBufferSize -= msgsize; |
130 ipc->readBufferSize -= msgsize; |
135 return msgsize; |
131 return msgsize; |
136 } else if(!ipc->sock && ipc->readBufferSize>0) { |
132 } else if(!ipc->sock && ipc->readBufferSize>0) { |
137 flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", ipc->readBufferSize, msgsize); |
133 flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", ipc->readBufferSize, ipc->readBuffer[0]+1); |
138 ipc->readBufferSize = 0; |
134 ipc->readBufferSize = 0; |
139 return -1; |
135 return -1; |
140 } else { |
136 } else { |
141 return -1; |
137 return -1; |
142 } |
138 } |
143 } |
139 } |
144 |
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 |
145 int flib_ipcconn_send_raw(flib_ipcconn ipc, void *data, size_t len) { |
158 int flib_ipcconn_send_raw(flib_ipcconn ipc, void *data, size_t len) { |
146 flib_ipcconn_tick(ipc); |
159 if(!ipc || (!data && len>0)) { |
147 |
160 flib_log_e("Call to flib_ipcconn_send_raw with ipc==null or data==null"); |
|
161 return -1; |
|
162 } |
148 if(!ipc->sock) { |
163 if(!ipc->sock) { |
149 flib_log_w("flib_ipcconn_send_message: Not connected."); |
164 flib_log_w("flib_ipcconn_send_raw: Not connected."); |
150 return -1; |
165 return -1; |
151 } |
166 } |
152 |
167 |
153 if(flib_socket_send(ipc->sock, data, len) == len) { |
168 if(flib_socket_send(ipc->sock, data, len) == len) { |
154 demo_record(ipc, data, 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 } |
155 return 0; |
175 return 0; |
156 } else { |
176 } else { |
157 flib_log_w("Failed or incomplete ICP write: engine connection lost."); |
177 flib_log_w("Failed or incomplete ICP write: engine connection lost."); |
158 flib_socket_close(&ipc->sock); |
178 flib_socket_close(&ipc->sock); |
159 return -1; |
179 return -1; |
160 } |
180 } |
161 } |
181 } |
162 |
182 |
163 int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len) { |
183 int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len) { |
164 if(len>255) { |
184 if(!ipc || (!data && len>0) || len>255) { |
165 flib_log_e("Attempt to send too much data to the engine in a single message."); |
185 flib_log_e("Call to flib_ipcconn_send_message with ipc==null or data==null or len>255"); |
166 return -1; |
186 return -1; |
167 } |
187 } |
168 |
188 |
169 uint8_t sendbuf[256]; |
189 uint8_t sendbuf[256]; |
170 sendbuf[0] = len; |
190 sendbuf[0] = len; |
175 |
195 |
176 int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data) { |
196 int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data) { |
177 return flib_ipcconn_send_message(ipc, data, strlen(data)); |
197 return flib_ipcconn_send_message(ipc, data, strlen(data)); |
178 } |
198 } |
179 |
199 |
180 void flib_ipcconn_tick(flib_ipcconn ipc) { |
200 void flib_ipcconn_accept(flib_ipcconn ipc) { |
181 if(!ipc->sock && ipc->acceptor) { |
201 if(!ipc) { |
|
202 flib_log_e("Call to flib_ipcconn_accept with ipc==null"); |
|
203 } else if(!ipc->sock && ipc->acceptor) { |
182 ipc->sock = flib_socket_accept(ipc->acceptor, true); |
204 ipc->sock = flib_socket_accept(ipc->acceptor, true); |
183 if(ipc->sock) { |
205 if(ipc->sock) { |
184 flib_acceptor_close(&ipc->acceptor); |
206 flib_acceptor_close(&ipc->acceptor); |
185 } |
207 } |
186 } |
208 } |
187 } |
209 } |
188 |
210 |
189 static void replace_gamemode(flib_buffer buf, char gamemode) { |
211 flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save) { |
190 size_t msgStart = 0; |
212 if(!ipc) { |
191 char *data = (char*)buf.data; |
213 flib_log_e("Call to flib_ipcconn_getrecord with ipc==null"); |
192 while(msgStart+2 < buf.size) { |
214 } |
193 if(!memcmp(data+msgStart, "\x02T", 2)) { |
215 if(!ipc || !ipc->demoBuffer) { |
194 data[msgStart+2] = gamemode; |
|
195 } |
|
196 msgStart += (uint8_t)data[msgStart]+1; |
|
197 } |
|
198 } |
|
199 |
|
200 flib_constbuffer flib_ipcconn_getdemo(flib_ipcconn ipc) { |
|
201 if(!ipc->demoBuffer) { |
|
202 flib_constbuffer result = {NULL, 0}; |
216 flib_constbuffer result = {NULL, 0}; |
203 return result; |
217 return result; |
204 } |
218 } |
205 replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), 'D'); |
219 flib_demo_replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), save ? 'S' : 'D'); |
206 return flib_vector_as_constbuffer(ipc->demoBuffer); |
220 return flib_vector_as_constbuffer(ipc->demoBuffer); |
207 } |
221 } |
208 |
|
209 flib_constbuffer flib_ipcconn_getsave(flib_ipcconn ipc) { |
|
210 if(!ipc->demoBuffer) { |
|
211 flib_constbuffer result = {NULL, 0}; |
|
212 return result; |
|
213 } |
|
214 replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), 'S'); |
|
215 return flib_vector_as_constbuffer(ipc->demoBuffer); |
|
216 } |
|