conn->remote_host = strdup(hostname);
conn->remote_port = port;
conn->context = context;
+ conn->pending_commands = silc_dlist_init();
/* Add the connection to connections table */
for (i = 0; i < client->conns_count; i++)
for (i = 0; i < client->conns_count; i++)
if (client->conns[i] == conn) {
+ if (conn->pending_commands)
+ silc_dlist_uninit(conn->pending_commands);
silc_free(conn);
client->conns[i] = NULL;
}
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
SILC_LOG_DEBUG(("Error during KE protocol"));
silc_protocol_free(protocol);
/* Free old protocol as it is finished now */
silc_protocol_free(protocol);
if (ctx->packet)
- silc_buffer_free(ctx->packet);
+ silc_packet_context_free(ctx->packet);
silc_free(ctx);
/* silc_free(ctx->keymat....); */
sock->protocol = NULL;
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
SILC_LOG_DEBUG(("Error during authentication protocol"));
silc_protocol_free(protocol);
silc_free(ctx->auth_data);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
silc_free(ctx);
conn->sock->protocol = NULL;
}
silc_client_packet_parse_type(client, sock, packet);
out:
- silc_buffer_clear(buffer);
- if (packet->src_id)
- silc_free(packet->src_id);
- if (packet->dst_id)
- silc_free(packet->dst_id);
- silc_free(packet);
+ silc_buffer_clear(sock->inbuf);
+ silc_packet_context_free(packet);
silc_free(parse_ctx);
}
SilcClientKEInternalContext *proto_ctx =
(SilcClientKEInternalContext *)sock->protocol->context;
- proto_ctx->packet = buffer;
+ proto_ctx->packet = silc_packet_context_dup(packet);
proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
/* Let the protocol handle the packet */
sock->protocol->execute(client->timeout_queue, 0,
(SilcClientKEInternalContext *)sock->protocol->context;
if (proto_ctx->packet)
- silc_buffer_free(proto_ctx->packet);
+ silc_packet_context_free(proto_ctx->packet);
- proto_ctx->packet = buffer;
+ proto_ctx->packet = silc_packet_context_dup(packet);
proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
/* Let the protocol handle the packet */
sock->protocol->execute(client->timeout_queue, 0,
SilcIDPayload idp;
idp = silc_id_payload_parse(buffer);
+ if (!idp)
+ break;
if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
break;
break;
}
+ case SILC_PACKET_HEARTBEAT:
+ /*
+ * Received heartbeat packet
+ */
+ SILC_LOG_DEBUG(("Heartbeat packet"));
+ break;
+
default:
SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
break;
/* Generate IV */
if (!channel->iv)
- for (i = 0; i < 16; i++)
- channel->iv[i] = silc_rng_get_byte(client->rng);
+ for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
else
silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
memset(conn->hmac_key, 0, conn->hmac_key_len);
silc_free(conn->hmac_key);
}
+ if (conn->pending_commands)
+ silc_dlist_uninit(conn->pending_commands);
conn->sock = NULL;
conn->remote_port = 0;
conn->local_id_data = NULL;
conn->remote_host = NULL;
conn->current_channel = NULL;
+ conn->pending_commands = NULL;
silc_client_del_connection(client, conn);
}
{
SilcPacketContext *p = (SilcPacketContext *)context;
silc_client_notify_by_server(p->context, p->sock, p);
- if (p->src_id)
- silc_free(p->src_id);
- if (p->dst_id)
- silc_free(p->dst_id);
- silc_buffer_free(p->buffer);
- silc_free(p);
+ silc_packet_context_free(p);
}
/* Received notify message from server */
SilcNotifyPayload payload;
SilcNotifyType type;
SilcArgumentPayload args;
- int i;
SilcClientID *client_id = NULL;
SilcChannelID *channel_id = NULL;
SilcClientEntry client_entry;
SilcClientEntry client_entry2;
SilcChannelEntry channel;
+ SilcChannelUser chu;
SilcIDCacheEntry id_cache = NULL;
unsigned char *tmp;
unsigned int tmp_len, mode;
payload = silc_notify_payload_parse(buffer);
+ if (!payload)
+ goto out;
+
type = silc_notify_get_type(payload);
args = silc_notify_get_args(payload);
if (!args)
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry and if not found query it */
client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
SilcPacketContext *p = silc_packet_context_dup(packet);
p->context = (void *)client;
p->sock = sock;
- silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
silc_client_notify_by_server_pending, p);
goto out;
}
goto out;
channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
/* XXX Will ALWAYS fail because currently we don't have way to resolve
channel information for channel that we're not joined to. */
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry and if not found query it */
client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
SilcPacketContext *p = silc_packet_context_dup(packet);
p->context = (void *)client;
p->sock = sock;
- silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
+ silc_client_notify_by_server_pending, p);
+ goto out;
+ }
+
+ /* If nickname or username hasn't been resolved, do so */
+ if (!client_entry->nickname || !client_entry->username) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+ silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
+ SILC_IDLIST_IDENT, 1,
+ 3, idp->data, idp->len);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
silc_client_notify_by_server_pending, p);
goto out;
}
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
channel = (SilcChannelEntry)id_cache->context;
/* Add client to channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client == NULL) {
- channel->clients[channel->clients_count].client = client_entry;
- channel->clients_count++;
- break;
- }
- }
-
- if (i == channel->clients_count) {
- channel->clients = silc_realloc(channel->clients,
- sizeof(*channel->clients) *
- (channel->clients_count + 1));
- channel->clients[channel->clients_count].client = client_entry;
- channel->clients[channel->clients_count].mode = 0;
- channel->clients_count++;
- }
+ chu = silc_calloc(1, sizeof(*chu));
+ chu->client = client_entry;
+ silc_list_add(channel->clients, chu);
/* XXX add support for multiple same nicks on same channel. Check
for them here */
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
channel = (SilcChannelEntry)id_cache->context;
/* Remove client from channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client == client_entry) {
- channel->clients[i].client = NULL;
- channel->clients_count--;
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ if (chu->client == client_entry) {
+ silc_list_del(channel->clients, chu);
+ silc_free(chu);
break;
}
}
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Ignore my ID */
if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
SilcPacketContext *p = silc_packet_context_dup(packet);
p->context = (void *)client;
p->sock = sock;
- silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
silc_client_notify_by_server_pending, p);
goto out;
}
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find old Client entry */
client_entry =
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
SILC_GET32_MSB(mode, tmp);
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
silc_free(client_id);
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find target Client entry */
client_entry2 =
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
channel = (SilcChannelEntry)id_cache->context;
/* Save the mode */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client == client_entry2) {
- channel->clients[i].mode = mode;
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ if (chu->client == client_entry) {
+ chu->mode = mode;
break;
}
}
channel->channel_name = channel_name;
channel->id = silc_id_payload_get_id(idp);
channel->mode = mode;
+ silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
+
conn->current_channel = channel;
/* Put it to the ID cache */
(void *)channel->id, (void *)channel, TRUE);
}
-/* Processes received key for channel. The received key will be used
- to protect the traffic on the channel for now on. Client must receive
- the key to the channel before talking on the channel is possible.
- This is the key that server has generated, this is not the channel
- private key, it is entirely local setting. */
+/* Saves channel key from encoded `key_payload'. This is used when we
+ receive Channel Key Payload and when we are processing JOIN command
+ reply. */
-void silc_client_receive_channel_key(SilcClient client,
- SilcSocketConnection sock,
- SilcBuffer packet)
+void silc_client_save_channel_key(SilcClientConnection conn,
+ SilcBuffer key_payload,
+ SilcChannelEntry channel)
{
unsigned char *id_string, *key, *cipher;
unsigned int tmp_len;
- SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcChannelID *id;
SilcIDCacheEntry id_cache = NULL;
- SilcChannelEntry channel;
SilcChannelKeyPayload payload;
- SILC_LOG_DEBUG(("Received key for channel"));
-
- payload = silc_channel_key_payload_parse(packet);
+ payload = silc_channel_key_payload_parse(key_payload);
if (!payload)
return;
silc_channel_key_payload_free(payload);
return;
}
- id = silc_id_payload_parse_id(id_string, tmp_len);
+
+ id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
+ if (!id) {
+ silc_channel_key_payload_free(payload);
+ return;
+ }
/* Find channel. */
- if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
- SILC_ID_CHANNEL, &id_cache))
- goto out;
+ if (!channel) {
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
+ SILC_ID_CHANNEL, &id_cache))
+ goto out;
+ /* Get channel entry */
+ channel = (SilcChannelEntry)id_cache->context;
+ }
+
/* Save the key */
key = silc_channel_key_get_key(payload, &tmp_len);
cipher = silc_channel_key_get_cipher(payload, NULL);
-
- channel = (SilcChannelEntry)id_cache->context;
channel->key_len = tmp_len;
channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
memcpy(channel->key, key, tmp_len);
if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
- client->ops->say(client, conn,
+ conn->client->ops->say(conn->client, conn,
"Cannot talk to channel: unsupported cipher %s", cipher);
goto out;
}
silc_channel_key_payload_free(payload);
}
+/* Processes received key for channel. The received key will be used
+ to protect the traffic on the channel for now on. Client must receive
+ the key to the channel before talking on the channel is possible.
+ This is the key that server has generated, this is not the channel
+ private key, it is entirely local setting. */
+
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet)
+{
+ SILC_LOG_DEBUG(("Received key for channel"));
+
+ /* Save the key */
+ silc_client_save_channel_key(sock->user_data, packet, NULL);
+}
+
/* Process received message to a channel (or from a channel, really). This
decrypts the channel message with channel specific key and parses the
channel payload. Finally it displays the message on the screen. */
SilcChannelPayload payload = NULL;
SilcChannelID *id = NULL;
SilcChannelEntry channel;
+ SilcChannelUser chu;
SilcIDCacheEntry id_cache = NULL;
SilcClientID *client_id = NULL;
- int i;
char *nickname;
/* Sanity checks */
if (packet->dst_id_type != SILC_ID_CHANNEL)
goto out;
- client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
- id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!client_id)
+ goto out;
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
+ if (!id)
+ goto out;
/* Find the channel entry from channels on this connection */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
/* Find nickname */
nickname = "[unknown]";
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client &&
- !SILC_ID_CLIENT_COMPARE(channel->clients[i].client->id, client_id))
- nickname = channel->clients[i].client->nickname;
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
+ nickname = chu->client->nickname;
+ break;
+ }
}
/* Pass the message to application */
SilcBuffer buffer = packet->buffer;
unsigned short nick_len;
unsigned char *nickname, *message;
+ int ret;
/* Get nickname */
- silc_buffer_unformat(buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
- SILC_STR_END);
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+ SILC_STR_END);
+ if (ret == -1)
+ return;
+
silc_buffer_pull(buffer, 2 + nick_len);
-
+
message = silc_calloc(buffer->len + 1, sizeof(char));
memcpy(message, buffer->data, buffer->len);
if (packet->src_id_type != SILC_ID_CLIENT)
goto out;
- remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
if (!remote_id)
goto out;
SilcIDCacheEntry id_cache;
SilcIDCacheList list;
SilcChannelEntry channel;
- int i;
+ SilcChannelUser chu;
if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
SILC_ID_CHANNEL, &list))
while (channel) {
/* Remove client from channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client == client_entry) {
- channel->clients[i].client = NULL;
- channel->clients_count--;
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ if (chu->client == client_entry) {
+ silc_list_del(channel->clients, chu);
+ silc_free(chu);
break;
}
}
SilcIDCacheEntry id_cache;
SilcIDCacheList list;
SilcChannelEntry channel;
- int i;
+ SilcChannelUser chu;
if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
SILC_ID_CHANNEL, &list))
while (channel) {
- /* Remove client from channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i].client == old) {
- channel->clients[i].client = new;
+ /* Replace client entry */
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ if (chu->client == old) {
+ chu->client = new;
break;
}
}