comparison libpurple/protocols/msn/p2p.c @ 31558:ce968e115c95

propagate from branch 'im.pidgin.cpw.masca.p2p' (head 33ca865dacb9e5bcf763d06f6a42cbaca337cc64) to branch 'im.pidgin.pidgin' (head 92f47f4e8b0cbb107fd97e1ab814d1cedbf109ad)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Fri, 06 May 2011 06:25:14 +0000
parents f518effe7395
children 968103d932d6
comparison
equal deleted inserted replaced
31557:f021d93a1f9b 31558:ce968e115c95
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 */ 23 */
24 24
25 #include "internal.h" 25 #include "internal.h"
26 #include "debug.h"
26 27
27 #include "p2p.h" 28 #include "p2p.h"
29 #include "tlv.h"
28 #include "msnutils.h" 30 #include "msnutils.h"
29 31
30 MsnP2PHeader * 32 MsnP2PInfo *
31 msn_p2p_header_from_wire(const char *wire) 33 msn_p2p_info_new(MsnP2PVersion version)
32 { 34 {
33 MsnP2PHeader *header; 35 MsnP2PInfo *info = g_new0(MsnP2PInfo, 1);
34 36 info->version = version;
35 header = g_new(MsnP2PHeader, 1); 37
36 38 switch (version) {
37 header->session_id = msn_pop32le(wire); 39 case MSN_P2P_VERSION_ONE:
38 header->id = msn_pop32le(wire); 40 case MSN_P2P_VERSION_TWO:
39 header->offset = msn_pop64le(wire); 41 /* Nothing to do */
40 header->total_size = msn_pop64le(wire); 42 break;
41 header->length = msn_pop32le(wire); 43
42 header->flags = msn_pop32le(wire); 44 default:
43 header->ack_id = msn_pop32le(wire); 45 purple_debug_error("msn", "Invalid P2P Info version: %d\n", version);
44 header->ack_sub_id = msn_pop32le(wire); 46 g_free(info);
45 header->ack_size = msn_pop64le(wire); 47 info = NULL;
46 48 }
47 return header; 49
50 return info;
51 }
52
53 MsnP2PInfo *
54 msn_p2p_info_dup(MsnP2PInfo *info)
55 {
56 MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1);
57
58 new_info->version = info->version;
59
60 switch (info->version) {
61 case MSN_P2P_VERSION_ONE:
62 *new_info = *info;
63 break;
64
65 case MSN_P2P_VERSION_TWO:
66 *new_info = *info;
67 new_info->header.v2.header_tlv = msn_tlvlist_copy(info->header.v2.header_tlv);
68 new_info->header.v2.data_tlv = msn_tlvlist_copy(info->header.v2.data_tlv);
69 break;
70
71 default:
72 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
73 g_free(new_info);
74 new_info = NULL;
75 }
76
77 return new_info;
78 }
79
80 void
81 msn_p2p_info_free(MsnP2PInfo *info)
82 {
83 switch (info->version) {
84 case MSN_P2P_VERSION_ONE:
85 /* Nothing to do! */
86 break;
87
88 case MSN_P2P_VERSION_TWO:
89 msn_tlvlist_free(info->header.v2.header_tlv);
90 msn_tlvlist_free(info->header.v2.data_tlv);
91 break;
92
93 default:
94 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
95 }
96
97 g_free(info);
98 }
99
100 size_t
101 msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire, size_t max_len)
102 {
103 size_t len = 0;
104
105 switch (info->version) {
106 case MSN_P2P_VERSION_ONE: {
107 MsnP2PHeader *header = &info->header.v1;
108
109 if (max_len < P2P_PACKET_HEADER_SIZE) {
110 /* Invalid packet length */
111 len = 0;
112 break;
113 }
114
115 header->session_id = msn_pop32le(wire);
116 header->id = msn_pop32le(wire);
117 header->offset = msn_pop64le(wire);
118 header->total_size = msn_pop64le(wire);
119 header->length = msn_pop32le(wire);
120 header->flags = msn_pop32le(wire);
121 header->ack_id = msn_pop32le(wire);
122 header->ack_sub_id = msn_pop32le(wire);
123 header->ack_size = msn_pop64le(wire);
124
125 len = P2P_PACKET_HEADER_SIZE;
126 break;
127 }
128
129 case MSN_P2P_VERSION_TWO: {
130 MsnP2Pv2Header *header = &info->header.v2;
131
132 header->header_len = msn_pop8(wire);
133 header->opcode = msn_pop8(wire);
134 header->message_len = msn_pop16be(wire);
135 header->base_id = msn_pop32be(wire);
136 if (header->header_len + header->message_len + P2P_PACKET_FOOTER_SIZE > max_len) {
137 /* Invalid header and data length */
138 len = 0;
139 break;
140 }
141
142 if (header->header_len > 8) {
143 header->header_tlv = msn_tlvlist_read(wire, header->header_len - 8);
144 wire += header->header_len - 8;
145 }
146
147 if (header->message_len > 0) {
148 /* Parse Data packet */
149
150 header->data_header_len = msn_pop8(wire);
151 if (header->data_header_len > header->message_len) {
152 /* Invalid data header length */
153 len = 0;
154 break;
155 }
156 header->data_tf = msn_pop8(wire);
157 header->package_number = msn_pop16be(wire);
158 header->session_id = msn_pop32be(wire);
159
160 if (header->data_header_len > 8) {
161 header->data_tlv = msn_tlvlist_read(wire, header->data_header_len - 8);
162 wire += header->data_header_len - 8;
163 }
164 }
165
166 len = header->header_len + header->message_len;
167
168 break;
169 }
170
171 default:
172 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
173 }
174
175 return len;
48 } 176 }
49 177
50 char * 178 char *
51 msn_p2p_header_to_wire(MsnP2PHeader *header) 179 msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len)
52 { 180 {
181 char *wire = NULL;
182 char *tmp;
183
184 switch (info->version) {
185 case MSN_P2P_VERSION_ONE: {
186 MsnP2PHeader *header = &info->header.v1;
187 tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE);
188
189 msn_push32le(tmp, header->session_id);
190 msn_push32le(tmp, header->id);
191 msn_push64le(tmp, header->offset);
192 msn_push64le(tmp, header->total_size);
193 msn_push32le(tmp, header->length);
194 msn_push32le(tmp, header->flags);
195 msn_push32le(tmp, header->ack_id);
196 msn_push32le(tmp, header->ack_sub_id);
197 msn_push64le(tmp, header->ack_size);
198
199 if (len)
200 *len = P2P_PACKET_HEADER_SIZE;
201
202 break;
203 }
204
205 case MSN_P2P_VERSION_TWO: {
206 MsnP2Pv2Header *header = &info->header.v2;
207 char *header_wire = NULL;
208 char *data_header_wire = NULL;
209
210 if (header->header_tlv != NULL)
211 header_wire = msn_tlvlist_write(header->header_tlv, (size_t *)&header->header_len);
212 else
213 header->header_len = 0;
214
215 if (header->data_tlv != NULL)
216 data_header_wire = msn_tlvlist_write(header->data_tlv, (size_t *)&header->data_header_len);
217 else
218 header->data_header_len = 0;
219
220 tmp = wire = g_new(char, 16 + header->header_len + header->data_header_len);
221
222 msn_push8(tmp, header->header_len + 8);
223 msn_push8(tmp, header->opcode);
224 msn_push16be(tmp, header->data_header_len + 8 + header->message_len);
225 msn_push32be(tmp, header->base_id);
226
227 if (header_wire != NULL) {
228 memcpy(tmp, header_wire, header->header_len);
229 tmp += header->header_len;
230 }
231
232 msn_push8(tmp, header->data_header_len + 8);
233 msn_push8(tmp, header->data_tf);
234 msn_push16be(tmp, header->package_number);
235 msn_push32be(tmp, header->session_id);
236
237 if (data_header_wire != NULL) {
238 memcpy(tmp, data_header_wire, header->data_header_len);
239 tmp += header->data_header_len;
240 }
241
242 if (len)
243 *len = header->header_len + header->data_header_len + 16;
244
245 break;
246 }
247
248 default:
249 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
250 }
251
252 return wire;
253 }
254
255 size_t
256 msn_p2p_footer_from_wire(MsnP2PInfo *info, const char *wire)
257 {
258 MsnP2PFooter *footer;
259
260 footer = &info->footer;
261
262 footer->value = msn_pop32be(wire);
263
264 return P2P_PACKET_FOOTER_SIZE;
265 }
266
267 char *
268 msn_p2p_footer_to_wire(MsnP2PInfo *info, size_t *len)
269 {
270 MsnP2PFooter *footer;
53 char *wire; 271 char *wire;
54 char *tmp; 272 char *tmp;
55 273
56 tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE); 274 footer = &info->footer;
57 275 tmp = wire = g_new(char, P2P_PACKET_FOOTER_SIZE);
58 msn_push32le(tmp, header->session_id); 276
59 msn_push32le(tmp, header->id); 277 msn_push32be(tmp, footer->value);
60 msn_push64le(tmp, header->offset); 278
61 msn_push64le(tmp, header->total_size); 279 if (len)
62 msn_push32le(tmp, header->length); 280 *len = P2P_PACKET_FOOTER_SIZE;
63 msn_push32le(tmp, header->flags);
64 msn_push32le(tmp, header->ack_id);
65 msn_push32le(tmp, header->ack_sub_id);
66 msn_push64le(tmp, header->ack_size);
67 281
68 return wire; 282 return wire;
69 283 }
70 } 284
71 285 void
72 MsnP2PFooter * 286 msn_p2p_info_to_string(MsnP2PInfo *info, GString *str)
73 msn_p2p_footer_from_wire(const char *wire) 287 {
74 { 288 switch (info->version) {
75 MsnP2PFooter *footer; 289 case MSN_P2P_VERSION_ONE: {
76 290 MsnP2PHeader *header = &info->header.v1;
77 footer = g_new(MsnP2PFooter, 1); 291 g_string_append_printf(str, "Session ID: %u\r\n", header->session_id);
78 292 g_string_append_printf(str, "ID: %u\r\n", header->id);
79 footer->value = msn_pop32be(wire); 293 g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", header->offset);
80 294 g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", header->total_size);
81 return footer; 295 g_string_append_printf(str, "Length: %u\r\n", header->length);
82 } 296 g_string_append_printf(str, "Flags: 0x%x\r\n", header->flags);
83 297 g_string_append_printf(str, "ACK ID: %u\r\n", header->ack_id);
84 char * 298 g_string_append_printf(str, "SUB ID: %u\r\n", header->ack_sub_id);
85 msn_p2p_footer_to_wire(MsnP2PFooter *footer) 299 g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", header->ack_size);
86 { 300
87 char *wire; 301 break;
88 char *tmp; 302 }
89 303
90 tmp = wire = g_new(char, P2P_PACKET_FOOTER_SIZE); 304 case MSN_P2P_VERSION_TWO:
91 305 /* Nothing to do! */
92 msn_push32be(tmp, footer->value); 306 break;
93 307
94 return wire; 308 default:
309 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
310 }
311
312 g_string_append_printf(str, "Footer: 0x%08X\r\n", info->footer.value);
95 } 313 }
96 314
97 gboolean 315 gboolean
98 msn_p2p_msg_is_data(const MsnP2PHeaderFlag flags) 316 msn_p2p_msg_is_data(const MsnP2PHeaderFlag flags)
99 { 317 {
100 return (flags == P2P_MSN_OBJ_DATA || 318 return (flags == P2P_MSN_OBJ_DATA ||
101 flags == (P2P_WLM2009_COMP | P2P_MSN_OBJ_DATA) || 319 flags == (P2P_WLM2009_COMP | P2P_MSN_OBJ_DATA) ||
102 flags == P2P_FILE_DATA); 320 flags == P2P_FILE_DATA);
103 } 321 }
104 322
323 gboolean
324 msn_p2p_info_is_valid(MsnP2PInfo *info)
325 {
326 gboolean valid = FALSE;
327
328 switch (info->version) {
329 case MSN_P2P_VERSION_ONE:
330 valid = info->header.v1.total_size >= info->header.v1.length;
331 break;
332
333 case MSN_P2P_VERSION_TWO:
334 /* Nothing to do! */
335 break;
336
337 default:
338 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
339 }
340
341 return valid;
342 }
343
344 gboolean
345 msn_p2p_info_is_final(MsnP2PInfo *info)
346 {
347 gboolean final = FALSE;
348
349 switch (info->version) {
350 case MSN_P2P_VERSION_ONE:
351 final = info->header.v1.offset + info->header.v1.length >= info->header.v1.total_size;
352 break;
353
354 case MSN_P2P_VERSION_TWO:
355 /* Nothing to do! */
356 break;
357
358 default:
359 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
360 }
361
362 return final;
363 }
364
365 guint32
366 msn_p2p_info_get_session_id(MsnP2PInfo *info)
367 {
368 guint32 session_id = 0;
369
370 switch (info->version) {
371 case MSN_P2P_VERSION_ONE:
372 session_id = info->header.v1.session_id;
373 break;
374
375 case MSN_P2P_VERSION_TWO:
376 session_id = info->header.v2.session_id;
377 break;
378
379 default:
380 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
381 }
382
383 return session_id;
384 }
385
386 guint32
387 msn_p2p_info_get_id(MsnP2PInfo *info)
388 {
389 guint32 id = 0;
390
391 switch (info->version) {
392 case MSN_P2P_VERSION_ONE:
393 id = info->header.v1.id;
394 break;
395
396 case MSN_P2P_VERSION_TWO:
397 id = info->header.v2.base_id;
398 break;
399
400 default:
401 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
402 }
403
404 return id;
405 }
406
407 guint64
408 msn_p2p_info_get_offset(MsnP2PInfo *info)
409 {
410 guint64 offset = 0;
411
412 switch (info->version) {
413 case MSN_P2P_VERSION_ONE:
414 offset = info->header.v1.offset;
415 break;
416
417 case MSN_P2P_VERSION_TWO:
418 /* Nothing to do! */
419 break;
420
421 default:
422 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
423 }
424
425 return offset;
426 }
427
428 guint64
429 msn_p2p_info_get_total_size(MsnP2PInfo *info)
430 {
431 guint64 total_size = 0;
432
433 switch (info->version) {
434 case MSN_P2P_VERSION_ONE:
435 total_size = info->header.v1.total_size;
436 break;
437
438 case MSN_P2P_VERSION_TWO:
439 /* Nothing to do! */
440 break;
441
442 default:
443 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
444 }
445
446 return total_size;
447 }
448
449 guint32
450 msn_p2p_info_get_length(MsnP2PInfo *info)
451 {
452 guint32 length = 0;
453
454 switch (info->version) {
455 case MSN_P2P_VERSION_ONE:
456 length = info->header.v1.length;
457 break;
458
459 case MSN_P2P_VERSION_TWO:
460 /* Nothing to do! */
461 break;
462
463 default:
464 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
465 }
466
467 return length;
468 }
469
470 guint32
471 msn_p2p_info_get_flags(MsnP2PInfo *info)
472 {
473 guint32 flags = 0;
474
475 switch (info->version) {
476 case MSN_P2P_VERSION_ONE:
477 flags = info->header.v1.flags;
478 break;
479
480 case MSN_P2P_VERSION_TWO:
481 /* Nothing to do! */
482 break;
483
484 default:
485 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
486 }
487
488 return flags;
489 }
490
491 guint32
492 msn_p2p_info_get_ack_id(MsnP2PInfo *info)
493 {
494 guint32 ack_id = 0;
495
496 switch (info->version) {
497 case MSN_P2P_VERSION_ONE:
498 ack_id = info->header.v1.ack_id;
499 break;
500
501 case MSN_P2P_VERSION_TWO:
502 /* Nothing to do! */
503 break;
504
505 default:
506 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
507 }
508
509 return ack_id;
510 }
511
512 guint32
513 msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info)
514 {
515 guint32 ack_sub_id = 0;
516
517 switch (info->version) {
518 case MSN_P2P_VERSION_ONE:
519 ack_sub_id = info->header.v1.ack_sub_id;
520 break;
521
522 case MSN_P2P_VERSION_TWO:
523 /* Nothing to do! */
524 break;
525
526 default:
527 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
528 }
529
530 return ack_sub_id;
531 }
532
533 guint64
534 msn_p2p_info_get_ack_size(MsnP2PInfo *info)
535 {
536 guint64 ack_size = 0;
537
538 switch (info->version) {
539 case MSN_P2P_VERSION_ONE:
540 ack_size = info->header.v1.ack_size;
541 break;
542
543 case MSN_P2P_VERSION_TWO:
544 /* Nothing to do! */
545 break;
546
547 default:
548 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
549 }
550
551 return ack_size;
552 }
553
554 guint32
555 msn_p2p_info_get_app_id(MsnP2PInfo *info)
556 {
557 return info->footer.value;
558 }
559
560 void
561 msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id)
562 {
563 switch (info->version) {
564 case MSN_P2P_VERSION_ONE:
565 info->header.v1.session_id = session_id;
566 break;
567
568 case MSN_P2P_VERSION_TWO:
569 info->header.v2.session_id = session_id;
570 break;
571
572 default:
573 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
574 }
575
576 }
577
578 void
579 msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id)
580 {
581 switch (info->version) {
582 case MSN_P2P_VERSION_ONE:
583 info->header.v1.id = id;
584 break;
585
586 case MSN_P2P_VERSION_TWO:
587 info->header.v2.base_id = id;
588 break;
589
590 default:
591 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
592 }
593
594 }
595
596 void
597 msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset)
598 {
599 switch (info->version) {
600 case MSN_P2P_VERSION_ONE:
601 info->header.v1.offset = offset;
602 break;
603
604 case MSN_P2P_VERSION_TWO:
605 /* Nothing to do! */
606 break;
607
608 default:
609 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
610 }
611 }
612
613 void
614 msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size)
615 {
616 switch (info->version) {
617 case MSN_P2P_VERSION_ONE:
618 info->header.v1.total_size = total_size;
619 break;
620
621 case MSN_P2P_VERSION_TWO:
622 /* Nothing to do! */
623 break;
624
625 default:
626 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
627 }
628 }
629
630 void
631 msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length)
632 {
633 switch (info->version) {
634 case MSN_P2P_VERSION_ONE:
635 info->header.v1.length = length;
636 break;
637
638 case MSN_P2P_VERSION_TWO:
639 /* Nothing to do! */
640 break;
641
642 default:
643 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
644 }
645 }
646
647 void
648 msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags)
649 {
650 switch (info->version) {
651 case MSN_P2P_VERSION_ONE:
652 info->header.v1.flags = flags;
653 break;
654
655 case MSN_P2P_VERSION_TWO:
656 /* Nothing to do! */
657 break;
658
659 default:
660 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
661 }
662 }
663
664 void
665 msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id)
666 {
667 switch (info->version) {
668 case MSN_P2P_VERSION_ONE:
669 info->header.v1.ack_id = ack_id;
670 break;
671
672 case MSN_P2P_VERSION_TWO:
673 /* Nothing to do! */
674 break;
675
676 default:
677 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
678 }
679 }
680
681 void
682 msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id)
683 {
684 switch (info->version) {
685 case MSN_P2P_VERSION_ONE:
686 info->header.v1.ack_sub_id = ack_sub_id;
687 break;
688
689 case MSN_P2P_VERSION_TWO:
690 /* Nothing to do! */
691 break;
692
693 default:
694 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
695 }
696 }
697
698 void
699 msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size)
700 {
701 switch (info->version) {
702 case MSN_P2P_VERSION_ONE:
703 info->header.v1.ack_size = ack_size;
704 break;
705
706 case MSN_P2P_VERSION_TWO:
707 /* Nothing to do! */
708 break;
709
710 default:
711 purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
712 }
713 }
714
715 void
716 msn_p2p_info_set_app_id(MsnP2PInfo *info, guint32 app_id)
717 {
718 info->footer.value = app_id;
719 }
720