summaryrefslogtreecommitdiff
path: root/toxav/msi.c
diff options
context:
space:
mode:
authorEniz Vukovic <eniz_vukovic@hotmail.com>2015-10-10 23:54:23 +0200
committerEniz Vukovic <eniz_vukovic@hotmail.com>2015-10-10 23:54:23 +0200
commitd6fdf16520b6f242935ca95eeb739ec9a8eaa14c (patch)
tree069f3355835aa0497fe494c36554ea24d0b222f1 /toxav/msi.c
parentbf5e9b89d2a67c293aae503c03e193307ea7990b (diff)
New Adaptive BR algorithm, cleanups and fixes
Diffstat (limited to 'toxav/msi.c')
-rw-r--r--toxav/msi.c620
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
54typedef enum { 53typedef 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
67GENERIC_HEADER ( Request, MSIRequest ); 67GENERIC_HEADER (Request, MSIRequest);
68GENERIC_HEADER ( Error, MSIError ); 68GENERIC_HEADER (Error, MSIError);
69GENERIC_HEADER ( Capabilities, uint8_t ); 69GENERIC_HEADER (Capabilities, uint8_t);
70GENERIC_HEADER ( VFPSZ, uint16_t );
71 70
72 71
73typedef struct { 72typedef 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
81void msg_init (MSIMessage *dest, MSIRequest request); 79void msg_init (MSIMessage *dest, MSIRequest request);
82int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); 80int msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length);
83uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); 81uint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length);
84static int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg ); 82static int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg);
85int send_error ( Messenger* m, uint32_t friend_number, MSIError error ); 83int send_error (Messenger *m, uint32_t friend_number, MSIError error);
86static int invoke_callback(MSICall* call, MSICallbackID cb); 84static int invoke_callback(MSICall *call, MSICallbackID cb);
87static MSICall *get_call ( MSISession *session, uint32_t friend_number ); 85static MSICall *get_call (MSISession *session, uint32_t friend_number);
88MSICall *new_call ( MSISession *session, uint32_t friend_number ); 86MSICall *new_call (MSISession *session, uint32_t friend_number);
89void kill_call ( MSICall *call ); 87void kill_call (MSICall *call);
90void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data); 88void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);
91void handle_push ( MSICall *call, const MSIMessage *msg ); 89void handle_init (MSICall *call, const MSIMessage *msg);
92void handle_pop ( MSICall *call, const MSIMessage *msg ); 90void handle_push (MSICall *call, const MSIMessage *msg);
93void handle_msi_packet ( Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object ); 91void handle_pop (MSICall *call, const MSIMessage *msg);
92void 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 */
99void msi_register_callback ( MSISession* session, msi_action_cb* callback, MSICallbackID id) 98void 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}
105MSISession *msi_new ( Messenger *m ) 107MSISession *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}
135int msi_kill ( MSISession *session ) 137int 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}
163int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities ) 170int 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}
200int msi_hangup ( MSICall* call ) 211int 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}
222int msi_answer ( MSICall* call, uint8_t capabilities ) 240int 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}
255int msi_change_capabilities( MSICall* call, uint8_t capabilities ) 277int 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 */
293void msg_init(MSIMessage* dest, MSIRequest request) 315void 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}
299int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) 321int 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}
384uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ) 395uint8_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}
402int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg ) 413int 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}
453int send_error ( Messenger* m, uint32_t friend_number, MSIError error ) 458int 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}
469int invoke_callback(MSICall* call, MSICallbackID cb) 474int 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
483FAILURE: 489FAILURE:
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}
492static MSICall *get_call ( MSISession *session, uint32_t friend_number ) 499static 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}
501MSICall *new_call ( MSISession *session, uint32_t friend_number ) 508MSICall *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}
552void kill_call ( MSICall *call ) 560void 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
581CLEAR_CONTAINER: 589CLEAR_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}
587void on_peer_status(Messenger* m, uint32_t friend_number, uint8_t status, void* data) 595void 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}
614void handle_push ( MSICall *call, const MSIMessage *msg ) 622void 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;
678FAILURE:
679 send_error(call->session->messenger, call->friend_number, call->error);
680 kill_call(call);
681}
682void 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
713FAILURE: 731FAILURE:
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}
717void handle_pop ( MSICall *call, const MSIMessage *msg ) 735void 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}
757void handle_msi_packet ( Messenger* m, uint32_t friend_number, const uint8_t* data, uint16_t length, void* object ) 779void 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}