26 #include "../util/util.h" |
26 #include "../util/util.h" |
27 |
27 |
28 #include <stdlib.h> |
28 #include <stdlib.h> |
29 |
29 |
30 typedef enum { |
30 typedef enum { |
31 AWAIT_CONNECTION, |
31 AWAIT_CONNECTION, |
32 AWAIT_REPLY, |
32 AWAIT_REPLY, |
33 AWAIT_CLOSE, |
33 AWAIT_CLOSE, |
34 FINISHED |
34 FINISHED |
35 } mapconn_state; |
35 } mapconn_state; |
36 |
36 |
37 struct _flib_mapconn { |
37 struct _flib_mapconn { |
38 uint8_t mapBuffer[IPCBASE_MAPMSG_BYTES]; |
38 uint8_t mapBuffer[IPCBASE_MAPMSG_BYTES]; |
39 flib_ipcbase *ipcBase; |
39 flib_ipcbase *ipcBase; |
40 flib_vector *configBuffer; |
40 flib_vector *configBuffer; |
41 |
41 |
42 mapconn_state progress; |
42 mapconn_state progress; |
43 |
43 |
44 void (*onSuccessCb)(void*, const uint8_t*, int); |
44 void (*onSuccessCb)(void*, const uint8_t*, int); |
45 void *onSuccessCtx; |
45 void *onSuccessCtx; |
46 |
46 |
47 void (*onFailureCb)(void*, const char*); |
47 void (*onFailureCb)(void*, const char*); |
48 void *onFailureCtx; |
48 void *onFailureCtx; |
49 |
49 |
50 bool running; |
50 bool running; |
51 bool destroyRequested; |
51 bool destroyRequested; |
52 }; |
52 }; |
53 |
53 |
54 static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {} |
54 static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {} |
55 static void noop_handleFailure(void *context, const char *errormessage) {} |
55 static void noop_handleFailure(void *context, const char *errormessage) {} |
56 |
56 |
57 static void clearCallbacks(flib_mapconn *conn) { |
57 static void clearCallbacks(flib_mapconn *conn) { |
58 conn->onSuccessCb = &noop_handleSuccess; |
58 conn->onSuccessCb = &noop_handleSuccess; |
59 conn->onFailureCb = &noop_handleFailure; |
59 conn->onFailureCb = &noop_handleFailure; |
60 } |
60 } |
61 |
61 |
62 static flib_vector *createConfigBuffer(const flib_map *mapdesc) { |
62 static flib_vector *createConfigBuffer(const flib_map *mapdesc) { |
63 flib_vector *result = NULL; |
63 flib_vector *result = NULL; |
64 flib_vector *tempbuffer = flib_vector_create(); |
64 flib_vector *tempbuffer = flib_vector_create(); |
65 if(tempbuffer) { |
65 if(tempbuffer) { |
66 bool error = false; |
66 bool error = false; |
67 error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true); |
67 error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true); |
68 error |= flib_ipc_append_message(tempbuffer, "!"); |
68 error |= flib_ipc_append_message(tempbuffer, "!"); |
69 if(!error) { |
69 if(!error) { |
70 result = tempbuffer; |
70 result = tempbuffer; |
71 tempbuffer = NULL; |
71 tempbuffer = NULL; |
72 } |
72 } |
73 } |
73 } |
74 flib_vector_destroy(tempbuffer); |
74 flib_vector_destroy(tempbuffer); |
75 return result; |
75 return result; |
76 } |
76 } |
77 |
77 |
78 flib_mapconn *flib_mapconn_create(const flib_map *mapdesc) { |
78 flib_mapconn *flib_mapconn_create(const flib_map *mapdesc) { |
79 if(log_badargs_if(mapdesc==NULL)) { |
79 if(log_badargs_if(mapdesc==NULL)) { |
80 return NULL; |
80 return NULL; |
81 } |
81 } |
82 flib_mapconn *result = NULL; |
82 flib_mapconn *result = NULL; |
83 flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn)); |
83 flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn)); |
84 if(tempConn) { |
84 if(tempConn) { |
85 tempConn->ipcBase = flib_ipcbase_create(); |
85 tempConn->ipcBase = flib_ipcbase_create(); |
86 tempConn->configBuffer = createConfigBuffer(mapdesc); |
86 tempConn->configBuffer = createConfigBuffer(mapdesc); |
87 if(tempConn->ipcBase && tempConn->configBuffer) { |
87 if(tempConn->ipcBase && tempConn->configBuffer) { |
88 tempConn->progress = AWAIT_CONNECTION; |
88 tempConn->progress = AWAIT_CONNECTION; |
89 clearCallbacks(tempConn); |
89 clearCallbacks(tempConn); |
90 result = tempConn; |
90 result = tempConn; |
91 tempConn = NULL; |
91 tempConn = NULL; |
92 } |
92 } |
93 } |
93 } |
94 flib_mapconn_destroy(tempConn); |
94 flib_mapconn_destroy(tempConn); |
95 return result; |
95 return result; |
96 } |
96 } |
97 |
97 |
98 void flib_mapconn_destroy(flib_mapconn *conn) { |
98 void flib_mapconn_destroy(flib_mapconn *conn) { |
99 if(conn) { |
99 if(conn) { |
100 if(conn->running) { |
100 if(conn->running) { |
101 /* |
101 /* |
102 * The function was called from a callback, so the tick function is still running |
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 |
103 * and we delay the actual destruction. We ensure no further callbacks will be |
104 * sent to prevent surprises. |
104 * sent to prevent surprises. |
105 */ |
105 */ |
106 clearCallbacks(conn); |
106 clearCallbacks(conn); |
107 conn->destroyRequested = true; |
107 conn->destroyRequested = true; |
108 } else { |
108 } else { |
109 flib_ipcbase_destroy(conn->ipcBase); |
109 flib_ipcbase_destroy(conn->ipcBase); |
110 flib_vector_destroy(conn->configBuffer); |
110 flib_vector_destroy(conn->configBuffer); |
111 free(conn); |
111 free(conn); |
112 } |
112 } |
113 } |
113 } |
114 } |
114 } |
115 |
115 |
116 int flib_mapconn_getport(flib_mapconn *conn) { |
116 int flib_mapconn_getport(flib_mapconn *conn) { |
117 if(log_badargs_if(conn==NULL)) { |
117 if(log_badargs_if(conn==NULL)) { |
118 return 0; |
118 return 0; |
119 } |
119 } |
120 return flib_ipcbase_port(conn->ipcBase); |
120 return flib_ipcbase_port(conn->ipcBase); |
121 } |
121 } |
122 |
122 |
123 void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context) { |
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)) { |
124 if(!log_badargs_if(conn==NULL)) { |
125 conn->onSuccessCb = callback ? callback : &noop_handleSuccess; |
125 conn->onSuccessCb = callback ? callback : &noop_handleSuccess; |
126 conn->onSuccessCtx = context; |
126 conn->onSuccessCtx = context; |
127 } |
127 } |
128 } |
128 } |
129 |
129 |
130 void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) { |
130 void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) { |
131 if(!log_badargs_if(conn==NULL)) { |
131 if(!log_badargs_if(conn==NULL)) { |
132 conn->onFailureCb = callback ? callback : &noop_handleFailure; |
132 conn->onFailureCb = callback ? callback : &noop_handleFailure; |
133 conn->onFailureCtx = context; |
133 conn->onFailureCtx = context; |
134 } |
134 } |
135 } |
135 } |
136 |
136 |
137 static void flib_mapconn_wrappedtick(flib_mapconn *conn) { |
137 static void flib_mapconn_wrappedtick(flib_mapconn *conn) { |
138 if(conn->progress == AWAIT_CONNECTION) { |
138 if(conn->progress == AWAIT_CONNECTION) { |
139 flib_ipcbase_accept(conn->ipcBase); |
139 flib_ipcbase_accept(conn->ipcBase); |
140 switch(flib_ipcbase_state(conn->ipcBase)) { |
140 switch(flib_ipcbase_state(conn->ipcBase)) { |
141 case IPC_CONNECTED: |
141 case IPC_CONNECTED: |
142 { |
142 { |
143 flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer); |
143 flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer); |
144 if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) { |
144 if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) { |
145 conn->progress = FINISHED; |
145 conn->progress = FINISHED; |
146 conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine."); |
146 conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine."); |
147 return; |
147 return; |
148 } else { |
148 } else { |
149 conn->progress = AWAIT_REPLY; |
149 conn->progress = AWAIT_REPLY; |
150 } |
150 } |
151 } |
151 } |
152 break; |
152 break; |
153 case IPC_NOT_CONNECTED: |
153 case IPC_NOT_CONNECTED: |
154 conn->progress = FINISHED; |
154 conn->progress = FINISHED; |
155 conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly."); |
155 conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly."); |
156 return; |
156 return; |
157 default: |
157 default: |
158 break; |
158 break; |
159 } |
159 } |
160 } |
160 } |
161 |
161 |
162 if(conn->progress == AWAIT_REPLY) { |
162 if(conn->progress == AWAIT_REPLY) { |
163 if(flib_ipcbase_recv_map(conn->ipcBase, conn->mapBuffer) >= 0) { |
163 if(flib_ipcbase_recv_map(conn->ipcBase, conn->mapBuffer) >= 0) { |
164 conn->progress = AWAIT_CLOSE; |
164 conn->progress = AWAIT_CLOSE; |
165 } else if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) { |
165 } else if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) { |
166 conn->progress = FINISHED; |
166 conn->progress = FINISHED; |
167 conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly."); |
167 conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly."); |
168 return; |
168 return; |
169 } |
169 } |
170 } |
170 } |
171 |
171 |
172 if(conn->progress == AWAIT_CLOSE) { |
172 if(conn->progress == AWAIT_CLOSE) { |
173 // Just do throwaway reads so we find out when the engine disconnects |
173 // Just do throwaway reads so we find out when the engine disconnects |
174 uint8_t buf[256]; |
174 uint8_t buf[256]; |
175 flib_ipcbase_recv_message(conn->ipcBase, buf); |
175 flib_ipcbase_recv_message(conn->ipcBase, buf); |
176 if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) { |
176 if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) { |
177 conn->progress = FINISHED; |
177 conn->progress = FINISHED; |
178 conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCBASE_MAPMSG_BYTES-1]); |
178 conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCBASE_MAPMSG_BYTES-1]); |
179 return; |
179 return; |
180 } |
180 } |
181 } |
181 } |
182 } |
182 } |
183 |
183 |
184 void flib_mapconn_tick(flib_mapconn *conn) { |
184 void flib_mapconn_tick(flib_mapconn *conn) { |
185 if(!log_badargs_if(conn==NULL) |
185 if(!log_badargs_if(conn==NULL) |
186 && !log_w_if(conn->running, "Call to flib_mapconn_tick from a callback") |
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.")) { |
187 && !log_w_if(conn->progress == FINISHED, "We are already done.")) { |
188 conn->running = true; |
188 conn->running = true; |
189 flib_mapconn_wrappedtick(conn); |
189 flib_mapconn_wrappedtick(conn); |
190 conn->running = false; |
190 conn->running = false; |
191 |
191 |
192 if(conn->destroyRequested) { |
192 if(conn->destroyRequested) { |
193 flib_mapconn_destroy(conn); |
193 flib_mapconn_destroy(conn); |
194 } |
194 } |
195 } |
195 } |
196 } |
196 } |