X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fpacket_send.c;h=c42daec9404c9e25f8d1fdb239c350b3c6278772;hp=550ec9c39bbb4f8a14cee3a2403efa1945469636;hb=e5d8d3db6caa344b3d419b884556c21b15e7d123;hpb=2ccba0fda23268cb45841b5984fc31b4287a3d4b diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 550ec9c3..c42daec9 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -31,7 +31,7 @@ int silc_server_packet_send_real(SilcServer server, SilcSocketConnection sock, - int force_send) + bool force_send) { int ret; @@ -44,6 +44,10 @@ int silc_server_packet_send_real(SilcServer server, if (SILC_SERVER_IS_REKEY(sock)) force_send = FALSE; + /* If outbound data is already pending do not force send */ + if (SILC_IS_OUTBUF_PENDING(sock)) + force_send = FALSE; + /* Send the packet */ ret = silc_packet_send(sock, force_send); if (ret != -2) @@ -75,10 +79,11 @@ void silc_server_packet_send(SilcServer server, SilcPacketFlags flags, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { void *dst_id = NULL; SilcIdType dst_id_type = SILC_ID_NONE; + SilcIDListData idata = (SilcIDListData)sock->user_data; if (!sock) return; @@ -87,6 +92,10 @@ void silc_server_packet_send(SilcServer server, if (SILC_IS_DISCONNECTING(sock)) return; + /* If entry is disabled do not sent anything. */ + if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED) + return; + /* Get data used in the packet sending, keys and stuff */ switch(sock->type) { case SILC_SOCKET_TYPE_CLIENT: @@ -125,10 +134,10 @@ void silc_server_packet_send_dest(SilcServer server, SilcIdType dst_id_type, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { SilcPacketContext packetdata; - SilcIDListData idata; + SilcIDListData idata = (SilcIDListData)sock->user_data; SilcCipher cipher = NULL; SilcHmac hmac = NULL; unsigned char *dst_id_data = NULL; @@ -138,10 +147,11 @@ void silc_server_packet_send_dest(SilcServer server, if (SILC_IS_DISCONNECTING(sock)) return; - SILC_LOG_DEBUG(("Sending packet, type %d", type)); + /* If entry is disabled do not sent anything. */ + if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED) + return; - /* Get data used in the packet sending, keys and stuff */ - idata = (SilcIDListData)sock->user_data; + SILC_LOG_DEBUG(("Sending packet, type %d", type)); if (dst_id) { dst_id_data = silc_id_id2str(dst_id, dst_id_type); @@ -218,7 +228,7 @@ void silc_server_packet_send_srcdest(SilcServer server, SilcIdType dst_id_type, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { SilcPacketContext packetdata; SilcIDListData idata; @@ -378,7 +388,7 @@ silc_server_packet_send_to_channel_real(SilcServer server, unsigned char *data, uint32 data_len, int channel_message, - int force_send) + bool force_send) { packet->truelen = data_len + SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len; @@ -394,7 +404,8 @@ silc_server_packet_send_to_channel_real(SilcServer server, packet->buffer = sock->outbuf; /* Put the data to buffer, assemble and encrypt the packet. The packet - is encrypted with normal session key shared with the client. */ + is encrypted with normal session key shared with the client, unless + the `channel_message' is TRUE. */ silc_buffer_put(sock->outbuf, data, data_len); silc_packet_assemble(packet); if (channel_message) @@ -424,10 +435,10 @@ void silc_server_packet_send_to_channel(SilcServer server, SilcSocketConnection sender, SilcChannelEntry channel, SilcPacketType type, - unsigned char route, + bool route, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { SilcSocketConnection sock = NULL; SilcPacketContext packetdata; @@ -439,8 +450,7 @@ void silc_server_packet_send_to_channel(SilcServer server, uint32 routed_count = 0; /* This doesn't send channel message packets */ - if (type == SILC_PACKET_CHANNEL_MESSAGE) - return; + assert(type != SILC_PACKET_CHANNEL_MESSAGE); SILC_LOG_DEBUG(("Sending packet to channel")); @@ -459,7 +469,7 @@ void silc_server_packet_send_to_channel(SilcServer server, /* If there are global users in the channel we will send the message first to our router for further routing. */ - if (route && server->server_type == SILC_SERVER && !server->standalone && + if (route && server->server_type != SILC_ROUTER && !server->standalone && channel->global_users) { SilcServerEntry router; @@ -554,7 +564,7 @@ void silc_server_packet_send_to_channel(SilcServer server, then we'll need to encrypt it with the channel key. This is called from the silc_server_packet_relay_to_channel. */ -static void +static bool silc_server_packet_relay_to_channel_encrypt(SilcServer server, SilcSocketConnection sock, SilcChannelEntry channel, @@ -572,7 +582,7 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server, channel->channel_key) { SilcBuffer chp; uint32 iv_len, i; - uint16 data_len, flags; + uint16 dlen, flags; iv_len = silc_cipher_get_block_len(channel->channel_key); if (channel->iv[0] == '\0') @@ -583,15 +593,22 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server, /* Encode new payload. This encrypts it also. */ SILC_GET16_MSB(flags, data); - SILC_GET16_MSB(data_len, data + 2); - chp = silc_channel_message_payload_encode(flags, data_len, - data + 4, + SILC_GET16_MSB(dlen, data + 2); + + if (dlen > data_len) { + SILC_LOG_WARNING(("Corrupted channel message, cannot relay it")); + return FALSE; + } + + chp = silc_channel_message_payload_encode(flags, dlen, data + 4, iv_len, channel->iv, channel->channel_key, channel->hmac); memcpy(data, chp->data, chp->len); silc_buffer_free(chp); } + + return TRUE; } /* This routine is explicitly used to relay messages to some channel. @@ -611,7 +628,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, void *sender_entry, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { bool found = FALSE; SilcSocketConnection sock = NULL; @@ -625,6 +642,15 @@ void silc_server_packet_relay_to_channel(SilcServer server, SILC_LOG_DEBUG(("Relaying packet to channel")); + /* This encrypts the packet, if needed. It will be encrypted if + it came from the router thus it needs to be encrypted with the + channel key. If the channel key does not exist, then we know we + don't have a single local user on the channel. */ + if (!silc_server_packet_relay_to_channel_encrypt(server, sender_sock, + channel, data, + data_len)) + return; + /* Set the packet context pointers. */ packetdata.flags = 0; packetdata.type = SILC_PACKET_CHANNEL_MESSAGE; @@ -638,17 +664,9 @@ void silc_server_packet_relay_to_channel(SilcServer server, packetdata.src_id_len + packetdata.dst_id_len)); - /* This encrypts the packet, if needed. It will be encrypted if - it came from the router thus it needs to be encrypted with the - channel key. If the channel key does not exist, then we know we - don't have a single local user on the channel. */ - silc_server_packet_relay_to_channel_encrypt(server, sender_sock, - channel, data, - data_len); - /* If there are global users in the channel we will send the message first to our router for further routing. */ - if (server->server_type == SILC_SERVER && !server->standalone && + if (server->server_type != SILC_ROUTER && !server->standalone && channel->global_users) { SilcServerEntry router; @@ -735,6 +753,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, channel keys are cell specific and we have different channel key than the remote router has. */ if (sock->type == SILC_SOCKET_TYPE_ROUTER) { + SILC_LOG_DEBUG(("Remote is router, encrypt with session key")); /* If private key mode is not set then decrypt the packet and re-encrypt it */ @@ -824,7 +843,7 @@ void silc_server_packet_send_local_channel(SilcServer server, SilcPacketFlags flags, unsigned char *data, uint32 data_len, - int force_send) + bool force_send) { SilcChannelClientEntry chl; SilcHashTableList htl; @@ -950,6 +969,14 @@ void silc_server_send_notify(SilcServer server, silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, packet->data, packet->len, FALSE); + + /* Send to backup routers if this is being broadcasted to primary + router. */ + if (server->router && server->router->connection && + sock == server->router->connection && broadcast) + silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0, + packet->data, packet->len, FALSE, TRUE); + silc_buffer_free(packet); va_end(ap); } @@ -1344,7 +1371,7 @@ void silc_server_send_notify_on_channels(SilcServer server, SilcBuffer packet; unsigned char *data; uint32 data_len; - int force_send = FALSE; + bool force_send = FALSE; va_list ap; SILC_LOG_DEBUG(("Start")); @@ -1487,6 +1514,14 @@ void silc_server_send_new_id(SilcServer server, silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, idp->data, idp->len, FALSE); + + /* Send to backup routers if this is being broadcasted to primary + router. */ + if (server->router && server->router->connection && + sock == server->router->connection && broadcast) + silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0, + idp->data, idp->len, FALSE, TRUE); + silc_buffer_free(idp); } @@ -1521,6 +1556,13 @@ void silc_server_send_new_channel(SilcServer server, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, packet->data, packet->len, FALSE); + /* Send to backup routers if this is being broadcasted to primary + router. */ + if (server->router && server->router->connection && + sock == server->router->connection && broadcast) + silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0, + packet->data, packet->len, FALSE, TRUE); + silc_free(cid); silc_buffer_free(packet); } @@ -1556,7 +1598,6 @@ void silc_server_send_channel_key(SilcServer server, chid, tmp_len, channel->channel_key->cipher->name, channel->key_len / 8, channel->key); - silc_server_packet_send_to_channel(server, sender, channel, SILC_PACKET_CHANNEL_KEY, route, packet->data, packet->len, FALSE); @@ -1602,7 +1643,7 @@ void silc_server_relay_packet(SilcServer server, SilcCipher cipher, SilcHmac hmac, SilcPacketContext *packet, - int force_send) + bool force_send) { silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len + packet->padlen); @@ -1640,3 +1681,25 @@ void silc_server_send_connection_auth_request(SilcServer server, 0, packet->data, packet->len, FALSE); silc_buffer_free(packet); } + +/* Purge the outgoing packet queue to the network if there is data. This + function can be used to empty the packet queue. It is guaranteed that + after this function returns the outgoing data queue is empty. */ + +void silc_server_packet_queue_purge(SilcServer server, + SilcSocketConnection sock) +{ + if (sock && SILC_IS_OUTBUF_PENDING(sock) && + (SILC_IS_DISCONNECTED(sock) == FALSE)) { + server->stat.packets_sent++; + + if (sock->outbuf->data - sock->outbuf->head) + silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head); + + silc_packet_send(sock, TRUE); + + SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock); + SILC_UNSET_OUTBUF_PENDING(sock); + silc_buffer_clear(sock->outbuf); + } +}