src/protocols/sametime/meanwhile/channel.c

changeset 12496
788b20ccec91
parent 12495
4b2c27ae504a
child 12497
a17568773be3
equal deleted inserted replaced
12495:4b2c27ae504a 12496:788b20ccec91
1
2 /*
3 Meanwhile - Unofficial Lotus Sametime Community Client Library
4 Copyright (C) 2004 Christopher (siege) O'Brien
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the Free
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <glib.h>
22 #include <glib/ghash.h>
23 #include <glib/glist.h>
24 #include <string.h>
25
26 #include "mw_channel.h"
27 #include "mw_cipher.h"
28 #include "mw_debug.h"
29 #include "mw_error.h"
30 #include "mw_message.h"
31 #include "mw_service.h"
32 #include "mw_session.h"
33 #include "mw_util.h"
34
35
36 /** @todo reorganize this file, stuff is just strewn about */
37
38
39 struct mwChannel {
40
41 /** session this channel belongs to */
42 struct mwSession *session;
43
44 enum mwChannelState state;
45
46 /** creator for incoming channel, target for outgoing channel */
47 struct mwLoginInfo user;
48
49 /* similar to data from the CreateCnl message in 8.4.1.7 */
50 guint32 reserved; /**< special, unknown meaning */
51 guint32 id; /**< channel ID */
52 guint32 service; /**< service ID */
53 guint32 proto_type; /**< service protocol type */
54 guint32 proto_ver; /**< service protocol version */
55 guint32 options; /**< channel options */
56
57 struct mwOpaque addtl_create;
58 struct mwOpaque addtl_accept;
59
60 /** all those supported ciphers */
61 GHashTable *supported;
62 guint16 offered_policy; /**< @see enum mwEncryptPolicy */
63 guint16 policy; /**< @see enum mwEncryptPolicy */
64
65 /** cipher information determined at channel acceptance */
66 struct mwCipherInstance *cipher;
67
68 /** statistics table */
69 GHashTable *stats;
70
71 GSList *outgoing_queue; /**< queued outgoing messages */
72 GSList *incoming_queue; /**< queued incoming messages */
73
74 struct mw_datum srvc_data; /**< service-specific data */
75 };
76
77
78 struct mwChannelSet {
79 struct mwSession *session; /**< owning session */
80 GHashTable *map; /**< map of all channels, by ID */
81 guint32 counter; /**< counter for outgoing ID */
82 };
83
84
85 static void flush_channel(struct mwChannel *);
86
87
88 static const char *state_str(enum mwChannelState state) {
89 switch(state) {
90 case mwChannel_NEW: return "new";
91 case mwChannel_INIT: return "initializing";
92 case mwChannel_WAIT: return "waiting";
93 case mwChannel_OPEN: return "open";
94 case mwChannel_DESTROY: return "closing";
95 case mwChannel_ERROR: return "error";
96
97 case mwChannel_UNKNOWN: /* fall through */
98 default: return "UNKNOWN";
99 }
100 }
101
102
103 static void state(struct mwChannel *chan, enum mwChannelState state,
104 guint32 err_code) {
105
106 g_return_if_fail(chan != NULL);
107
108 if(chan->state == state) return;
109
110 chan->state = state;
111
112 if(err_code) {
113 g_message("channel 0x%08x state: %s (0x%08x)",
114 chan->id, state_str(state), err_code);
115 } else {
116 g_message("channel 0x%08x state: %s", chan->id, state_str(state));
117 }
118 }
119
120
121 static gpointer get_stat(struct mwChannel *chan,
122 enum mwChannelStatField field) {
123
124 return g_hash_table_lookup(chan->stats, (gpointer) field);
125 }
126
127
128 static void set_stat(struct mwChannel *chan, enum mwChannelStatField field,
129 gpointer val) {
130
131 g_hash_table_insert(chan->stats, (gpointer) field, val);
132 }
133
134
135 #define incr_stat(chan, field, incr) \
136 set_stat(chan, field, get_stat(chan, field) + incr)
137
138
139 #define timestamp_stat(chan, field) \
140 set_stat(chan, field, (gpointer) time(NULL))
141
142
143 static void sup_free(gpointer a) {
144 mwCipherInstance_free(a);
145 }
146
147
148 struct mwCipherInstance *get_supported(struct mwChannel *chan, guint16 id) {
149 guint32 cid = (guint32) id;
150 return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid));
151 }
152
153
154 void put_supported(struct mwChannel *chan, struct mwCipherInstance *ci) {
155 struct mwCipher *cipher = mwCipherInstance_getCipher(ci);
156 guint32 cid = (guint32) mwCipher_getType(cipher);
157 g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci);
158 }
159
160
161 struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) {
162 struct mwChannel *chan;
163
164 g_return_val_if_fail(cs != NULL, NULL);
165 g_return_val_if_fail(cs->session != NULL, NULL);
166
167 chan = g_new0(struct mwChannel, 1);
168 chan->state = mwChannel_NEW;
169 chan->session = cs->session;
170 chan->id = id;
171
172 chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal);
173
174 chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal,
175 NULL, sup_free);
176
177 g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan);
178
179 state(chan, mwChannel_WAIT, 0);
180
181 return chan;
182 }
183
184
185 struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) {
186 guint32 id;
187 struct mwChannel *chan;
188
189 g_return_val_if_fail(cs != NULL, NULL);
190 g_return_val_if_fail(cs->map != NULL, NULL);
191
192 /* grab the next id, and try to make sure there isn't already a
193 channel using it */
194 do {
195 id = ++cs->counter;
196 } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id)));
197
198 chan = mwChannel_newIncoming(cs, id);
199 state(chan, mwChannel_INIT, 0);
200
201 return chan;
202 }
203
204
205 guint32 mwChannel_getId(struct mwChannel *chan) {
206 g_return_val_if_fail(chan != NULL, 0);
207 return chan->id;
208 }
209
210
211 struct mwSession *mwChannel_getSession(struct mwChannel *chan) {
212 g_return_val_if_fail(chan != NULL, NULL);
213 return chan->session;
214 }
215
216
217 guint32 mwChannel_getServiceId(struct mwChannel *chan) {
218 g_return_val_if_fail(chan != NULL, 0);
219 return chan->service;
220 }
221
222
223 struct mwService *mwChannel_getService(struct mwChannel *chan) {
224 g_return_val_if_fail(chan != NULL, NULL);
225 return mwSession_getService(chan->session, chan->service);
226 }
227
228
229 void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) {
230 g_return_if_fail(chan != NULL);
231 g_return_if_fail(srvc != NULL);
232 g_return_if_fail(chan->state == mwChannel_INIT);
233 chan->service = mwService_getType(srvc);
234 }
235
236
237 gpointer mwChannel_getServiceData(struct mwChannel *chan) {
238 g_return_val_if_fail(chan != NULL, NULL);
239 return mw_datum_get(&chan->srvc_data);
240 }
241
242
243 void mwChannel_setServiceData(struct mwChannel *chan,
244 gpointer data, GDestroyNotify clean) {
245
246 g_return_if_fail(chan != NULL);
247 mw_datum_set(&chan->srvc_data, data, clean);
248 }
249
250
251 void mwChannel_removeServiceData(struct mwChannel *chan) {
252 g_return_if_fail(chan != NULL);
253 mw_datum_clear(&chan->srvc_data);
254 }
255
256
257 guint32 mwChannel_getProtoType(struct mwChannel *chan) {
258 g_return_val_if_fail(chan != NULL, 0x00);
259 return chan->proto_type;
260 }
261
262
263 void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) {
264 g_return_if_fail(chan != NULL);
265 g_return_if_fail(chan->state == mwChannel_INIT);
266 chan->proto_type = proto_type;
267 }
268
269
270 guint32 mwChannel_getProtoVer(struct mwChannel *chan) {
271 g_return_val_if_fail(chan != NULL, 0x00);
272 return chan->proto_ver;
273 }
274
275
276 void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) {
277 g_return_if_fail(chan != NULL);
278 g_return_if_fail(chan->state == mwChannel_INIT);
279 chan->proto_ver = proto_ver;
280 }
281
282
283 guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) {
284 g_return_val_if_fail(chan != NULL, 0x00);
285 return chan->policy;
286 }
287
288
289 guint32 mwChannel_getOptions(struct mwChannel *chan) {
290 g_return_val_if_fail(chan != NULL, 0x00);
291 return chan->options;
292 }
293
294
295 void mwChannel_setOptions(struct mwChannel *chan, guint32 options) {
296 g_return_if_fail(chan != NULL);
297 g_return_if_fail(chan->state == mwChannel_INIT);
298 chan->options = options;
299 }
300
301
302 struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) {
303 g_return_val_if_fail(chan != NULL, NULL);
304 return &chan->user;
305 }
306
307
308 struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) {
309 g_return_val_if_fail(chan != NULL, NULL);
310 return &chan->addtl_create;
311 }
312
313
314 struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) {
315 g_return_val_if_fail(chan != NULL, NULL);
316 return &chan->addtl_accept;
317 }
318
319
320 struct mwCipherInstance *mwChannel_getCipherInstance(struct mwChannel *chan) {
321 g_return_val_if_fail(chan != NULL, NULL);
322 return chan->cipher;
323 }
324
325
326 enum mwChannelState mwChannel_getState(struct mwChannel *chan) {
327 g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN);
328 return chan->state;
329 }
330
331
332 gpointer mwChannel_getStatistic(struct mwChannel *chan,
333 enum mwChannelStatField stat) {
334
335 g_return_val_if_fail(chan != NULL, 0);
336 g_return_val_if_fail(chan->stats != NULL, 0);
337
338 return get_stat(chan, stat);
339 }
340
341
342 /* send a channel create message */
343 int mwChannel_create(struct mwChannel *chan) {
344 struct mwMsgChannelCreate *msg;
345 GList *list, *l;
346 int ret;
347
348 g_return_val_if_fail(chan != NULL, -1);
349 g_return_val_if_fail(chan->state == mwChannel_INIT, -1);
350 g_return_val_if_fail(mwChannel_isOutgoing(chan), -1);
351
352 msg = (struct mwMsgChannelCreate *)
353 mwMessage_new(mwMessage_CHANNEL_CREATE);
354
355 msg->channel = chan->id;
356 msg->target.user = g_strdup(chan->user.user_id);
357 msg->target.community = g_strdup(chan->user.community);
358 msg->service = chan->service;
359 msg->proto_type = chan->proto_type;
360 msg->proto_ver = chan->proto_ver;
361 msg->options = chan->options;
362 mwOpaque_clone(&msg->addtl, &chan->addtl_create);
363
364 list = mwChannel_getSupportedCipherInstances(chan);
365 if(list) {
366 /* offer what we have */
367 for(l = list; l; l = l->next) {
368 struct mwEncryptItem *ei = mwCipherInstance_offer(l->data);
369 msg->encrypt.items = g_list_append(msg->encrypt.items, ei);
370 }
371
372 /* we're easy to get along with */
373 chan->offered_policy = mwEncrypt_WHATEVER;
374 g_list_free(list);
375
376 } else {
377 /* we apparently don't support anything */
378 chan->offered_policy = mwEncrypt_NONE;
379 }
380
381 msg->encrypt.mode = chan->offered_policy;
382 msg->encrypt.extra = chan->offered_policy;
383
384 ret = mwSession_send(chan->session, MW_MESSAGE(msg));
385 mwMessage_free(MW_MESSAGE(msg));
386
387 state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret);
388
389 return ret;
390 }
391
392
393 static void channel_open(struct mwChannel *chan) {
394 state(chan, mwChannel_OPEN, 0);
395 timestamp_stat(chan, mwChannelStat_OPENED_AT);
396 flush_channel(chan);
397 }
398
399
400 int mwChannel_accept(struct mwChannel *chan) {
401 struct mwSession *session;
402 struct mwMsgChannelAccept *msg;
403 struct mwCipherInstance *ci;
404
405 int ret;
406
407 g_return_val_if_fail(chan != NULL, -1);
408 g_return_val_if_fail(mwChannel_isIncoming(chan), -1);
409 g_return_val_if_fail(chan->state == mwChannel_WAIT, -1);
410
411 session = chan->session;
412 g_return_val_if_fail(session != NULL, -1);
413
414 msg = (struct mwMsgChannelAccept *)
415 mwMessage_new(mwMessage_CHANNEL_ACCEPT);
416
417 msg->head.channel = chan->id;
418 msg->service = chan->service;
419 msg->proto_type = chan->proto_type;
420 msg->proto_ver = chan->proto_ver;
421 mwOpaque_clone(&msg->addtl, &chan->addtl_accept);
422
423 ci = chan->cipher;
424
425 if(! ci) {
426 /* automatically select a cipher if one hasn't been already */
427
428 switch(chan->offered_policy) {
429 case mwEncrypt_NONE:
430 mwChannel_selectCipherInstance(chan, NULL);
431 break;
432
433 case mwEncrypt_RC2_40:
434 ci = get_supported(chan, mwCipher_RC2_40);
435 mwChannel_selectCipherInstance(chan, ci);
436 break;
437
438 case mwEncrypt_RC2_128:
439 ci = get_supported(chan, mwCipher_RC2_128);
440 mwChannel_selectCipherInstance(chan, ci);
441 break;
442
443 case mwEncrypt_WHATEVER:
444 case mwEncrypt_ALL:
445 default:
446 {
447 GList *l, *ll;
448
449 l = mwChannel_getSupportedCipherInstances(chan);
450 if(l) {
451 /* nobody selected a cipher, so we'll just pick the last in
452 the list of available ones */
453 for(ll = l; ll->next; ll = ll->next);
454 ci = ll->data;
455 g_list_free(l);
456
457 mwChannel_selectCipherInstance(chan, ci);
458
459 } else {
460 /* this may cause breakage, but there's really nothing else
461 we can do. They want something we can't provide. If they
462 don't like it, then they'll error the channel out */
463 mwChannel_selectCipherInstance(chan, NULL);
464 }
465 }
466 }
467 }
468
469 msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */
470 msg->encrypt.extra = chan->offered_policy;
471
472 if(chan->cipher) {
473 msg->encrypt.item = mwCipherInstance_accept(chan->cipher);
474 }
475
476 ret = mwSession_send(session, MW_MESSAGE(msg));
477 mwMessage_free(MW_MESSAGE(msg));
478
479 if(ret) {
480 state(chan, mwChannel_ERROR, ret);
481 } else {
482 channel_open(chan);
483 }
484
485 return ret;
486 }
487
488
489 static void channel_free(struct mwChannel *chan) {
490 struct mwSession *s;
491 struct mwMessage *msg;
492 GSList *l;
493
494 /* maybe no warning in the future */
495 g_return_if_fail(chan != NULL);
496
497 s = chan->session;
498
499 mwLoginInfo_clear(&chan->user);
500 mwOpaque_clear(&chan->addtl_create);
501 mwOpaque_clear(&chan->addtl_accept);
502
503 if(chan->supported) {
504 g_hash_table_destroy(chan->supported);
505 chan->supported = NULL;
506 }
507
508 if(chan->stats) {
509 g_hash_table_destroy(chan->stats);
510 chan->stats = NULL;
511 }
512
513 mwCipherInstance_free(chan->cipher);
514
515 /* clean up the outgoing queue */
516 for(l = chan->outgoing_queue; l; l = l->next) {
517 msg = (struct mwMessage *) l->data;
518 l->data = NULL;
519 mwMessage_free(msg);
520 }
521 g_slist_free(chan->outgoing_queue);
522
523 /* clean up the incoming queue */
524 for(l = chan->incoming_queue; l; l = l->next) {
525 msg = (struct mwMessage *) l->data;
526 l->data = NULL;
527 mwMessage_free(msg);
528 }
529 g_slist_free(chan->incoming_queue);
530
531 g_free(chan);
532 }
533
534
535 int mwChannel_destroy(struct mwChannel *chan,
536 guint32 reason, struct mwOpaque *info) {
537
538 struct mwMsgChannelDestroy *msg;
539 struct mwSession *session;
540 struct mwChannelSet *cs;
541 int ret;
542
543 /* may make this not a warning in the future */
544 g_return_val_if_fail(chan != NULL, 0);
545
546 state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason);
547
548 session = chan->session;
549 g_return_val_if_fail(session != NULL, -1);
550
551 cs = mwSession_getChannels(session);
552 g_return_val_if_fail(cs != NULL, -1);
553
554 /* compose the message */
555 msg = (struct mwMsgChannelDestroy *)
556 mwMessage_new(mwMessage_CHANNEL_DESTROY);
557 msg->head.channel = chan->id;
558 msg->reason = reason;
559 if(info) mwOpaque_clone(&msg->data, info);
560
561 /* remove the channel from the channel set */
562 g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
563
564 /* send the message */
565 ret = mwSession_send(session, (struct mwMessage *) msg);
566 mwMessage_free(MW_MESSAGE(msg));
567
568 return ret;
569 }
570
571
572 static void queue_outgoing(struct mwChannel *chan,
573 struct mwMsgChannelSend *msg) {
574
575 g_info("queue_outgoing, channel 0x%08x", chan->id);
576 chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg);
577 }
578
579
580 static int channel_send(struct mwChannel *chan,
581 struct mwMsgChannelSend *msg) {
582
583 int ret = 0;
584
585 /* if the channel is open, send and free the message. Otherwise,
586 queue the message to be sent once the channel is finally
587 opened */
588
589 if(chan->state == mwChannel_OPEN) {
590 ret = mwSession_send(chan->session, (struct mwMessage *) msg);
591 mwMessage_free(MW_MESSAGE(msg));
592
593 } else {
594 queue_outgoing(chan, msg);
595 }
596
597 return ret;
598 }
599
600
601 int mwChannel_sendEncrypted(struct mwChannel *chan,
602 guint32 type, struct mwOpaque *data,
603 gboolean encrypt) {
604
605 struct mwMsgChannelSend *msg;
606
607 g_return_val_if_fail(chan != NULL, -1);
608
609 msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND);
610 msg->head.channel = chan->id;
611 msg->type = type;
612
613 mwOpaque_clone(&msg->data, data);
614
615 if(encrypt && chan->cipher) {
616 msg->head.options = mwMessageOption_ENCRYPT;
617 mwCipherInstance_encrypt(chan->cipher, &msg->data);
618 }
619
620 return channel_send(chan, msg);
621 }
622
623
624 int mwChannel_send(struct mwChannel *chan, guint32 type,
625 struct mwOpaque *data) {
626
627 return mwChannel_sendEncrypted(chan, type, data, TRUE);
628 }
629
630
631 static void queue_incoming(struct mwChannel *chan,
632 struct mwMsgChannelSend *msg) {
633
634 /* we clone the message, because session_process will clear it once
635 we return */
636
637 struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1);
638 m->head.type = msg->head.type;
639 m->head.options = msg->head.options;
640 m->head.channel = msg->head.channel;
641 mwOpaque_clone(&m->head.attribs, &msg->head.attribs);
642
643 m->type = msg->type;
644 mwOpaque_clone(&m->data, &msg->data);
645
646 g_info("queue_incoming, channel 0x%08x", chan->id);
647 chan->incoming_queue = g_slist_append(chan->incoming_queue, m);
648 }
649
650
651 static void channel_recv(struct mwChannel *chan,
652 struct mwMsgChannelSend *msg) {
653
654 struct mwService *srvc;
655 srvc = mwChannel_getService(chan);
656
657 incr_stat(chan, mwChannelStat_MSG_RECV, 1);
658
659 if(msg->head.options & mwMessageOption_ENCRYPT) {
660 struct mwOpaque data = { 0, 0 };
661 mwOpaque_clone(&data, &msg->data);
662
663 mwCipherInstance_decrypt(chan->cipher, &data);
664 mwService_recv(srvc, chan, msg->type, &data);
665 mwOpaque_clear(&data);
666
667 } else {
668 mwService_recv(srvc, chan, msg->type, &msg->data);
669 }
670 }
671
672
673 static void flush_channel(struct mwChannel *chan) {
674 GSList *l;
675
676 for(l = chan->incoming_queue; l; l = l->next) {
677 struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data;
678 l->data = NULL;
679
680 channel_recv(chan, msg);
681 mwMessage_free(MW_MESSAGE(msg));
682 }
683 g_slist_free(chan->incoming_queue);
684 chan->incoming_queue = NULL;
685
686 for(l = chan->outgoing_queue; l; l = l->next) {
687 struct mwMessage *msg = (struct mwMessage *) l->data;
688 l->data = NULL;
689
690 mwSession_send(chan->session, msg);
691 mwMessage_free(msg);
692 }
693 g_slist_free(chan->outgoing_queue);
694 chan->outgoing_queue = NULL;
695 }
696
697
698 void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) {
699 if(chan->state == mwChannel_OPEN) {
700 channel_recv(chan, msg);
701
702 } else {
703 queue_incoming(chan, msg);
704 }
705 }
706
707
708 struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) {
709 g_return_val_if_fail(cs != NULL, NULL);
710 g_return_val_if_fail(cs->map != NULL, NULL);
711 return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan));
712 }
713
714
715 void mwChannelSet_free(struct mwChannelSet *cs) {
716 if(! cs) return;
717 if(cs->map) g_hash_table_destroy(cs->map);
718 g_free(cs);
719 }
720
721
722 struct mwChannelSet *mwChannelSet_new(struct mwSession *s) {
723 struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1);
724 cs->session = s;
725
726 /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */
727 cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
728 NULL, (GDestroyNotify) channel_free);
729 return cs;
730 }
731
732
733 void mwChannel_recvCreate(struct mwChannel *chan,
734 struct mwMsgChannelCreate *msg) {
735
736 struct mwSession *session;
737 GList *list;
738 struct mwService *srvc;
739
740 g_return_if_fail(chan != NULL);
741 g_return_if_fail(msg != NULL);
742 g_return_if_fail(chan->id == msg->channel);
743
744 session = chan->session;
745 g_return_if_fail(session != NULL);
746
747 if(mwChannel_isOutgoing(chan)) {
748 g_warning("channel 0x%08x not an incoming channel", chan->id);
749 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
750 return;
751 }
752
753 chan->offered_policy = msg->encrypt.mode;
754 g_message("channel offered with encrypt policy 0x%04x", chan->policy);
755
756 for(list = msg->encrypt.items; list; list = list->next) {
757 struct mwEncryptItem *ei = list->data;
758 struct mwCipher *cipher;
759 struct mwCipherInstance *ci;
760
761 g_message("channel offered cipher id 0x%04x", ei->id);
762 cipher = mwSession_getCipher(session, ei->id);
763 if(! cipher) {
764 g_message("no such cipher found in session");
765 continue;
766 }
767
768 ci = mwCipher_newInstance(cipher, chan);
769 mwCipherInstance_offered(ci, ei);
770 mwChannel_addSupportedCipherInstance(chan, ci);
771 }
772
773 mwLoginInfo_clone(&chan->user, &msg->creator);
774 chan->service = msg->service;
775 chan->proto_type = msg->proto_type;
776 chan->proto_ver = msg->proto_ver;
777
778 srvc = mwSession_getService(session, msg->service);
779 if(srvc) {
780 mwService_recvCreate(srvc, chan, msg);
781
782 } else {
783 mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
784 }
785 }
786
787
788 void mwChannel_recvAccept(struct mwChannel *chan,
789 struct mwMsgChannelAccept *msg) {
790
791 struct mwService *srvc;
792
793 g_return_if_fail(chan != NULL);
794 g_return_if_fail(msg != NULL);
795 g_return_if_fail(chan->id == msg->head.channel);
796
797 if(mwChannel_isIncoming(chan)) {
798 g_warning("channel 0x%08x not an outgoing channel", chan->id);
799 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
800 return;
801 }
802
803 if(chan->state != mwChannel_WAIT) {
804 g_warning("channel 0x%08x state not WAIT: %s",
805 chan->id, state_str(chan->state));
806 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
807 return;
808 }
809
810 mwLoginInfo_clone(&chan->user, &msg->acceptor);
811
812 srvc = mwSession_getService(chan->session, chan->service);
813 if(! srvc) {
814 g_warning("no service: 0x%08x", chan->service);
815 mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL);
816 return;
817 }
818
819 chan->policy = msg->encrypt.mode;
820 g_message("channel accepted with encrypt policy 0x%04x", chan->policy);
821
822 if(! msg->encrypt.mode || ! msg->encrypt.item) {
823 /* no mode or no item means no encryption */
824 mwChannel_selectCipherInstance(chan, NULL);
825
826 } else {
827 guint16 cid = msg->encrypt.item->id;
828 struct mwCipherInstance *ci = get_supported(chan, cid);
829
830 if(! ci) {
831 g_warning("not an offered cipher: 0x%04x", cid);
832 mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL);
833 return;
834 }
835
836 mwCipherInstance_accepted(ci, msg->encrypt.item);
837 mwChannel_selectCipherInstance(chan, ci);
838 }
839
840 /* mark it as open for the service */
841 state(chan, mwChannel_OPEN, 0);
842
843 /* let the service know */
844 mwService_recvAccept(srvc, chan, msg);
845
846 /* flush it if the service didn't just immediately close it */
847 if(mwChannel_isState(chan, mwChannel_OPEN)) {
848 channel_open(chan);
849 }
850 }
851
852
853 void mwChannel_recvDestroy(struct mwChannel *chan,
854 struct mwMsgChannelDestroy *msg) {
855
856 struct mwChannelSet *cs;
857 struct mwService *srvc;
858
859 g_return_if_fail(chan != NULL);
860 g_return_if_fail(msg != NULL);
861 g_return_if_fail(chan->id == msg->head.channel);
862
863 state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason);
864
865 srvc = mwChannel_getService(chan);
866 if(srvc) mwService_recvDestroy(srvc, chan, msg);
867
868 cs = mwSession_getChannels(chan->session);
869 g_return_if_fail(cs != NULL);
870 g_return_if_fail(cs->map != NULL);
871
872 g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id));
873 }
874
875
876 void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) {
877 struct mwSession *session;
878 GList *list;
879
880 g_return_if_fail(chan != NULL);
881
882 session = chan->session;
883 g_return_if_fail(session != NULL);
884
885 for(list = mwSession_getCiphers(session); list; list = list->next) {
886 struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan);
887 if(! ci) continue;
888 put_supported(chan, ci);
889 }
890 }
891
892
893 void mwChannel_addSupportedCipherInstance(struct mwChannel *chan,
894 struct mwCipherInstance *ci) {
895 g_return_if_fail(chan != NULL);
896 g_message("channel 0x%08x added cipher %s", chan->id,
897 NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci))));
898 put_supported(chan, ci);
899 }
900
901
902 static void collect(gpointer a, gpointer b, gpointer c) {
903 GList **list = c;
904 *list = g_list_append(*list, b);
905 }
906
907
908 GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) {
909 GList *list = NULL;
910
911 g_return_val_if_fail(chan != NULL, NULL);
912 g_hash_table_foreach(chan->supported, collect, &list);
913
914 return list;
915 }
916
917
918 void mwChannel_selectCipherInstance(struct mwChannel *chan,
919 struct mwCipherInstance *ci) {
920 struct mwCipher *c;
921
922 g_return_if_fail(chan != NULL);
923 g_return_if_fail(chan->supported != NULL);
924
925 chan->cipher = ci;
926 if(ci) {
927 guint cid;
928
929 c = mwCipherInstance_getCipher(ci);
930 cid = mwCipher_getType(c);
931
932 g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid));
933
934 switch(mwCipher_getType(c)) {
935 case mwCipher_RC2_40:
936 chan->policy = mwEncrypt_RC2_40;
937 break;
938
939 case mwCipher_RC2_128:
940 chan->policy = mwEncrypt_RC2_128;
941 break;
942
943 default:
944 /* unsure if this is bad */
945 chan->policy = mwEncrypt_WHATEVER;
946 }
947
948 g_message("channel 0x%08x selected cipher %s",
949 chan->id, NSTR(mwCipher_getName(c)));
950
951 } else {
952
953 chan->policy = mwEncrypt_NONE;
954 g_message("channel 0x%08x selected no cipher", chan->id);
955 }
956
957 g_hash_table_destroy(chan->supported);
958 chan->supported = NULL;
959 }
960
961

mercurial