diff -r 39a4efae983c -r 9af807a5c9e7 src/protocols/sametime/meanwhile/channel.c --- a/src/protocols/sametime/meanwhile/channel.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,961 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include - -#include "mw_channel.h" -#include "mw_cipher.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_util.h" - - -/** @todo reorganize this file, stuff is just strewn about */ - - -struct mwChannel { - - /** session this channel belongs to */ - struct mwSession *session; - - enum mwChannelState state; - - /** creator for incoming channel, target for outgoing channel */ - struct mwLoginInfo user; - - /* similar to data from the CreateCnl message in 8.4.1.7 */ - guint32 reserved; /**< special, unknown meaning */ - guint32 id; /**< channel ID */ - guint32 service; /**< service ID */ - guint32 proto_type; /**< service protocol type */ - guint32 proto_ver; /**< service protocol version */ - guint32 options; /**< channel options */ - - struct mwOpaque addtl_create; - struct mwOpaque addtl_accept; - - /** all those supported ciphers */ - GHashTable *supported; - guint16 offered_policy; /**< @see enum mwEncryptPolicy */ - guint16 policy; /**< @see enum mwEncryptPolicy */ - - /** cipher information determined at channel acceptance */ - struct mwCipherInstance *cipher; - - /** statistics table */ - GHashTable *stats; - - GSList *outgoing_queue; /**< queued outgoing messages */ - GSList *incoming_queue; /**< queued incoming messages */ - - struct mw_datum srvc_data; /**< service-specific data */ -}; - - -struct mwChannelSet { - struct mwSession *session; /**< owning session */ - GHashTable *map; /**< map of all channels, by ID */ - guint32 counter; /**< counter for outgoing ID */ -}; - - -static void flush_channel(struct mwChannel *); - - -static const char *state_str(enum mwChannelState state) { - switch(state) { - case mwChannel_NEW: return "new"; - case mwChannel_INIT: return "initializing"; - case mwChannel_WAIT: return "waiting"; - case mwChannel_OPEN: return "open"; - case mwChannel_DESTROY: return "closing"; - case mwChannel_ERROR: return "error"; - - case mwChannel_UNKNOWN: /* fall through */ - default: return "UNKNOWN"; - } -} - - -static void state(struct mwChannel *chan, enum mwChannelState state, - guint32 err_code) { - - g_return_if_fail(chan != NULL); - - if(chan->state == state) return; - - chan->state = state; - - if(err_code) { - g_message("channel 0x%08x state: %s (0x%08x)", - chan->id, state_str(state), err_code); - } else { - g_message("channel 0x%08x state: %s", chan->id, state_str(state)); - } -} - - -static gpointer get_stat(struct mwChannel *chan, - enum mwChannelStatField field) { - - return g_hash_table_lookup(chan->stats, (gpointer) field); -} - - -static void set_stat(struct mwChannel *chan, enum mwChannelStatField field, - gpointer val) { - - g_hash_table_insert(chan->stats, (gpointer) field, val); -} - - -#define incr_stat(chan, field, incr) \ - set_stat(chan, field, get_stat(chan, field) + incr) - - -#define timestamp_stat(chan, field) \ - set_stat(chan, field, (gpointer) time(NULL)) - - -static void sup_free(gpointer a) { - mwCipherInstance_free(a); -} - - -struct mwCipherInstance *get_supported(struct mwChannel *chan, guint16 id) { - guint32 cid = (guint32) id; - return g_hash_table_lookup(chan->supported, GUINT_TO_POINTER(cid)); -} - - -void put_supported(struct mwChannel *chan, struct mwCipherInstance *ci) { - struct mwCipher *cipher = mwCipherInstance_getCipher(ci); - guint32 cid = (guint32) mwCipher_getType(cipher); - g_hash_table_insert(chan->supported, GUINT_TO_POINTER(cid), ci); -} - - -struct mwChannel *mwChannel_newIncoming(struct mwChannelSet *cs, guint32 id) { - struct mwChannel *chan; - - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->session != NULL, NULL); - - chan = g_new0(struct mwChannel, 1); - chan->state = mwChannel_NEW; - chan->session = cs->session; - chan->id = id; - - chan->stats = g_hash_table_new(g_direct_hash, g_direct_equal); - - chan->supported = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, sup_free); - - g_hash_table_insert(cs->map, GUINT_TO_POINTER(id), chan); - - state(chan, mwChannel_WAIT, 0); - - return chan; -} - - -struct mwChannel *mwChannel_newOutgoing(struct mwChannelSet *cs) { - guint32 id; - struct mwChannel *chan; - - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->map != NULL, NULL); - - /* grab the next id, and try to make sure there isn't already a - channel using it */ - do { - id = ++cs->counter; - } while(g_hash_table_lookup(cs->map, GUINT_TO_POINTER(id))); - - chan = mwChannel_newIncoming(cs, id); - state(chan, mwChannel_INIT, 0); - - return chan; -} - - -guint32 mwChannel_getId(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0); - return chan->id; -} - - -struct mwSession *mwChannel_getSession(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return chan->session; -} - - -guint32 mwChannel_getServiceId(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0); - return chan->service; -} - - -struct mwService *mwChannel_getService(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return mwSession_getService(chan->session, chan->service); -} - - -void mwChannel_setService(struct mwChannel *chan, struct mwService *srvc) { - g_return_if_fail(chan != NULL); - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->service = mwService_getType(srvc); -} - - -gpointer mwChannel_getServiceData(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return mw_datum_get(&chan->srvc_data); -} - - -void mwChannel_setServiceData(struct mwChannel *chan, - gpointer data, GDestroyNotify clean) { - - g_return_if_fail(chan != NULL); - mw_datum_set(&chan->srvc_data, data, clean); -} - - -void mwChannel_removeServiceData(struct mwChannel *chan) { - g_return_if_fail(chan != NULL); - mw_datum_clear(&chan->srvc_data); -} - - -guint32 mwChannel_getProtoType(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->proto_type; -} - - -void mwChannel_setProtoType(struct mwChannel *chan, guint32 proto_type) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->proto_type = proto_type; -} - - -guint32 mwChannel_getProtoVer(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->proto_ver; -} - - -void mwChannel_setProtoVer(struct mwChannel *chan, guint32 proto_ver) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->proto_ver = proto_ver; -} - - -guint16 mwChannel_getEncryptPolicy(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->policy; -} - - -guint32 mwChannel_getOptions(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, 0x00); - return chan->options; -} - - -void mwChannel_setOptions(struct mwChannel *chan, guint32 options) { - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->state == mwChannel_INIT); - chan->options = options; -} - - -struct mwLoginInfo *mwChannel_getUser(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->user; -} - - -struct mwOpaque *mwChannel_getAddtlCreate(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->addtl_create; -} - - -struct mwOpaque *mwChannel_getAddtlAccept(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return &chan->addtl_accept; -} - - -struct mwCipherInstance *mwChannel_getCipherInstance(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, NULL); - return chan->cipher; -} - - -enum mwChannelState mwChannel_getState(struct mwChannel *chan) { - g_return_val_if_fail(chan != NULL, mwChannel_UNKNOWN); - return chan->state; -} - - -gpointer mwChannel_getStatistic(struct mwChannel *chan, - enum mwChannelStatField stat) { - - g_return_val_if_fail(chan != NULL, 0); - g_return_val_if_fail(chan->stats != NULL, 0); - - return get_stat(chan, stat); -} - - -/* send a channel create message */ -int mwChannel_create(struct mwChannel *chan) { - struct mwMsgChannelCreate *msg; - GList *list, *l; - int ret; - - g_return_val_if_fail(chan != NULL, -1); - g_return_val_if_fail(chan->state == mwChannel_INIT, -1); - g_return_val_if_fail(mwChannel_isOutgoing(chan), -1); - - msg = (struct mwMsgChannelCreate *) - mwMessage_new(mwMessage_CHANNEL_CREATE); - - msg->channel = chan->id; - msg->target.user = g_strdup(chan->user.user_id); - msg->target.community = g_strdup(chan->user.community); - msg->service = chan->service; - msg->proto_type = chan->proto_type; - msg->proto_ver = chan->proto_ver; - msg->options = chan->options; - mwOpaque_clone(&msg->addtl, &chan->addtl_create); - - list = mwChannel_getSupportedCipherInstances(chan); - if(list) { - /* offer what we have */ - for(l = list; l; l = l->next) { - struct mwEncryptItem *ei = mwCipherInstance_offer(l->data); - msg->encrypt.items = g_list_append(msg->encrypt.items, ei); - } - - /* we're easy to get along with */ - chan->offered_policy = mwEncrypt_WHATEVER; - g_list_free(list); - - } else { - /* we apparently don't support anything */ - chan->offered_policy = mwEncrypt_NONE; - } - - msg->encrypt.mode = chan->offered_policy; - msg->encrypt.extra = chan->offered_policy; - - ret = mwSession_send(chan->session, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - state(chan, (ret)? mwChannel_ERROR: mwChannel_WAIT, ret); - - return ret; -} - - -static void channel_open(struct mwChannel *chan) { - state(chan, mwChannel_OPEN, 0); - timestamp_stat(chan, mwChannelStat_OPENED_AT); - flush_channel(chan); -} - - -int mwChannel_accept(struct mwChannel *chan) { - struct mwSession *session; - struct mwMsgChannelAccept *msg; - struct mwCipherInstance *ci; - - int ret; - - g_return_val_if_fail(chan != NULL, -1); - g_return_val_if_fail(mwChannel_isIncoming(chan), -1); - g_return_val_if_fail(chan->state == mwChannel_WAIT, -1); - - session = chan->session; - g_return_val_if_fail(session != NULL, -1); - - msg = (struct mwMsgChannelAccept *) - mwMessage_new(mwMessage_CHANNEL_ACCEPT); - - msg->head.channel = chan->id; - msg->service = chan->service; - msg->proto_type = chan->proto_type; - msg->proto_ver = chan->proto_ver; - mwOpaque_clone(&msg->addtl, &chan->addtl_accept); - - ci = chan->cipher; - - if(! ci) { - /* automatically select a cipher if one hasn't been already */ - - switch(chan->offered_policy) { - case mwEncrypt_NONE: - mwChannel_selectCipherInstance(chan, NULL); - break; - - case mwEncrypt_RC2_40: - ci = get_supported(chan, mwCipher_RC2_40); - mwChannel_selectCipherInstance(chan, ci); - break; - - case mwEncrypt_RC2_128: - ci = get_supported(chan, mwCipher_RC2_128); - mwChannel_selectCipherInstance(chan, ci); - break; - - case mwEncrypt_WHATEVER: - case mwEncrypt_ALL: - default: - { - GList *l, *ll; - - l = mwChannel_getSupportedCipherInstances(chan); - if(l) { - /* nobody selected a cipher, so we'll just pick the last in - the list of available ones */ - for(ll = l; ll->next; ll = ll->next); - ci = ll->data; - g_list_free(l); - - mwChannel_selectCipherInstance(chan, ci); - - } else { - /* this may cause breakage, but there's really nothing else - we can do. They want something we can't provide. If they - don't like it, then they'll error the channel out */ - mwChannel_selectCipherInstance(chan, NULL); - } - } - } - } - - msg->encrypt.mode = chan->policy; /* set in selectCipherInstance */ - msg->encrypt.extra = chan->offered_policy; - - if(chan->cipher) { - msg->encrypt.item = mwCipherInstance_accept(chan->cipher); - } - - ret = mwSession_send(session, MW_MESSAGE(msg)); - mwMessage_free(MW_MESSAGE(msg)); - - if(ret) { - state(chan, mwChannel_ERROR, ret); - } else { - channel_open(chan); - } - - return ret; -} - - -static void channel_free(struct mwChannel *chan) { - struct mwSession *s; - struct mwMessage *msg; - GSList *l; - - /* maybe no warning in the future */ - g_return_if_fail(chan != NULL); - - s = chan->session; - - mwLoginInfo_clear(&chan->user); - mwOpaque_clear(&chan->addtl_create); - mwOpaque_clear(&chan->addtl_accept); - - if(chan->supported) { - g_hash_table_destroy(chan->supported); - chan->supported = NULL; - } - - if(chan->stats) { - g_hash_table_destroy(chan->stats); - chan->stats = NULL; - } - - mwCipherInstance_free(chan->cipher); - - /* clean up the outgoing queue */ - for(l = chan->outgoing_queue; l; l = l->next) { - msg = (struct mwMessage *) l->data; - l->data = NULL; - mwMessage_free(msg); - } - g_slist_free(chan->outgoing_queue); - - /* clean up the incoming queue */ - for(l = chan->incoming_queue; l; l = l->next) { - msg = (struct mwMessage *) l->data; - l->data = NULL; - mwMessage_free(msg); - } - g_slist_free(chan->incoming_queue); - - g_free(chan); -} - - -int mwChannel_destroy(struct mwChannel *chan, - guint32 reason, struct mwOpaque *info) { - - struct mwMsgChannelDestroy *msg; - struct mwSession *session; - struct mwChannelSet *cs; - int ret; - - /* may make this not a warning in the future */ - g_return_val_if_fail(chan != NULL, 0); - - state(chan, reason? mwChannel_ERROR: mwChannel_DESTROY, reason); - - session = chan->session; - g_return_val_if_fail(session != NULL, -1); - - cs = mwSession_getChannels(session); - g_return_val_if_fail(cs != NULL, -1); - - /* compose the message */ - msg = (struct mwMsgChannelDestroy *) - mwMessage_new(mwMessage_CHANNEL_DESTROY); - msg->head.channel = chan->id; - msg->reason = reason; - if(info) mwOpaque_clone(&msg->data, info); - - /* remove the channel from the channel set */ - g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); - - /* send the message */ - ret = mwSession_send(session, (struct mwMessage *) msg); - mwMessage_free(MW_MESSAGE(msg)); - - return ret; -} - - -static void queue_outgoing(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - g_info("queue_outgoing, channel 0x%08x", chan->id); - chan->outgoing_queue = g_slist_append(chan->outgoing_queue, msg); -} - - -static int channel_send(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - int ret = 0; - - /* if the channel is open, send and free the message. Otherwise, - queue the message to be sent once the channel is finally - opened */ - - if(chan->state == mwChannel_OPEN) { - ret = mwSession_send(chan->session, (struct mwMessage *) msg); - mwMessage_free(MW_MESSAGE(msg)); - - } else { - queue_outgoing(chan, msg); - } - - return ret; -} - - -int mwChannel_sendEncrypted(struct mwChannel *chan, - guint32 type, struct mwOpaque *data, - gboolean encrypt) { - - struct mwMsgChannelSend *msg; - - g_return_val_if_fail(chan != NULL, -1); - - msg = (struct mwMsgChannelSend *) mwMessage_new(mwMessage_CHANNEL_SEND); - msg->head.channel = chan->id; - msg->type = type; - - mwOpaque_clone(&msg->data, data); - - if(encrypt && chan->cipher) { - msg->head.options = mwMessageOption_ENCRYPT; - mwCipherInstance_encrypt(chan->cipher, &msg->data); - } - - return channel_send(chan, msg); -} - - -int mwChannel_send(struct mwChannel *chan, guint32 type, - struct mwOpaque *data) { - - return mwChannel_sendEncrypted(chan, type, data, TRUE); -} - - -static void queue_incoming(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - /* we clone the message, because session_process will clear it once - we return */ - - struct mwMsgChannelSend *m = g_new0(struct mwMsgChannelSend, 1); - m->head.type = msg->head.type; - m->head.options = msg->head.options; - m->head.channel = msg->head.channel; - mwOpaque_clone(&m->head.attribs, &msg->head.attribs); - - m->type = msg->type; - mwOpaque_clone(&m->data, &msg->data); - - g_info("queue_incoming, channel 0x%08x", chan->id); - chan->incoming_queue = g_slist_append(chan->incoming_queue, m); -} - - -static void channel_recv(struct mwChannel *chan, - struct mwMsgChannelSend *msg) { - - struct mwService *srvc; - srvc = mwChannel_getService(chan); - - incr_stat(chan, mwChannelStat_MSG_RECV, 1); - - if(msg->head.options & mwMessageOption_ENCRYPT) { - struct mwOpaque data = { 0, 0 }; - mwOpaque_clone(&data, &msg->data); - - mwCipherInstance_decrypt(chan->cipher, &data); - mwService_recv(srvc, chan, msg->type, &data); - mwOpaque_clear(&data); - - } else { - mwService_recv(srvc, chan, msg->type, &msg->data); - } -} - - -static void flush_channel(struct mwChannel *chan) { - GSList *l; - - for(l = chan->incoming_queue; l; l = l->next) { - struct mwMsgChannelSend *msg = (struct mwMsgChannelSend *) l->data; - l->data = NULL; - - channel_recv(chan, msg); - mwMessage_free(MW_MESSAGE(msg)); - } - g_slist_free(chan->incoming_queue); - chan->incoming_queue = NULL; - - for(l = chan->outgoing_queue; l; l = l->next) { - struct mwMessage *msg = (struct mwMessage *) l->data; - l->data = NULL; - - mwSession_send(chan->session, msg); - mwMessage_free(msg); - } - g_slist_free(chan->outgoing_queue); - chan->outgoing_queue = NULL; -} - - -void mwChannel_recv(struct mwChannel *chan, struct mwMsgChannelSend *msg) { - if(chan->state == mwChannel_OPEN) { - channel_recv(chan, msg); - - } else { - queue_incoming(chan, msg); - } -} - - -struct mwChannel *mwChannel_find(struct mwChannelSet *cs, guint32 chan) { - g_return_val_if_fail(cs != NULL, NULL); - g_return_val_if_fail(cs->map != NULL, NULL); - return g_hash_table_lookup(cs->map, GUINT_TO_POINTER(chan)); -} - - -void mwChannelSet_free(struct mwChannelSet *cs) { - if(! cs) return; - if(cs->map) g_hash_table_destroy(cs->map); - g_free(cs); -} - - -struct mwChannelSet *mwChannelSet_new(struct mwSession *s) { - struct mwChannelSet *cs = g_new0(struct mwChannelSet, 1); - cs->session = s; - - /* for some reason, g_int_hash/g_int_equal cause a SIGSEGV */ - cs->map = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) channel_free); - return cs; -} - - -void mwChannel_recvCreate(struct mwChannel *chan, - struct mwMsgChannelCreate *msg) { - - struct mwSession *session; - GList *list; - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->channel); - - session = chan->session; - g_return_if_fail(session != NULL); - - if(mwChannel_isOutgoing(chan)) { - g_warning("channel 0x%08x not an incoming channel", chan->id); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - chan->offered_policy = msg->encrypt.mode; - g_message("channel offered with encrypt policy 0x%04x", chan->policy); - - for(list = msg->encrypt.items; list; list = list->next) { - struct mwEncryptItem *ei = list->data; - struct mwCipher *cipher; - struct mwCipherInstance *ci; - - g_message("channel offered cipher id 0x%04x", ei->id); - cipher = mwSession_getCipher(session, ei->id); - if(! cipher) { - g_message("no such cipher found in session"); - continue; - } - - ci = mwCipher_newInstance(cipher, chan); - mwCipherInstance_offered(ci, ei); - mwChannel_addSupportedCipherInstance(chan, ci); - } - - mwLoginInfo_clone(&chan->user, &msg->creator); - chan->service = msg->service; - chan->proto_type = msg->proto_type; - chan->proto_ver = msg->proto_ver; - - srvc = mwSession_getService(session, msg->service); - if(srvc) { - mwService_recvCreate(srvc, chan, msg); - - } else { - mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); - } -} - - -void mwChannel_recvAccept(struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->head.channel); - - if(mwChannel_isIncoming(chan)) { - g_warning("channel 0x%08x not an outgoing channel", chan->id); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - if(chan->state != mwChannel_WAIT) { - g_warning("channel 0x%08x state not WAIT: %s", - chan->id, state_str(chan->state)); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - mwLoginInfo_clone(&chan->user, &msg->acceptor); - - srvc = mwSession_getService(chan->session, chan->service); - if(! srvc) { - g_warning("no service: 0x%08x", chan->service); - mwChannel_destroy(chan, ERR_SERVICE_NO_SUPPORT, NULL); - return; - } - - chan->policy = msg->encrypt.mode; - g_message("channel accepted with encrypt policy 0x%04x", chan->policy); - - if(! msg->encrypt.mode || ! msg->encrypt.item) { - /* no mode or no item means no encryption */ - mwChannel_selectCipherInstance(chan, NULL); - - } else { - guint16 cid = msg->encrypt.item->id; - struct mwCipherInstance *ci = get_supported(chan, cid); - - if(! ci) { - g_warning("not an offered cipher: 0x%04x", cid); - mwChannel_destroy(chan, ERR_REQUEST_INVALID, NULL); - return; - } - - mwCipherInstance_accepted(ci, msg->encrypt.item); - mwChannel_selectCipherInstance(chan, ci); - } - - /* mark it as open for the service */ - state(chan, mwChannel_OPEN, 0); - - /* let the service know */ - mwService_recvAccept(srvc, chan, msg); - - /* flush it if the service didn't just immediately close it */ - if(mwChannel_isState(chan, mwChannel_OPEN)) { - channel_open(chan); - } -} - - -void mwChannel_recvDestroy(struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwChannelSet *cs; - struct mwService *srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(msg != NULL); - g_return_if_fail(chan->id == msg->head.channel); - - state(chan, msg->reason? mwChannel_ERROR: mwChannel_DESTROY, msg->reason); - - srvc = mwChannel_getService(chan); - if(srvc) mwService_recvDestroy(srvc, chan, msg); - - cs = mwSession_getChannels(chan->session); - g_return_if_fail(cs != NULL); - g_return_if_fail(cs->map != NULL); - - g_hash_table_remove(cs->map, GUINT_TO_POINTER(chan->id)); -} - - -void mwChannel_populateSupportedCipherInstances(struct mwChannel *chan) { - struct mwSession *session; - GList *list; - - g_return_if_fail(chan != NULL); - - session = chan->session; - g_return_if_fail(session != NULL); - - for(list = mwSession_getCiphers(session); list; list = list->next) { - struct mwCipherInstance *ci = mwCipher_newInstance(list->data, chan); - if(! ci) continue; - put_supported(chan, ci); - } -} - - -void mwChannel_addSupportedCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci) { - g_return_if_fail(chan != NULL); - g_message("channel 0x%08x added cipher %s", chan->id, - NSTR(mwCipher_getName(mwCipherInstance_getCipher(ci)))); - put_supported(chan, ci); -} - - -static void collect(gpointer a, gpointer b, gpointer c) { - GList **list = c; - *list = g_list_append(*list, b); -} - - -GList *mwChannel_getSupportedCipherInstances(struct mwChannel *chan) { - GList *list = NULL; - - g_return_val_if_fail(chan != NULL, NULL); - g_hash_table_foreach(chan->supported, collect, &list); - - return list; -} - - -void mwChannel_selectCipherInstance(struct mwChannel *chan, - struct mwCipherInstance *ci) { - struct mwCipher *c; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan->supported != NULL); - - chan->cipher = ci; - if(ci) { - guint cid; - - c = mwCipherInstance_getCipher(ci); - cid = mwCipher_getType(c); - - g_hash_table_steal(chan->supported, GUINT_TO_POINTER(cid)); - - switch(mwCipher_getType(c)) { - case mwCipher_RC2_40: - chan->policy = mwEncrypt_RC2_40; - break; - - case mwCipher_RC2_128: - chan->policy = mwEncrypt_RC2_128; - break; - - default: - /* unsure if this is bad */ - chan->policy = mwEncrypt_WHATEVER; - } - - g_message("channel 0x%08x selected cipher %s", - chan->id, NSTR(mwCipher_getName(c))); - - } else { - - chan->policy = mwEncrypt_NONE; - g_message("channel 0x%08x selected no cipher", chan->id); - } - - g_hash_table_destroy(chan->supported); - chan->supported = NULL; -} - -