Blame src/channel.c

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