diff options
author | Eniz Vukovic <eniz_vukovic@hotmail.com> | 2015-10-10 23:54:23 +0200 |
---|---|---|
committer | Eniz Vukovic <eniz_vukovic@hotmail.com> | 2015-10-10 23:54:23 +0200 |
commit | d6fdf16520b6f242935ca95eeb739ec9a8eaa14c (patch) | |
tree | 069f3355835aa0497fe494c36554ea24d0b222f1 /toxav/msi.c | |
parent | bf5e9b89d2a67c293aae503c03e193307ea7990b (diff) |
New Adaptive BR algorithm, cleanups and fixes
Diffstat (limited to 'toxav/msi.c')
-rw-r--r-- | toxav/msi.c | 620 |
1 files changed, 325 insertions, 295 deletions
diff --git a/toxav/msi.c b/toxav/msi.c index b262e9a0..ef307bcb 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -46,12 +46,12 @@ typedef enum { | |||
46 | IDRequest = 1, | 46 | IDRequest = 1, |
47 | IDError, | 47 | IDError, |
48 | IDCapabilities, | 48 | IDCapabilities, |
49 | IDVFPSZ, | ||
50 | 49 | ||
51 | } MSIHeaderID; | 50 | } MSIHeaderID; |
52 | 51 | ||
53 | 52 | ||
54 | typedef enum { | 53 | typedef enum { |
54 | requ_init, | ||
55 | requ_push, | 55 | requ_push, |
56 | requ_pop, | 56 | requ_pop, |
57 | } MSIRequest; | 57 | } MSIRequest; |
@@ -64,224 +64,246 @@ typedef struct { \ | |||
64 | } MSIHeader##header | 64 | } MSIHeader##header |
65 | 65 | ||
66 | 66 | ||
67 | GENERIC_HEADER ( Request, MSIRequest ); | 67 | GENERIC_HEADER (Request, MSIRequest); |
68 | GENERIC_HEADER ( Error, MSIError ); | 68 | GENERIC_HEADER (Error, MSIError); |
69 | GENERIC_HEADER ( Capabilities, uint8_t ); | 69 | GENERIC_HEADER (Capabilities, uint8_t); |
70 | GENERIC_HEADER ( VFPSZ, uint16_t ); | ||
71 | 70 | ||
72 | 71 | ||
73 | typedef struct { | 72 | typedef struct { |
74 | MSIHeaderRequest request; | 73 | MSIHeaderRequest request; |
75 | MSIHeaderError error; | 74 | MSIHeaderError error; |
76 | MSIHeaderCapabilities capabilities; | 75 | MSIHeaderCapabilities capabilities; |
77 | MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order TODO: get rid of this eventually */ | ||
78 | } MSIMessage; | 76 | } MSIMessage; |
79 | 77 | ||
80 | 78 | ||
81 | void msg_init (MSIMessage *dest, MSIRequest request); | 79 | void msg_init (MSIMessage *dest, MSIRequest request); |
82 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); | 80 | int msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length); |
83 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); | 81 | uint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length); |
84 | static int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg ); | 82 | static int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg); |
85 | int send_error ( Messenger* m, uint32_t friend_number, MSIError error ); | 83 | int send_error (Messenger *m, uint32_t friend_number, MSIError error); |
86 | static int invoke_callback(MSICall* call, MSICallbackID cb); | 84 | static int invoke_callback(MSICall *call, MSICallbackID cb); |
87 | static MSICall *get_call ( MSISession *session, uint32_t friend_number ); | 85 | static MSICall *get_call (MSISession *session, uint32_t friend_number); |
88 | MSICall *new_call ( MSISession *session, uint32_t friend_number ); | 86 | MSICall *new_call (MSISession *session, uint32_t friend_number); |
89 | void kill_call ( MSICall *call ); | 87 | void kill_call (MSICall *call); |
90 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data); | 88 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data); |
91 | void handle_push ( MSICall *call, const MSIMessage *msg ); | 89 | void handle_init (MSICall *call, const MSIMessage *msg); |
92 | void handle_pop ( MSICall *call, const MSIMessage *msg ); | 90 | void handle_push (MSICall *call, const MSIMessage *msg); |
93 | void handle_msi_packet ( Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object ); | 91 | void handle_pop (MSICall *call, const MSIMessage *msg); |
92 | void handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object); | ||
94 | 93 | ||
95 | 94 | ||
96 | /** | 95 | /** |
97 | * Public functions | 96 | * Public functions |
98 | */ | 97 | */ |
99 | void msi_register_callback ( MSISession* session, msi_action_cb* callback, MSICallbackID id) | 98 | void msi_register_callback (MSISession *session, msi_action_cb *callback, MSICallbackID id) |
100 | { | 99 | { |
100 | if (!session) | ||
101 | return; | ||
102 | |||
101 | pthread_mutex_lock(session->mutex); | 103 | pthread_mutex_lock(session->mutex); |
102 | session->callbacks[id] = callback; | 104 | session->callbacks[id] = callback; |
103 | pthread_mutex_unlock(session->mutex); | 105 | pthread_mutex_unlock(session->mutex); |
104 | } | 106 | } |
105 | MSISession *msi_new ( Messenger *m ) | 107 | MSISession *msi_new (Messenger *m) |
106 | { | 108 | { |
107 | if (m == NULL) { | 109 | if (m == NULL) { |
108 | LOGGER_ERROR("Could not init session on empty messenger!"); | 110 | LOGGER_ERROR("Could not init session on empty messenger!"); |
109 | return NULL; | 111 | return NULL; |
110 | } | 112 | } |
111 | 113 | ||
112 | MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); | 114 | MSISession *retu = calloc (sizeof (MSISession), 1); |
113 | 115 | ||
114 | if (retu == NULL) { | 116 | if (retu == NULL) { |
115 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | 117 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); |
116 | return NULL; | 118 | return NULL; |
117 | } | 119 | } |
118 | 120 | ||
119 | if (create_recursive_mutex(retu->mutex) != 0) { | 121 | if (create_recursive_mutex(retu->mutex) != 0) { |
120 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | 122 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); |
121 | free(retu); | 123 | free(retu); |
122 | return NULL; | 124 | return NULL; |
123 | } | 125 | } |
124 | 126 | ||
125 | retu->messenger = m; | 127 | retu->messenger = m; |
126 | 128 | ||
127 | m_callback_msi_packet(m, handle_msi_packet, retu ); | 129 | m_callback_msi_packet(m, handle_msi_packet, retu); |
128 | 130 | ||
129 | /* This is called when remote terminates session */ | 131 | /* This is called when remote terminates session */ |
130 | m_callback_connectionstatus_internal_av(m, on_peer_status, retu); | 132 | m_callback_connectionstatus_internal_av(m, on_peer_status, retu); |
131 | 133 | ||
132 | LOGGER_DEBUG("New msi session: %p ", retu); | 134 | LOGGER_DEBUG("New msi session: %p ", retu); |
133 | return retu; | 135 | return retu; |
134 | } | 136 | } |
135 | int msi_kill ( MSISession *session ) | 137 | int msi_kill (MSISession *session) |
136 | { | 138 | { |
137 | if (session == NULL) { | 139 | if (session == NULL) { |
138 | LOGGER_ERROR("Tried to terminate non-existing session"); | 140 | LOGGER_ERROR("Tried to terminate non-existing session"); |
139 | return -1; | 141 | return -1; |
140 | } | 142 | } |
141 | 143 | ||
142 | m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL); | 144 | m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL); |
143 | pthread_mutex_lock(session->mutex); | ||
144 | 145 | ||
146 | if (pthread_mutex_trylock(session->mutex) != 0) { | ||
147 | LOGGER_ERROR ("Failed to aquire lock on msi mutex"); | ||
148 | return -1; | ||
149 | } | ||
150 | |||
145 | if (session->calls) { | 151 | if (session->calls) { |
146 | MSIMessage msg; | 152 | MSIMessage msg; |
147 | msg_init(&msg, requ_pop); | 153 | msg_init(&msg, requ_pop); |
148 | 154 | ||
149 | MSICall* it = get_call(session, session->calls_head); | 155 | MSICall *it = get_call(session, session->calls_head); |
156 | |||
150 | for (; it; it = it->next) { | 157 | for (; it; it = it->next) { |
151 | send_message(session->messenger, it->friend_number, &msg); | 158 | send_message(session->messenger, it->friend_number, &msg); |
152 | kill_call(it); /* This will eventually free session->calls */ | 159 | kill_call(it); /* This will eventually free session->calls */ |
153 | } | 160 | } |
154 | } | 161 | } |
155 | 162 | ||
156 | pthread_mutex_unlock(session->mutex); | 163 | pthread_mutex_unlock(session->mutex); |
157 | pthread_mutex_destroy(session->mutex); | 164 | pthread_mutex_destroy(session->mutex); |
158 | 165 | ||
159 | LOGGER_DEBUG("Terminated session: %p", session); | 166 | LOGGER_DEBUG("Terminated session: %p", session); |
160 | free ( session ); | 167 | free (session); |
161 | return 0; | 168 | return 0; |
162 | } | 169 | } |
163 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities ) | 170 | int msi_invite (MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities) |
164 | { | 171 | { |
165 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_number); | 172 | if (!session) |
173 | return -1; | ||
166 | 174 | ||
167 | pthread_mutex_lock(session->mutex); | 175 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_number); |
176 | |||
177 | if (pthread_mutex_trylock(session->mutex) != 0) { | ||
178 | LOGGER_ERROR ("Failed to aquire lock on msi mutex"); | ||
179 | return -1; | ||
180 | } | ||
181 | |||
168 | if (get_call(session, friend_number) != NULL) { | 182 | if (get_call(session, friend_number) != NULL) { |
169 | LOGGER_ERROR("Already in a call"); | 183 | LOGGER_ERROR("Already in a call"); |
170 | pthread_mutex_unlock(session->mutex); | 184 | pthread_mutex_unlock(session->mutex); |
171 | return -1; | 185 | return -1; |
172 | } | 186 | } |
173 | 187 | ||
174 | (*call) = new_call ( session, friend_number ); | 188 | (*call) = new_call (session, friend_number); |
175 | 189 | ||
176 | if ( *call == NULL ) { | 190 | if (*call == NULL) { |
177 | pthread_mutex_unlock(session->mutex); | 191 | pthread_mutex_unlock(session->mutex); |
178 | return -1; | 192 | return -1; |
179 | } | 193 | } |
180 | 194 | ||
181 | (*call)->self_capabilities = capabilities; | 195 | (*call)->self_capabilities = capabilities; |
182 | 196 | ||
183 | MSIMessage msg; | 197 | MSIMessage msg; |
184 | msg_init(&msg, requ_push); | 198 | msg_init(&msg, requ_init); |
185 | 199 | ||
186 | msg.capabilities.exists = true; | 200 | msg.capabilities.exists = true; |
187 | msg.capabilities.value = capabilities; | 201 | msg.capabilities.value = capabilities; |
188 | 202 | ||
189 | msg.vfpsz.exists = true; | 203 | send_message ((*call)->session->messenger, (*call)->friend_number, &msg); |
190 | msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; | 204 | |
191 | |||
192 | send_message ( (*call)->session->messenger, (*call)->friend_number, &msg ); | ||
193 | |||
194 | (*call)->state = msi_CallRequesting; | 205 | (*call)->state = msi_CallRequesting; |
195 | 206 | ||
196 | LOGGER_DEBUG("Invite sent"); | 207 | LOGGER_DEBUG("Invite sent"); |
197 | pthread_mutex_unlock(session->mutex); | 208 | pthread_mutex_unlock(session->mutex); |
198 | return 0; | 209 | return 0; |
199 | } | 210 | } |
200 | int msi_hangup ( MSICall* call ) | 211 | int msi_hangup (MSICall *call) |
201 | { | 212 | { |
202 | LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_number); | 213 | if (!call || !call->session) |
214 | return -1; | ||
203 | 215 | ||
204 | MSISession* session = call->session; | 216 | LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_number); |
205 | pthread_mutex_lock(session->mutex); | 217 | |
218 | MSISession *session = call->session; | ||
206 | 219 | ||
207 | if ( call->state == msi_CallInactive ) { | 220 | if (pthread_mutex_trylock(session->mutex) != 0) { |
221 | LOGGER_ERROR ("Failed to aquire lock on msi mutex"); | ||
222 | return -1; | ||
223 | } | ||
224 | |||
225 | if (call->state == msi_CallInactive) { | ||
208 | LOGGER_ERROR("Call is in invalid state!"); | 226 | LOGGER_ERROR("Call is in invalid state!"); |
209 | pthread_mutex_unlock(session->mutex); | 227 | pthread_mutex_unlock(session->mutex); |
210 | return -1; | 228 | return -1; |
211 | } | 229 | } |
212 | 230 | ||
213 | MSIMessage msg; | 231 | MSIMessage msg; |
214 | msg_init(&msg, requ_pop); | 232 | msg_init(&msg, requ_pop); |
215 | 233 | ||
216 | send_message ( session->messenger, call->friend_number, &msg ); | 234 | send_message (session->messenger, call->friend_number, &msg); |
217 | 235 | ||
218 | kill_call(call); | 236 | kill_call(call); |
219 | pthread_mutex_unlock(session->mutex); | 237 | pthread_mutex_unlock(session->mutex); |
220 | return 0; | 238 | return 0; |
221 | } | 239 | } |
222 | int msi_answer ( MSICall* call, uint8_t capabilities ) | 240 | int msi_answer (MSICall *call, uint8_t capabilities) |
223 | { | 241 | { |
242 | if (!call || !call->session) | ||
243 | return -1; | ||
244 | |||
224 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_number); | 245 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_number); |
225 | 246 | ||
226 | MSISession* session = call->session; | 247 | MSISession *session = call->session; |
227 | pthread_mutex_lock(session->mutex); | 248 | |
228 | 249 | if (pthread_mutex_trylock(session->mutex) != 0) { | |
229 | if ( call->state != msi_CallRequested ) { | 250 | LOGGER_ERROR ("Failed to aquire lock on msi mutex"); |
230 | /* Though sending in invalid state will not cause anything wierd | 251 | return -1; |
252 | } | ||
253 | |||
254 | if (call->state != msi_CallRequested) { | ||
255 | /* Though sending in invalid state will not cause anything wierd | ||
231 | * Its better to not do it like a maniac */ | 256 | * Its better to not do it like a maniac */ |
232 | LOGGER_ERROR("Call is in invalid state!"); | 257 | LOGGER_ERROR("Call is in invalid state!"); |
233 | pthread_mutex_unlock(session->mutex); | 258 | pthread_mutex_unlock(session->mutex); |
234 | return -1; | 259 | return -1; |
235 | } | 260 | } |
236 | 261 | ||
237 | call->self_capabilities = capabilities; | 262 | call->self_capabilities = capabilities; |
238 | 263 | ||
239 | MSIMessage msg; | 264 | MSIMessage msg; |
240 | msg_init(&msg, requ_push); | 265 | msg_init(&msg, requ_push); |
241 | 266 | ||
242 | msg.capabilities.exists = true; | 267 | msg.capabilities.exists = true; |
243 | msg.capabilities.value = capabilities; | 268 | msg.capabilities.value = capabilities; |
244 | 269 | ||
245 | msg.vfpsz.exists = true; | 270 | send_message (session->messenger, call->friend_number, &msg); |
246 | msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; | 271 | |
247 | |||
248 | send_message ( session->messenger, call->friend_number, &msg ); | ||
249 | |||
250 | call->state = msi_CallActive; | 272 | call->state = msi_CallActive; |
251 | pthread_mutex_unlock(session->mutex); | 273 | pthread_mutex_unlock(session->mutex); |
252 | 274 | ||
253 | return 0; | 275 | return 0; |
254 | } | 276 | } |
255 | int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | 277 | int msi_change_capabilities(MSICall *call, uint8_t capabilities) |
256 | { | 278 | { |
257 | LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_number); | 279 | if (!call || !call->session) |
258 | 280 | return -1; | |
259 | MSISession* session = call->session; | ||
260 | pthread_mutex_lock(session->mutex); | ||
261 | 281 | ||
262 | if ( call->state != msi_CallActive ) { | 282 | LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_number); |
263 | /* Sending capabilities change can cause error on other side if | 283 | |
264 | * the call is not active since we don't send header 'vfpsz'. | 284 | MSISession *session = call->session; |
265 | * If we were to send 'vfpsz' while call is active it would be | 285 | |
266 | * ignored. However, if call is not active peer will expect | 286 | if (pthread_mutex_trylock(session->mutex) != 0) { |
267 | * the said header on 'push' so that it could handle the call | 287 | LOGGER_ERROR ("Failed to aquire lock on msi mutex"); |
268 | * like new. TODO: explain this better | 288 | return -1; |
269 | */ | 289 | } |
290 | |||
291 | if (call->state != msi_CallActive) { | ||
270 | LOGGER_ERROR("Call is in invalid state!"); | 292 | LOGGER_ERROR("Call is in invalid state!"); |
271 | pthread_mutex_unlock(session->mutex); | 293 | pthread_mutex_unlock(session->mutex); |
272 | return -1; | 294 | return -1; |
273 | } | 295 | } |
274 | 296 | ||
275 | call->self_capabilities = capabilities; | 297 | call->self_capabilities = capabilities; |
276 | 298 | ||
277 | MSIMessage msg; | 299 | MSIMessage msg; |
278 | msg_init(&msg, requ_push); | 300 | msg_init(&msg, requ_push); |
279 | 301 | ||
280 | msg.capabilities.exists = true; | 302 | msg.capabilities.exists = true; |
281 | msg.capabilities.value = capabilities; | 303 | msg.capabilities.value = capabilities; |
282 | 304 | ||
283 | send_message ( call->session->messenger, call->friend_number, &msg ); | 305 | send_message (call->session->messenger, call->friend_number, &msg); |
284 | 306 | ||
285 | pthread_mutex_unlock(session->mutex); | 307 | pthread_mutex_unlock(session->mutex); |
286 | return 0; | 308 | return 0; |
287 | } | 309 | } |
@@ -290,23 +312,23 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | |||
290 | /** | 312 | /** |
291 | * Private functions | 313 | * Private functions |
292 | */ | 314 | */ |
293 | void msg_init(MSIMessage* dest, MSIRequest request) | 315 | void msg_init(MSIMessage *dest, MSIRequest request) |
294 | { | 316 | { |
295 | memset(dest, 0, sizeof(*dest)); | 317 | memset(dest, 0, sizeof(*dest)); |
296 | dest->request.exists = true; | 318 | dest->request.exists = true; |
297 | dest->request.value = request; | 319 | dest->request.value = request; |
298 | } | 320 | } |
299 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | 321 | int msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length) |
300 | { | 322 | { |
301 | /* Parse raw data received from socket into MSIMessage struct */ | 323 | /* Parse raw data received from socket into MSIMessage struct */ |
302 | 324 | ||
303 | #define CHECK_SIZE(bytes, constraint, size) \ | 325 | #define CHECK_SIZE(bytes, constraint, size) \ |
304 | if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \ | 326 | if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \ |
305 | if ( bytes[1] != size ) { LOGGER_ERROR("Invalid data size!"); return -1; } | 327 | if (bytes[1] != size) { LOGGER_ERROR("Invalid data size!"); return -1; } |
306 | 328 | ||
307 | #define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \ | 329 | #define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \ |
308 | if ( bytes[2] > enum_high ) { LOGGER_ERROR("Failed enum high limit!"); return -1; } | 330 | if (bytes[2] > enum_high) { LOGGER_ERROR("Failed enum high limit!"); return -1; } |
309 | 331 | ||
310 | #define SET_UINT8(bytes, header) do { \ | 332 | #define SET_UINT8(bytes, header) do { \ |
311 | header.value = bytes[2]; \ | 333 | header.value = bytes[2]; \ |
312 | header.exists = true; \ | 334 | header.exists = true; \ |
@@ -318,50 +340,39 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | |||
318 | header.exists = true; \ | 340 | header.exists = true; \ |
319 | bytes += 4; \ | 341 | bytes += 4; \ |
320 | } while(0) | 342 | } while(0) |
321 | 343 | ||
322 | 344 | ||
323 | assert(dest); | 345 | assert(dest); |
324 | 346 | ||
325 | if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ | 347 | if (length == 0 || data[length - 1]) { /* End byte must have value 0 */ |
326 | LOGGER_ERROR("Invalid end byte"); | 348 | LOGGER_ERROR("Invalid end byte"); |
327 | return -1; | 349 | return -1; |
328 | } | 350 | } |
329 | 351 | ||
330 | memset(dest, 0, sizeof(*dest)); | 352 | memset(dest, 0, sizeof(*dest)); |
331 | 353 | ||
332 | const uint8_t *it = data; | 354 | const uint8_t *it = data; |
333 | int size_constraint = length; | 355 | int size_constraint = length; |
334 | 356 | ||
335 | while ( *it ) {/* until end byte is hit */ | 357 | while (*it) {/* until end byte is hit */ |
336 | switch (*it) { | 358 | switch (*it) { |
337 | case IDRequest: | 359 | case IDRequest: |
338 | CHECK_SIZE(it, size_constraint, 1); | 360 | CHECK_SIZE(it, size_constraint, 1); |
339 | CHECK_ENUM_HIGH(it, requ_pop); | 361 | CHECK_ENUM_HIGH(it, requ_pop); |
340 | SET_UINT8(it, dest->request); | 362 | SET_UINT8(it, dest->request); |
341 | break; | 363 | break; |
342 | 364 | ||
343 | case IDError: | 365 | case IDError: |
344 | CHECK_SIZE(it, size_constraint, 1); | 366 | CHECK_SIZE(it, size_constraint, 1); |
345 | CHECK_ENUM_HIGH(it, msi_EUndisclosed); | 367 | CHECK_ENUM_HIGH(it, msi_EUndisclosed); |
346 | SET_UINT8(it, dest->error); | 368 | SET_UINT8(it, dest->error); |
347 | break; | 369 | break; |
348 | 370 | ||
349 | case IDCapabilities: | 371 | case IDCapabilities: |
350 | CHECK_SIZE(it, size_constraint, 1); | 372 | CHECK_SIZE(it, size_constraint, 1); |
351 | SET_UINT8(it, dest->capabilities); | 373 | SET_UINT8(it, dest->capabilities); |
352 | break; | 374 | break; |
353 | 375 | ||
354 | case IDVFPSZ: | ||
355 | CHECK_SIZE(it, size_constraint, 2); | ||
356 | SET_UINT16(it, dest->vfpsz); | ||
357 | dest->vfpsz.value = ntohs(dest->vfpsz.value); | ||
358 | |||
359 | if (dest->vfpsz.value > 1200) { | ||
360 | LOGGER_ERROR("Invalid vfpsz param"); | ||
361 | return -1; | ||
362 | } | ||
363 | break; | ||
364 | |||
365 | default: | 376 | default: |
366 | LOGGER_ERROR("Invalid id byte"); | 377 | LOGGER_ERROR("Invalid id byte"); |
367 | return -1; | 378 | return -1; |
@@ -373,7 +384,7 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | |||
373 | LOGGER_ERROR("Invalid request field!"); | 384 | LOGGER_ERROR("Invalid request field!"); |
374 | return -1; | 385 | return -1; |
375 | } | 386 | } |
376 | 387 | ||
377 | return 0; | 388 | return 0; |
378 | 389 | ||
379 | #undef CHECK_SIZE | 390 | #undef CHECK_SIZE |
@@ -381,13 +392,13 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | |||
381 | #undef SET_UINT8 | 392 | #undef SET_UINT8 |
382 | #undef SET_UINT16 | 393 | #undef SET_UINT16 |
383 | } | 394 | } |
384 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ) | 395 | uint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length) |
385 | { | 396 | { |
386 | /* Parse a single header for sending */ | 397 | /* Parse a single header for sending */ |
387 | assert(dest); | 398 | assert(dest); |
388 | assert(value); | 399 | assert(value); |
389 | assert(value_len); | 400 | assert(value_len); |
390 | 401 | ||
391 | *dest = id; | 402 | *dest = id; |
392 | dest ++; | 403 | dest ++; |
393 | *dest = value_len; | 404 | *dest = value_len; |
@@ -399,208 +410,205 @@ uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value | |||
399 | 410 | ||
400 | return dest + value_len; /* Set to next position ready to be written */ | 411 | return dest + value_len; /* Set to next position ready to be written */ |
401 | } | 412 | } |
402 | int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg ) | 413 | int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg) |
403 | { | 414 | { |
404 | /* Parse and send message */ | 415 | /* Parse and send message */ |
405 | assert(m); | 416 | assert(m); |
406 | 417 | ||
407 | uint8_t parsed [MSI_MAXMSG_SIZE]; | 418 | uint8_t parsed [MSI_MAXMSG_SIZE]; |
408 | 419 | ||
409 | uint8_t *it = parsed; | 420 | uint8_t *it = parsed; |
410 | uint16_t size = 0; | 421 | uint16_t size = 0; |
411 | 422 | ||
412 | if (msg->request.exists) { | 423 | if (msg->request.exists) { |
413 | uint8_t cast = msg->request.value; | 424 | uint8_t cast = msg->request.value; |
414 | it = msg_parse_header_out(IDRequest, it, &cast, | 425 | it = msg_parse_header_out(IDRequest, it, &cast, |
415 | sizeof(cast), &size); | 426 | sizeof(cast), &size); |
416 | } else { | 427 | } else { |
417 | LOGGER_DEBUG("Must have request field"); | 428 | LOGGER_DEBUG("Must have request field"); |
418 | return -1; | 429 | return -1; |
419 | } | 430 | } |
420 | 431 | ||
421 | if (msg->error.exists) { | 432 | if (msg->error.exists) { |
422 | uint8_t cast = msg->error.value; | 433 | uint8_t cast = msg->error.value; |
423 | it = msg_parse_header_out(IDError, it, &cast, | 434 | it = msg_parse_header_out(IDError, it, &cast, |
424 | sizeof(cast), &size); | 435 | sizeof(cast), &size); |
425 | } | 436 | } |
426 | 437 | ||
427 | if (msg->capabilities.exists) { | 438 | if (msg->capabilities.exists) { |
428 | it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value, | 439 | it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value, |
429 | sizeof(msg->capabilities.value), &size); | 440 | sizeof(msg->capabilities.value), &size); |
430 | } | 441 | } |
431 | 442 | ||
432 | if (msg->vfpsz.exists) { | 443 | if (it == parsed) { |
433 | uint16_t nb_vfpsz = htons(msg->vfpsz.value); | ||
434 | it = msg_parse_header_out(IDVFPSZ, it, &nb_vfpsz, | ||
435 | sizeof(nb_vfpsz), &size); | ||
436 | } | ||
437 | |||
438 | if ( it == parsed ) { | ||
439 | LOGGER_WARNING("Parsing message failed; empty message"); | 444 | LOGGER_WARNING("Parsing message failed; empty message"); |
440 | return -1; | 445 | return -1; |
441 | } | 446 | } |
442 | 447 | ||
443 | *it = 0; | 448 | *it = 0; |
444 | size ++; | 449 | size ++; |
445 | 450 | ||
446 | if ( m_msi_packet(m, friend_number, parsed, size) ) { | 451 | if (m_msi_packet(m, friend_number, parsed, size)) { |
447 | LOGGER_DEBUG("Sent message"); | 452 | LOGGER_DEBUG("Sent message"); |
448 | return 0; | 453 | return 0; |
449 | } | 454 | } |
450 | 455 | ||
451 | return -1; | 456 | return -1; |
452 | } | 457 | } |
453 | int send_error ( Messenger* m, uint32_t friend_number, MSIError error ) | 458 | int send_error (Messenger *m, uint32_t friend_number, MSIError error) |
454 | { | 459 | { |
455 | /* Send error message */ | 460 | /* Send error message */ |
456 | assert(m); | 461 | assert(m); |
457 | 462 | ||
458 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_number); | 463 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_number); |
459 | 464 | ||
460 | MSIMessage msg; | 465 | MSIMessage msg; |
461 | msg_init(&msg, requ_pop); | 466 | msg_init(&msg, requ_pop); |
462 | 467 | ||
463 | msg.error.exists = true; | 468 | msg.error.exists = true; |
464 | msg.error.value = error; | 469 | msg.error.value = error; |
465 | 470 | ||
466 | send_message ( m, friend_number, &msg ); | 471 | send_message (m, friend_number, &msg); |
467 | return 0; | 472 | return 0; |
468 | } | 473 | } |
469 | int invoke_callback(MSICall* call, MSICallbackID cb) | 474 | int invoke_callback(MSICall *call, MSICallbackID cb) |
470 | { | 475 | { |
471 | assert(call); | 476 | assert(call); |
472 | 477 | ||
473 | if ( call->session->callbacks[cb] ) { | 478 | if (call->session->callbacks[cb]) { |
474 | LOGGER_DEBUG("Invoking callback function: %d", cb); | 479 | LOGGER_DEBUG("Invoking callback function: %d", cb); |
475 | if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) { | 480 | |
481 | if (call->session->callbacks[cb] (call->session->av, call) != 0) { | ||
476 | LOGGER_WARNING("Callback state handling failed, sending error"); | 482 | LOGGER_WARNING("Callback state handling failed, sending error"); |
477 | goto FAILURE; | 483 | goto FAILURE; |
478 | } | 484 | } |
479 | 485 | ||
480 | return 0; | 486 | return 0; |
481 | } | 487 | } |
482 | 488 | ||
483 | FAILURE: | 489 | FAILURE: |
484 | /* If no callback present or error happened while handling, | 490 | /* If no callback present or error happened while handling, |
485 | * an error message will be sent to friend | 491 | * an error message will be sent to friend |
486 | */ | 492 | */ |
487 | 493 | ||
488 | if (call->error == msi_ENone) | 494 | if (call->error == msi_ENone) |
489 | call->error = msi_EHandle; | 495 | call->error = msi_EHandle; |
496 | |||
490 | return -1; | 497 | return -1; |
491 | } | 498 | } |
492 | static MSICall *get_call ( MSISession *session, uint32_t friend_number ) | 499 | static MSICall *get_call (MSISession *session, uint32_t friend_number) |
493 | { | 500 | { |
494 | assert(session); | 501 | assert(session); |
495 | 502 | ||
496 | if (session->calls == NULL || session->calls_tail < friend_number) | 503 | if (session->calls == NULL || session->calls_tail < friend_number) |
497 | return NULL; | 504 | return NULL; |
498 | 505 | ||
499 | return session->calls[friend_number]; | 506 | return session->calls[friend_number]; |
500 | } | 507 | } |
501 | MSICall *new_call ( MSISession *session, uint32_t friend_number ) | 508 | MSICall *new_call (MSISession *session, uint32_t friend_number) |
502 | { | 509 | { |
503 | assert(session); | 510 | assert(session); |
504 | 511 | ||
505 | MSICall *rc = calloc(sizeof(MSICall), 1); | 512 | MSICall *rc = calloc(sizeof(MSICall), 1); |
506 | 513 | ||
507 | if (rc == NULL) | 514 | if (rc == NULL) |
508 | return NULL; | 515 | return NULL; |
509 | 516 | ||
510 | rc->session = session; | 517 | rc->session = session; |
511 | rc->friend_number = friend_number; | 518 | rc->friend_number = friend_number; |
512 | 519 | ||
513 | if (session->calls == NULL) { /* Creating */ | 520 | if (session->calls == NULL) { /* Creating */ |
514 | session->calls = calloc (sizeof(MSICall*), friend_number + 1); | 521 | session->calls = calloc (sizeof(MSICall *), friend_number + 1); |
515 | 522 | ||
516 | if (session->calls == NULL) { | 523 | if (session->calls == NULL) { |
517 | free(rc); | 524 | free(rc); |
518 | return NULL; | 525 | return NULL; |
519 | } | 526 | } |
520 | 527 | ||
521 | session->calls_tail = session->calls_head = friend_number; | 528 | session->calls_tail = session->calls_head = friend_number; |
522 | 529 | ||
523 | } else if (session->calls_tail < friend_number) { /* Appending */ | 530 | } else if (session->calls_tail < friend_number) { /* Appending */ |
524 | void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_number + 1); | 531 | void *tmp = realloc(session->calls, sizeof(MSICall *) * friend_number + 1); |
525 | 532 | ||
526 | if (tmp == NULL) { | 533 | if (tmp == NULL) { |
527 | free(rc); | 534 | free(rc); |
528 | return NULL; | 535 | return NULL; |
529 | } | 536 | } |
530 | 537 | ||
531 | session->calls = tmp; | 538 | session->calls = tmp; |
532 | 539 | ||
533 | /* Set fields in between to null */ | 540 | /* Set fields in between to null */ |
534 | uint32_t i = session->calls_tail + 1; | 541 | uint32_t i = session->calls_tail + 1; |
542 | |||
535 | for (; i < friend_number; i ++) | 543 | for (; i < friend_number; i ++) |
536 | session->calls[i] = NULL; | 544 | session->calls[i] = NULL; |
537 | 545 | ||
538 | rc->prev = session->calls[session->calls_tail]; | 546 | rc->prev = session->calls[session->calls_tail]; |
539 | session->calls[session->calls_tail]->next = rc; | 547 | session->calls[session->calls_tail]->next = rc; |
540 | 548 | ||
541 | session->calls_tail = friend_number; | 549 | session->calls_tail = friend_number; |
542 | 550 | ||
543 | } else if (session->calls_head > friend_number) { /* Inserting at front */ | 551 | } else if (session->calls_head > friend_number) { /* Inserting at front */ |
544 | rc->next = session->calls[session->calls_head]; | 552 | rc->next = session->calls[session->calls_head]; |
545 | session->calls[session->calls_head]->prev = rc; | 553 | session->calls[session->calls_head]->prev = rc; |
546 | session->calls_head = friend_number; | 554 | session->calls_head = friend_number; |
547 | } | 555 | } |
548 | 556 | ||
549 | session->calls[friend_number] = rc; | 557 | session->calls[friend_number] = rc; |
550 | return rc; | 558 | return rc; |
551 | } | 559 | } |
552 | void kill_call ( MSICall *call ) | 560 | void kill_call (MSICall *call) |
553 | { | 561 | { |
554 | /* Assume that session mutex is locked */ | 562 | /* Assume that session mutex is locked */ |
555 | if ( call == NULL ) | 563 | if (call == NULL) |
556 | return; | 564 | return; |
557 | 565 | ||
558 | LOGGER_DEBUG("Killing call: %p", call); | 566 | LOGGER_DEBUG("Killing call: %p", call); |
559 | 567 | ||
560 | MSISession* session = call->session; | 568 | MSISession *session = call->session; |
561 | 569 | ||
562 | MSICall* prev = call->prev; | 570 | MSICall *prev = call->prev; |
563 | MSICall* next = call->next; | 571 | MSICall *next = call->next; |
564 | 572 | ||
565 | if (prev) | 573 | if (prev) |
566 | prev->next = next; | 574 | prev->next = next; |
567 | else if (next) | 575 | else if (next) |
568 | session->calls_head = next->friend_number; | 576 | session->calls_head = next->friend_number; |
569 | else goto CLEAR_CONTAINER; | 577 | else goto CLEAR_CONTAINER; |
570 | 578 | ||
571 | if (next) | 579 | if (next) |
572 | next->prev = prev; | 580 | next->prev = prev; |
573 | else if (prev) | 581 | else if (prev) |
574 | session->calls_tail = prev->friend_number; | 582 | session->calls_tail = prev->friend_number; |
575 | else goto CLEAR_CONTAINER; | 583 | else goto CLEAR_CONTAINER; |
576 | 584 | ||
577 | session->calls[call->friend_number] = NULL; | 585 | session->calls[call->friend_number] = NULL; |
578 | free(call); | 586 | free(call); |
579 | return; | 587 | return; |
580 | 588 | ||
581 | CLEAR_CONTAINER: | 589 | CLEAR_CONTAINER: |
582 | session->calls_head = session->calls_tail = 0; | 590 | session->calls_head = session->calls_tail = 0; |
583 | free(session->calls); | 591 | free(session->calls); |
584 | free(call); | 592 | free(call); |
585 | session->calls = NULL; | 593 | session->calls = NULL; |
586 | } | 594 | } |
587 | void on_peer_status(Messenger* m, uint32_t friend_number, uint8_t status, void* data) | 595 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data) |
588 | { | 596 | { |
589 | (void)m; | 597 | (void)m; |
590 | MSISession *session = data; | 598 | MSISession *session = data; |
591 | 599 | ||
592 | switch ( status ) { | 600 | switch (status) { |
593 | case 0: { /* Friend is now offline */ | 601 | case 0: { /* Friend is now offline */ |
594 | LOGGER_DEBUG("Friend %d is now offline", friend_number); | 602 | LOGGER_DEBUG("Friend %d is now offline", friend_number); |
595 | 603 | ||
596 | pthread_mutex_lock(session->mutex); | 604 | pthread_mutex_lock(session->mutex); |
597 | MSICall* call = get_call(session, friend_number); | 605 | MSICall *call = get_call(session, friend_number); |
598 | 606 | ||
599 | if (call == NULL) { | 607 | if (call == NULL) { |
600 | pthread_mutex_unlock(session->mutex); | 608 | pthread_mutex_unlock(session->mutex); |
601 | return; | 609 | return; |
602 | } | 610 | } |
603 | 611 | ||
604 | invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ | 612 | invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ |
605 | kill_call(call); | 613 | kill_call(call); |
606 | pthread_mutex_unlock(session->mutex); | 614 | pthread_mutex_unlock(session->mutex); |
@@ -611,186 +619,208 @@ void on_peer_status(Messenger* m, uint32_t friend_number, uint8_t status, void* | |||
611 | break; | 619 | break; |
612 | } | 620 | } |
613 | } | 621 | } |
614 | void handle_push ( MSICall *call, const MSIMessage *msg ) | 622 | void handle_init (MSICall* call, const MSIMessage* msg) |
615 | { | 623 | { |
616 | assert(call); | 624 | assert(call); |
625 | LOGGER_DEBUG("Session: %p Handling 'init' friend: %d", call->session, call->friend_number); | ||
617 | 626 | ||
618 | LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number); | ||
619 | |||
620 | if (!msg->capabilities.exists) { | 627 | if (!msg->capabilities.exists) { |
621 | LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); | 628 | LOGGER_WARNING("Session: %p Invalid capabilities on 'init'"); |
622 | call->error = msi_EInvalidMessage; | 629 | call->error = msi_EInvalidMessage; |
623 | goto FAILURE; | 630 | goto FAILURE; |
624 | } | 631 | } |
625 | 632 | ||
626 | if (call->state != msi_CallActive) { | 633 | switch (call->state) |
627 | if (!msg->vfpsz.exists) { | 634 | { |
628 | LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'"); | ||
629 | call->error = msi_EInvalidMessage; | ||
630 | goto FAILURE; | ||
631 | } | ||
632 | |||
633 | call->peer_vfpsz = msg->vfpsz.value; | ||
634 | } | ||
635 | |||
636 | |||
637 | switch (call->state) { | ||
638 | case msi_CallInactive: { | 635 | case msi_CallInactive: { |
639 | LOGGER_INFO("Friend is calling us"); | ||
640 | |||
641 | /* Call requested */ | 636 | /* Call requested */ |
642 | call->peer_capabilities = msg->capabilities.value; | 637 | call->peer_capabilities = msg->capabilities.value; |
643 | call->state = msi_CallRequested; | 638 | call->state = msi_CallRequested; |
644 | 639 | ||
645 | if ( invoke_callback(call, msi_OnInvite) == -1 ) | 640 | if (invoke_callback(call, msi_OnInvite) == -1) |
646 | goto FAILURE; | 641 | goto FAILURE; |
647 | 642 | } | |
648 | } break; | 643 | break; |
649 | 644 | ||
650 | case msi_CallActive: { | 645 | case msi_CallActive: { |
651 | if (msg->vfpsz.exists) { | 646 | /* If peer sent init while the call is already |
652 | /* If peer sended video frame piece size | 647 | * active it's probable that he is trying to |
653 | * while the call is already active it's probable | 648 | * re-call us while the call is not terminated |
654 | * that he is trying to re-call us while the call | 649 | * on our side. We can assume that in this case |
655 | * is not terminated on our side. We can assume that | 650 | * we can automatically answer the re-call. |
656 | * in this case we can automatically answer the re-call. | 651 | */ |
657 | */ | ||
658 | if (call->peer_vfpsz != msg->vfpsz.value) { | ||
659 | LOGGER_WARNING("Friend sent invalid parameters for re-call"); | ||
660 | call->error = msi_EInvalidParam; | ||
661 | invoke_callback(call, msi_OnError); | ||
662 | goto FAILURE; | ||
663 | } | ||
664 | |||
665 | LOGGER_INFO("Friend is recalling us"); | ||
666 | |||
667 | MSIMessage msg; | ||
668 | msg_init(&msg, requ_push); | ||
669 | |||
670 | msg.capabilities.exists = true; | ||
671 | msg.capabilities.value = call->self_capabilities; | ||
672 | |||
673 | msg.vfpsz.exists = true; | ||
674 | msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; | ||
675 | |||
676 | send_message ( call->session->messenger, call->friend_number, &msg ); | ||
677 | |||
678 | /* If peer changed capabilities during re-call they will | ||
679 | * be handled accordingly during the next step | ||
680 | */ | ||
681 | } | ||
682 | 652 | ||
653 | LOGGER_INFO("Friend is recalling us"); | ||
654 | |||
655 | MSIMessage msg; | ||
656 | msg_init(&msg, requ_push); | ||
657 | |||
658 | msg.capabilities.exists = true; | ||
659 | msg.capabilities.value = call->self_capabilities; | ||
660 | |||
661 | send_message (call->session->messenger, call->friend_number, &msg); | ||
662 | |||
663 | /* If peer changed capabilities during re-call they will | ||
664 | * be handled accordingly during the next step | ||
665 | */ | ||
666 | } | ||
667 | break; | ||
668 | |||
669 | default: { | ||
670 | LOGGER_WARNING("Session: %p Invalid state on 'init'"); | ||
671 | call->error = msi_EInvalidState; | ||
672 | goto FAILURE; | ||
673 | } | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | return; | ||
678 | FAILURE: | ||
679 | send_error(call->session->messenger, call->friend_number, call->error); | ||
680 | kill_call(call); | ||
681 | } | ||
682 | void handle_push (MSICall *call, const MSIMessage *msg) | ||
683 | { | ||
684 | assert(call); | ||
685 | |||
686 | LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number); | ||
687 | |||
688 | if (!msg->capabilities.exists) { | ||
689 | LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); | ||
690 | call->error = msi_EInvalidMessage; | ||
691 | goto FAILURE; | ||
692 | } | ||
693 | |||
694 | switch (call->state) { | ||
695 | case msi_CallActive: { | ||
683 | /* Only act if capabilities changed */ | 696 | /* Only act if capabilities changed */ |
684 | if ( call->peer_capabilities != msg->capabilities.value) { | 697 | if (call->peer_capabilities != msg->capabilities.value) { |
685 | LOGGER_INFO("Friend is changing capabilities to: %u", msg->capabilities.value); | 698 | LOGGER_INFO("Friend is changing capabilities to: %u", msg->capabilities.value); |
686 | 699 | ||
687 | call->peer_capabilities = msg->capabilities.value; | 700 | call->peer_capabilities = msg->capabilities.value; |
688 | if ( invoke_callback(call, msi_OnCapabilities) == -1 ) | 701 | |
702 | if (invoke_callback(call, msi_OnCapabilities) == -1) | ||
689 | goto FAILURE; | 703 | goto FAILURE; |
690 | } | 704 | } |
691 | } break; | 705 | } |
692 | 706 | break; | |
707 | |||
693 | case msi_CallRequesting: { | 708 | case msi_CallRequesting: { |
694 | LOGGER_INFO("Friend answered our call"); | 709 | LOGGER_INFO("Friend answered our call"); |
695 | 710 | ||
696 | /* Call started */ | 711 | /* Call started */ |
697 | call->peer_capabilities = msg->capabilities.value; | 712 | call->peer_capabilities = msg->capabilities.value; |
698 | call->state = msi_CallActive; | 713 | call->state = msi_CallActive; |
699 | 714 | ||
700 | if ( invoke_callback(call, msi_OnStart) == -1 ) | 715 | if (invoke_callback(call, msi_OnStart) == -1) |
701 | goto FAILURE; | 716 | goto FAILURE; |
702 | 717 | ||
703 | } break; | 718 | } |
704 | 719 | break; | |
720 | |||
721 | /* Pushes during initialization state are ignored */ | ||
722 | case msi_CallInactive: | ||
705 | case msi_CallRequested: { | 723 | case msi_CallRequested: { |
706 | /* Consecutive pushes during initialization state are ignored */ | 724 | LOGGER_WARNING("Ignoring invalid push"); |
707 | LOGGER_WARNING("Consecutive push"); | 725 | } |
708 | } break; | 726 | break; |
709 | } | 727 | } |
710 | 728 | ||
711 | return; | 729 | return; |
712 | 730 | ||
713 | FAILURE: | 731 | FAILURE: |
714 | send_error(call->session->messenger, call->friend_number, call->error); | 732 | send_error(call->session->messenger, call->friend_number, call->error); |
715 | kill_call(call); | 733 | kill_call(call); |
716 | } | 734 | } |
717 | void handle_pop ( MSICall *call, const MSIMessage *msg ) | 735 | void handle_pop (MSICall *call, const MSIMessage *msg) |
718 | { | 736 | { |
719 | assert(call); | 737 | assert(call); |
720 | 738 | ||
721 | LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number); | 739 | LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number); |
722 | 740 | ||
723 | /* callback errors are ignored */ | 741 | /* callback errors are ignored */ |
724 | 742 | ||
725 | if (msg->error.exists) { | 743 | if (msg->error.exists) { |
726 | LOGGER_WARNING("Friend detected an error: %d", msg->error.value); | 744 | LOGGER_WARNING("Friend detected an error: %d", msg->error.value); |
727 | call->error = msg->error.value; | 745 | call->error = msg->error.value; |
728 | invoke_callback(call, msi_OnError); | 746 | invoke_callback(call, msi_OnError); |
729 | 747 | ||
730 | } else switch (call->state) { | 748 | } else switch (call->state) { |
731 | case msi_CallInactive: { | 749 | case msi_CallInactive: { |
732 | LOGGER_ERROR("Handling what should be impossible case"); | 750 | LOGGER_ERROR("Handling what should be impossible case"); |
733 | abort(); | 751 | abort(); |
734 | } break; | 752 | } |
735 | 753 | break; | |
754 | |||
736 | case msi_CallActive: { | 755 | case msi_CallActive: { |
737 | /* Hangup */ | 756 | /* Hangup */ |
738 | LOGGER_INFO("Friend hung up on us"); | 757 | LOGGER_INFO("Friend hung up on us"); |
739 | invoke_callback(call, msi_OnEnd); | 758 | invoke_callback(call, msi_OnEnd); |
740 | } break; | 759 | } |
741 | 760 | break; | |
761 | |||
742 | case msi_CallRequesting: { | 762 | case msi_CallRequesting: { |
743 | /* Reject */ | 763 | /* Reject */ |
744 | LOGGER_INFO("Friend rejected our call"); | 764 | LOGGER_INFO("Friend rejected our call"); |
745 | invoke_callback(call, msi_OnEnd); | 765 | invoke_callback(call, msi_OnEnd); |
746 | } break; | 766 | } |
747 | 767 | break; | |
768 | |||
748 | case msi_CallRequested: { | 769 | case msi_CallRequested: { |
749 | /* Cancel */ | 770 | /* Cancel */ |
750 | LOGGER_INFO("Friend canceled call invite"); | 771 | LOGGER_INFO("Friend canceled call invite"); |
751 | invoke_callback(call, msi_OnEnd); | 772 | invoke_callback(call, msi_OnEnd); |
752 | } break; | 773 | } |
774 | break; | ||
753 | } | 775 | } |
754 | 776 | ||
755 | kill_call ( call ); | 777 | kill_call (call); |
756 | } | 778 | } |
757 | void handle_msi_packet ( Messenger* m, uint32_t friend_number, const uint8_t* data, uint16_t length, void* object ) | 779 | void handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object) |
758 | { | 780 | { |
759 | LOGGER_DEBUG("Got msi message"); | 781 | LOGGER_DEBUG("Got msi message"); |
760 | 782 | ||
761 | MSISession *session = object; | 783 | MSISession *session = object; |
762 | MSIMessage msg; | 784 | MSIMessage msg; |
763 | 785 | ||
764 | if ( msg_parse_in ( &msg, data, length ) == -1 ) { | 786 | if (msg_parse_in (&msg, data, length) == -1) { |
765 | LOGGER_WARNING("Error parsing message"); | 787 | LOGGER_WARNING("Error parsing message"); |
766 | send_error(m, friend_number, msi_EInvalidMessage); | 788 | send_error(m, friend_number, msi_EInvalidMessage); |
767 | return; | 789 | return; |
768 | } else { | 790 | } else { |
769 | LOGGER_DEBUG("Successfully parsed message"); | 791 | LOGGER_DEBUG("Successfully parsed message"); |
770 | } | 792 | } |
771 | 793 | ||
772 | pthread_mutex_lock(session->mutex); | 794 | pthread_mutex_lock(session->mutex); |
773 | MSICall *call = get_call(session, friend_number); | 795 | MSICall *call = get_call(session, friend_number); |
774 | 796 | ||
775 | if (call == NULL) { | 797 | if (call == NULL) { |
776 | if (msg.request.value != requ_push) { | 798 | if (msg.request.value != requ_init) { |
777 | send_error(m, friend_number, msi_EStrayMessage); | 799 | send_error(m, friend_number, msi_EStrayMessage); |
778 | pthread_mutex_unlock(session->mutex); | 800 | pthread_mutex_unlock(session->mutex); |
779 | return; | 801 | return; |
780 | } | 802 | } |
781 | 803 | ||
782 | call = new_call(session, friend_number); | 804 | call = new_call(session, friend_number); |
805 | |||
783 | if (call == NULL) { | 806 | if (call == NULL) { |
784 | send_error(m, friend_number, msi_ESystem); | 807 | send_error(m, friend_number, msi_ESystem); |
785 | pthread_mutex_unlock(session->mutex); | 808 | pthread_mutex_unlock(session->mutex); |
786 | return; | 809 | return; |
787 | } | 810 | } |
788 | } | 811 | } |
789 | 812 | ||
790 | if (msg.request.value == requ_push) | 813 | switch (msg.request.value) { |
791 | handle_push(call, &msg); | 814 | case requ_init: |
792 | else | 815 | handle_init(call, &msg); |
793 | handle_pop(call, &msg); /* always kills the call */ | 816 | break; |
794 | 817 | case requ_push: | |
818 | handle_push(call, &msg); | ||
819 | break; | ||
820 | case requ_pop: | ||
821 | handle_pop(call, &msg); /* always kills the call */ | ||
822 | break; | ||
823 | } | ||
824 | |||
795 | pthread_mutex_unlock(session->mutex); | 825 | pthread_mutex_unlock(session->mutex); |
796 | } | 826 | } |