Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
protocol. */
silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
server->sockets[sock] = newsocket;
- newsocket->hostname = sconn->remote_host;
+ newsocket->hostname = strdup(sconn->remote_host);
newsocket->port = sconn->remote_port;
sconn->sock = newsocket;
SILC_LOG_DEBUG(("Accepting new connection"));
+ server->stat.conn_attempts++;
+
sock = silc_net_accept_connection(server->sock);
if (sock < 0) {
SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
+ server->stat.conn_failures++;
return;
}
/*silc_server_send_notify("Server is full, trying to redirect..."); */
} else {
SILC_LOG_ERROR(("Refusing connection, server is full"));
+ server->stat.conn_failures++;
}
return;
}
if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
!newsocket->ip) {
SILC_LOG_ERROR(("IP/DNS lookup failed"));
+ server->stat.conn_failures++;
return;
}
if (!newsocket->hostname)
protocol but will not start it yet. The connector will be the
initiator of the protocol thus we will wait for initiation from
there before we start the protocol. */
+ server->stat.auth_attempts++;
silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
&newsocket->protocol, proto_ctx,
silc_server_accept_new_connection_second);
sock->protocol = NULL;
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
+ server->stat.auth_failures++;
return;
}
sock->protocol = NULL;
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
+ server->stat.auth_failures++;
return;
}
break;
}
+ /* Statistics */
+ server->stat.my_clients++;
+ server->stat.clients++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients++;
+
id_entry = (void *)client;
break;
}
break;
}
+ /* Statistics */
+ if (sock->type == SILC_SOCKET_TYPE_SERVER)
+ server->stat.my_servers++;
+ else
+ server->stat.my_routers++;
+ server->stat.servers++;
+
id_entry = (void *)new_server;
/* There is connection to other server now, if it is router then
SilcHmac hmac = NULL;
int ret;
+ if (!sock)
+ return;
+
SILC_LOG_DEBUG(("Processing packet"));
/* Packet sending */
if (type == SILC_TASK_WRITE) {
+ server->stat.packets_sent++;
+
if (sock->outbuf->data - sock->outbuf->head)
silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
it later. */
if (ret == -2)
return;
+
+ if (ret == -1)
+ return;
/* The packet has been sent and now it is time to set the connection
back to only for input. When there is again some outgoing data
SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+ /* If the closed connection was our primary router connection the
+ start re-connecting phase. */
+ if (!server->standalone && server->server_type == SILC_SERVER &&
+ sock == server->router->connection)
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_connect_to_router,
+ context, 0, 500000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
if (sock->user_data)
silc_server_free_sock_user_data(server, sock);
silc_server_close_connection(server, sock);
return;
}
+ server->stat.packets_received++;
+
/* Get keys and stuff from ID entry */
idata = (SilcIDListData)sock->user_data;
if (idata) {
SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
/* Route the packet to fastest route for the destination ID */
- void *id = silc_id_str2id(packet->dst_id, packet->dst_id_type);
+ void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!id)
+ goto out;
silc_server_packet_route(server,
silc_server_route_get(server, id,
packet->dst_id_type),
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(server->timeout_queue, 0,
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(server->timeout_queue, 0,
silc_server_remove_channel_user(server, sock, packet);
break;
+ case SILC_PACKET_SET_MODE:
+ /*
+ * Received packet to set the mode of channel or client's channel mode.
+ */
+ SILC_LOG_DEBUG(("Set Mode packet"));
+ silc_server_set_mode(server, sock, packet);
+ break;
+
default:
SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
break;
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
-
SILC_LOG_DEBUG(("Closing connection %d", sock->sock));
/* We won't listen for this connection anymore */
va_list ap;
unsigned char buf[4096];
+ if (!sock)
+ return;
+
memset(buf, 0, sizeof(buf));
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
/* XXX must take some info to history before freeing */
/* Send REMOVE_ID packet to routers. */
- if (!server->standalone)
+ if (!server->standalone && server->router)
silc_server_send_remove_id(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, user_data->id,
/* Free the client entry and everything in it */
silc_idlist_del_data(user_data);
silc_idlist_del_client(server->local_list, user_data);
+ server->stat.my_clients--;
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
break;
}
case SILC_SOCKET_TYPE_SERVER:
SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
/* Send REMOVE_ID packet to routers. */
- silc_server_send_remove_id(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, user_data->id,
- SILC_ID_SERVER_LEN, SILC_ID_SERVER);
+ if (!server->standalone && server->router)
+ silc_server_send_remove_id(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, user_data->id,
+ SILC_ID_CLIENT_LEN, SILC_ID_CLIENT);
+
+ /* Free the server entry */
+ silc_idlist_del_data(user_data);
+ silc_idlist_del_server(server->local_list, user_data);
+ server->stat.my_servers--;
+ server->stat.servers--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_servers--;
break;
}
- break;
default:
{
SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
channel globally from SILC network, in this case we will
notify that this client has left the channel. */
if (channel->global_users)
- silc_server_send_notify_to_channel(server, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_SIGNOFF, 1,
clidp->data, clidp->len);
silc_idlist_del_channel(server->local_list, channel);
+ server->stat.my_channels--;
continue;
}
/* Remove from list */
silc_list_del(channel->user_list, chl);
silc_free(chl);
+ server->stat.my_chanclients--;
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
- silc_server_send_notify_to_channel(server, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_SIGNOFF, 1,
clidp->data, clidp->len);
silc_buffer_free(chidp);
if (silc_list_count(channel->user_list) < 2) {
/* Notify about leaving client if this channel has global users. */
if (notify && channel->global_users)
- silc_server_send_notify_to_channel(server, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
silc_idlist_del_channel(server->local_list, channel);
silc_buffer_free(clidp);
+ server->stat.my_channels--;
return FALSE;
}
/* Remove from list */
silc_list_del(channel->user_list, chl);
silc_free(chl);
+ server->stat.my_chanclients--;
/* If there is no global users on the channel anymore mark the channel
as local channel. */
!silc_server_channel_has_local(channel)) {
silc_idlist_del_channel(server->local_list, channel);
silc_buffer_free(clidp);
+ server->stat.my_channels--;
return FALSE;
}
/* Send notify to channel about client leaving the channel */
if (notify)
- silc_server_send_notify_to_channel(server, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
break;
SILC_TASK_CALLBACK(silc_server_timeout_remote)
{
- SilcServerConnection sconn = (SilcServerConnection)context;
- SilcSocketConnection sock = sconn->server->sockets[fd];
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection sock = server->sockets[fd];
- silc_server_disconnect_remote(sconn->server, sock,
+ if (!sock)
+ return;
+
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock);
+
+ silc_server_disconnect_remote(server, sock,
"Server closed connection: "
"Connection timeout");
}
channel_name, entry->id, SILC_ID_CHANNEL_LEN);
}
+ server->stat.my_channels++;
+
return entry;
}
/* Get channel ID */
tmp = silc_channel_key_get_id(payload, &tmp_len);
- id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+ id = silc_id_str2id(tmp, tmp_len, SILC_ID_CHANNEL);
if (!id) {
channel = NULL;
goto out;