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 mwMessageHead_clone(struct mwMessage *to, struct mwMessage *from) { to->type = from->type; to->options = from->options; to->channel = from->channel; mwOpaque_clone(&to->attribs, &from->attribs); }
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); }
struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, struct mwOpaque *data) { struct mwStorageUnit *u; u = g_new0(struct mwStorageUnit, 1); u->key = key; if(data) mwOpaque_clone(&u->data, data); return u; }
/* 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_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); } }
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_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; }