void silc_server_free(SilcServer server)
{
- if (server) {
+ if (!server)
+ return;
+
#ifdef SILC_SIM
+ {
SilcSim sim;
-
+
while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
silc_dlist_del(server->sim, sim);
silc_sim_free(sim);
}
silc_dlist_uninit(server->sim);
+ }
#endif
- silc_server_config_unref(&server->config_ref);
- if (server->rng)
- silc_rng_free(server->rng);
- if (server->pkcs)
- silc_pkcs_free(server->pkcs);
- if (server->public_key)
- silc_pkcs_public_key_free(server->public_key);
- if (server->private_key)
- silc_pkcs_private_key_free(server->private_key);
- if (server->pending_commands)
- silc_dlist_uninit(server->pending_commands);
- if (server->id_entry)
- silc_idlist_del_server(server->local_list, server->id_entry);
-
- silc_idcache_free(server->local_list->clients);
- silc_idcache_free(server->local_list->servers);
- silc_idcache_free(server->local_list->channels);
- silc_idcache_free(server->global_list->clients);
- silc_idcache_free(server->global_list->servers);
- silc_idcache_free(server->global_list->channels);
- silc_hash_table_free(server->watcher_list);
-
- silc_free(server->sockets);
- silc_free(server);
- }
+ silc_server_config_unref(&server->config_ref);
+ if (server->rng)
+ silc_rng_free(server->rng);
+ if (server->pkcs)
+ silc_pkcs_free(server->pkcs);
+ if (server->public_key)
+ silc_pkcs_public_key_free(server->public_key);
+ if (server->private_key)
+ silc_pkcs_private_key_free(server->private_key);
+ if (server->pending_commands)
+ silc_dlist_uninit(server->pending_commands);
+ if (server->id_entry)
+ silc_idlist_del_server(server->local_list, server->id_entry);
+
+ silc_idcache_free(server->local_list->clients);
+ silc_idcache_free(server->local_list->servers);
+ silc_idcache_free(server->local_list->channels);
+ silc_idcache_free(server->global_list->clients);
+ silc_idcache_free(server->global_list->servers);
+ silc_idcache_free(server->global_list->channels);
+ silc_hash_table_free(server->watcher_list);
+
+ silc_hash_free(server->md5hash);
+ silc_hash_free(server->sha1hash);
+ silc_hmac_unregister_all();
+ silc_hash_unregister_all();
+ silc_cipher_unregister_all();
+ silc_pkcs_unregister_all();
+
+ silc_free(server->local_list);
+ silc_free(server->global_list);
+ silc_free(server->server_name);
+ silc_free(server->id_string);
+ silc_free(server->purge_i);
+ silc_free(server->purge_g);
+ silc_free(server);
}
-/* Opens a listening port.
- XXX This function will become more general and will support multiple
- listening ports */
+/* Creates a new server listener. */
static bool silc_server_listen(SilcServer server, const char *server_ip,
- SilcUInt16 port, int *sock)
+ SilcUInt16 port, int *sock)
{
*sock = silc_net_create_server(port, server_ip);
if (*sock < 0) {
}
/* Adds a secondary listener. */
+
bool silc_server_init_secondary(SilcServer server)
{
- int sock=0, sock_list[server->config->param.connections_max];
+ int sock = 0, sock_list[server->config->param.connections_max];
SilcSocketConnection newsocket = NULL;
SilcServerConfigServerInfoInterface *interface;
for (interface = server->config->server_info->secondary; interface;
interface = interface->next, sock++) {
-
+
if (!silc_server_listen(server,
interface->server_ip, interface->port, &sock_list[sock]))
goto err;
/* Add ourselves also to the socket table. The entry allocated above
is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock_list[sock],
- SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+ silc_socket_alloc(sock_list[sock],
+ SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
server->sockets[sock_list[sock]] = newsocket;
+ SILC_SET_LISTENER(newsocket);
/* Perform name and address lookups to resolve the listenning address
and port. */
newsocket->hostname = strdup(newsocket->ip);
}
newsocket->port = silc_net_get_local_port(sock);
-
+
newsocket->user_data = (void *)server->id_entry;
silc_schedule_task_add(server->schedule, sock_list[sock],
silc_server_accept_new_connection,
(void *)server, 0, 0,
SILC_TASK_FD,
SILC_TASK_PRI_NORMAL);
-
}
return TRUE;
-
-err:
+ err:
do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
return FALSE;
-
}
/* Initializes the entire SILC server. This is called always before running
is sent as argument for fast referencing in the future. */
silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
server->sockets[sock] = newsocket;
+ SILC_SET_LISTENER(newsocket);
/* Perform name and address lookups to resolve the listenning address
and port. */
server->id = id;
server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
- server->id_type = SILC_ID_SERVER;
server->server_name = server->config->server_info->server_name;
server->config->server_info->server_name = NULL;
and removes the expired cache entries. */
/* Clients local list */
- purge = silc_calloc(1, sizeof(*purge));
+ server->purge_i = purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->local_list->clients;
purge->schedule = server->schedule;
purge->timeout = 600;
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Clients global list */
- purge = silc_calloc(1, sizeof(*purge));
+ server->purge_g = purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->global_list->clients;
purge->schedule = server->schedule;
purge->timeout = 300;
SILC_LOG_DEBUG(("Stopping server"));
if (server->schedule) {
+ int i;
+
+ /* Close all connections */
+ for (i = 0; i < server->config->param.connections_max; i++) {
+ if (!server->sockets[i])
+ continue;
+ if (!SILC_IS_LISTENER(server->sockets[i])) {
+ silc_schedule_task_del_by_context(server->schedule,
+ server->sockets[i]);
+ silc_server_disconnect_remote(server, server->sockets[i],
+ SILC_STATUS_OK,
+ "Server is shutting down");
+ } else {
+ silc_socket_free(server->sockets[i]);
+ server->sockets[i] = NULL;
+ }
+ }
+
+ /* We are not connected to network anymore */
+ server->standalone = TRUE;
+
silc_schedule_stop(server->schedule);
silc_schedule_uninit(server->schedule);
server->schedule = NULL;
+
+ silc_free(server->sockets);
+ server->sockets = NULL;
}
silc_server_protocols_unregister();
context = (void *)server;
- SILC_LOG_DEBUG(("Start"));
-
/* Check whether we could resolve both IP and FQDN. */
if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
server->config->require_reverse_lookup)) {
sock->ip));
/* Listenning port */
+ if (!server->sockets[(SilcUInt32)proto_ctx->context]) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT,
+ "Connection refused");
+ server->stat.conn_failures++;
+ silc_free(proto_ctx);
+ return;
+ }
port = server->sockets[(SilcUInt32)proto_ctx->context]->port;
/* Check whether this connection is denied to connect to us. */
initiator of the protocol thus we will wait for initiation from
there before we start the protocol. */
server->stat.auth_attempts++;
+ SILC_LOG_DEBUG(("Starting key exchange protocol"));
silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
&sock->protocol, proto_ctx,
silc_server_accept_new_connection_second);
if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
(protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
/* Error occured during protocol */
+ SILC_LOG_DEBUG(("Error key exchange protocol"));
silc_protocol_free(protocol);
sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
ctx->ske->prop->hmac,
ctx->ske->prop->group,
ctx->responder)) {
+ SILC_LOG_ERROR(("Error setting key material in use"));
silc_protocol_free(protocol);
sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
but we won't start it yet. We will be receiving party of this
protocol thus we will wait that connecting party will make
their first move. */
+ SILC_LOG_DEBUG(("Starting connection authentication protocol"));
silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
&sock->protocol, proto_ctx,
silc_server_accept_new_connection_final);
void *id_entry;
SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
- SILC_LOG_DEBUG(("Start"));
-
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);
sock->protocol = NULL;
if (ctx->packet)
if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
&server->config->param,
conn->param, ctx->ske)) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
+ sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ NULL);
server->stat.auth_failures++;
goto out;
}
&server->config->param,
rconn ? rconn->param : NULL,
ctx->ske)) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
+ sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ NULL);
server->stat.auth_failures++;
goto out;
}
&server->config->param,
sconn ? sconn->param : NULL,
ctx->ske)) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
+ sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ NULL);
server->stat.auth_failures++;
goto out;
}
SilcUInt32 sequence = 0;
int ret;
- if (!sock)
+ if (!sock) {
+ SILC_LOG_DEBUG(("Unknown socket connection"));
return;
-
- SILC_LOG_DEBUG(("Processing packet"));
+ }
/* Packet sending */
if (type == SILC_TASK_WRITE) {
/* Do not send data to disconnected connection */
- if (SILC_IS_DISCONNECTED(sock))
+ if (SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
return;
+ }
server->stat.packets_sent++;
SilcIDListData idata = (SilcIDListData)sock->user_data;
int ret;
- SILC_LOG_DEBUG(("Start"));
-
/* Parse the packet */
if (parse_ctx->normal)
ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
goto out;
}
- if (ret == SILC_PACKET_NONE)
+ if (ret == SILC_PACKET_NONE) {
+ SILC_LOG_DEBUG(("Error parsing packet"));
goto out;
+ }
/* Check that the the current client ID is same as in the client's packet. */
if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
packet->src_id_type);
if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
silc_free(id);
+ SILC_LOG_DEBUG(("Packet source is not same as sender"));
goto out;
}
silc_free(id);
SilcPacketType type = packet->type;
SilcIDListData idata = (SilcIDListData)sock->user_data;
- SILC_LOG_DEBUG(("Parsing packet type %d", type));
+ SILC_LOG_DEBUG(("Received %s packet [flags %d]",
+ silc_get_packet_name(type), packet->flags));
/* Parse the packet type */
switch (type) {
SilcStatus status;
char *message = NULL;
- SILC_LOG_DEBUG(("Disconnect packet"));
-
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
if (packet->buffer->len < 1)
status = (SilcStatus)packet->buffer->data[0];
if (packet->buffer->len > 1 &&
silc_utf8_valid(packet->buffer->data + 1, packet->buffer->len - 1))
- message = silc_memdup(packet->buffer->data, packet->buffer->len);
+ message = silc_memdup(packet->buffer->data + 1,
+ packet->buffer->len - 1);
SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s",
sock->ip, sock->hostname,
* one protocol for connection executing at once hence this
* success message is for whatever protocol is executing currently.
*/
- SILC_LOG_DEBUG(("Success packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
if (sock->protocol)
* one protocol for connection executing at once hence this
* failure message is for whatever protocol is executing currently.
*/
- SILC_LOG_DEBUG(("Failure packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
if (sock->protocol) {
break;
case SILC_PACKET_REJECT:
- SILC_LOG_DEBUG(("Reject packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
return;
* Received notify packet. Server can receive notify packets from
* router. Server then relays the notify messages to clients if needed.
*/
- SILC_LOG_DEBUG(("Notify packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
silc_server_notify_list(server, sock, packet);
else
* (although probably most common ones) thus they are handled
* specially.
*/
- SILC_LOG_DEBUG(("Channel Message packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
idata->last_receive = time(NULL);
* locally connected clients on the particular channel. Router
* never receives this channel and thus is ignored.
*/
- SILC_LOG_DEBUG(("Channel Key packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_channel_key(server, sock, packet);
* Recived command. Processes the command request and allocates the
* command context and calls the command.
*/
- SILC_LOG_DEBUG(("Command packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_command_process(server, sock, packet);
* may be reply to command sent by us or reply to command sent by client
* that we've routed further.
*/
- SILC_LOG_DEBUG(("Command Reply packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_command_reply(server, sock, packet);
* Received private message packet. The packet is coming from either
* client or server.
*/
- SILC_LOG_DEBUG(("Private Message packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
idata->last_receive = time(NULL);
* Key Exchange protocol packets
*/
case SILC_PACKET_KEY_EXCHANGE:
- SILC_LOG_DEBUG(("KE packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
break;
case SILC_PACKET_KEY_EXCHANGE_1:
- SILC_LOG_DEBUG(("KE 1 packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
break;
case SILC_PACKET_KEY_EXCHANGE_2:
- SILC_LOG_DEBUG(("KE 2 packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
* authentication method for the connection. This packet maybe received
* at any time.
*/
- SILC_LOG_DEBUG(("Connection authentication request packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_connection_auth_request(server, sock, packet);
case SILC_PACKET_CONNECTION_AUTH:
/* Start of the authentication protocol. We receive here the
authentication data and will verify it. */
- SILC_LOG_DEBUG(("Connection auth packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
* to distribute information about new registered entities in the
* SILC network.
*/
- SILC_LOG_DEBUG(("New ID packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
silc_server_new_id_list(server, sock, packet);
else
* we will use to create initial client ID. After creating new
* ID we will send it to the client.
*/
- SILC_LOG_DEBUG(("New Client packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_new_client(server, sock, packet);
* information that we may save. This is received after server has
* connected to us.
*/
- SILC_LOG_DEBUG(("New Server packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_new_server(server, sock, packet);
* Received new channel packet. Information about new channel in the
* network are distributed using this packet.
*/
- SILC_LOG_DEBUG(("New Channel packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
silc_server_new_channel_list(server, sock, packet);
else
/*
* Received heartbeat.
*/
- SILC_LOG_DEBUG(("Heartbeat packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
break;
/*
* Received heartbeat.
*/
- SILC_LOG_DEBUG(("Key agreement packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_key_agreement(server, sock, packet);
* Received re-key packet. The sender wants to regenerate the session
* keys.
*/
- SILC_LOG_DEBUG(("Re-key packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_rekey(server, sock, packet);
/*
* The re-key is done.
*/
- SILC_LOG_DEBUG(("Re-key done packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
case SILC_PACKET_FTP:
/* FTP packet */
- SILC_LOG_DEBUG(("FTP packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_ftp(server, sock, packet);
case SILC_PACKET_RESUME_CLIENT:
/* Resume client */
- SILC_LOG_DEBUG(("Resume Client packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_resume_client(server, sock, packet);
case SILC_PACKET_RESUME_ROUTER:
/* Resume router packet received. This packet is received for backup
router resuming protocol. */
- SILC_LOG_DEBUG(("Resume router packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
silc_server_backup_resume_router(server, sock, packet);
SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
break;
}
-
}
/* Creates connection to a remote router. */
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
- if (!server->sockets[sock->sock])
+ if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
+ silc_socket_free(sock);
return;
+ }
SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
sock->port,
channel->global_users = FALSE;
silc_free(chl);
- server->stat.my_chanclients--;
+
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_chanclients--;
+ if (server->server_type == SILC_ROUTER) {
+ server->stat.cell_chanclients--;
+ server->stat.chanclients--;
+ }
/* If there is not at least one local user on the channel then we don't
need the channel entry anymore, we can remove it safely, unless the
channel->global_users = FALSE;
silc_free(chl);
- server->stat.my_chanclients--;
+
+ /* Update statistics */
+ if (client->connection)
+ server->stat.my_chanclients--;
+ if (server->server_type == SILC_ROUTER) {
+ server->stat.cell_chanclients--;
+ server->stat.chanclients--;
+ }
clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
if (!clidp)
}
server->stat.my_channels++;
-
- if (server->server_type == SILC_ROUTER)
+ if (server->server_type == SILC_ROUTER) {
+ server->stat.channels++;
+ server->stat.cell_channels++;
entry->users_resolved = TRUE;
+ }
return entry;
}
}
server->stat.my_channels++;
-
- if (server->server_type == SILC_ROUTER)
+ if (server->server_type == SILC_ROUTER) {
+ server->stat.channels++;
+ server->stat.cell_channels++;
entry->users_resolved = TRUE;
+ }
return entry;
}