SILC_TASK_CALLBACK(silc_server_timeout_remote);
SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
SILC_TASK_CALLBACK(silc_server_failure_callback);
-SILC_TASK_CALLBACK(silc_server_rekey_callback);
SILC_TASK_CALLBACK(silc_server_get_stats);
/* Allocates a new SILC server object. This has to be done before the server
#ifdef SILC_SIM
{
SilcSim sim;
-
+ silc_dlist_start(server->sim);
while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
silc_dlist_del(server->sim, sim);
+ silc_sim_close(sim);
silc_sim_free(sim);
}
silc_dlist_uninit(server->sim);
{
*sock = silc_net_create_server(port, server_ip);
if (*sock < 0) {
- SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
+ SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
server_ip, port));
return FALSE;
}
server->starttime = time(NULL);
/* Take config object for us */
- silc_server_config_ref(&server->config_ref, server->config,
+ silc_server_config_ref(&server->config_ref, server->config,
server->config);
/* Steal public and private key from the config object */
server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
/* Init watcher list */
- server->watcher_list =
+ server->watcher_list =
silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
NULL, NULL, TRUE);
/* If we are normal server we'll retrieve network statisticial information
once in a while from the router. */
- if (server->server_type == SILC_SERVER)
+ if (server->server_type != SILC_ROUTER)
silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
server, 10, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_LOW);
silc_server_connect_to_router_retry,
context, 0, 1, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
- else
+ else {
silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ }
return;
}
if (conn && conn->param)
param = conn->param;
- /* Perform keepalive. The `hb_context' will be freed automatically
- when finally calling the silc_socket_free function. */
+ /* Perform keepalive. */
silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
silc_server_perform_heartbeat,
server->schedule);
/* If we are backup router then this primary router is whom we are
backing up. */
if (server->server_type == SILC_BACKUP_ROUTER)
- silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE);
+ silc_server_backup_add(server, server->id_entry, sock->ip,
+ sconn->remote_port, TRUE);
}
} else {
/* Add this server to be our backup router */
SilcSocketConnection sock = ctx->sock;
SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
void *id_entry;
- SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
+ SilcServerConfigConnParams *param = &server->config->param;
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Get connection parameters */
if (conn->param) {
- if (conn->param->keepalive_secs)
- hearbeat_timeout = conn->param->keepalive_secs;
+ param = conn->param;
+
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
+
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
+ }
/* Check if to be anonymous connection */
- if (conn->param->anonymous)
+ if (param->anonymous)
client->mode |= SILC_UMODE_ANONYMOUS;
}
if (rconn) {
if (rconn->param) {
- if (rconn->param->keepalive_secs)
- hearbeat_timeout = rconn->param->keepalive_secs;
+ param = rconn->param;
+
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
+
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
+ }
}
initiator = rconn->initiator;
}
if (sconn) {
if (sconn->param) {
- if (sconn->param->keepalive_secs)
- hearbeat_timeout = sconn->param->keepalive_secs;
+ param = sconn->param;
+
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
+
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
+ }
}
backup_router = sconn->backup_router;
ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
new_server->server_type = SILC_BACKUP_ROUTER;
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+ ("Backup router %s is now online",
+ sock->hostname));
+
/* Remove the backup waiting with timeout */
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_router_wait,
/* Connection has been fully established now. Everything is ok. */
SILC_LOG_DEBUG(("New connection authenticated"));
- /* Perform keepalive. The `hb_context' will be freed automatically
- when finally calling the silc_socket_free function. */
- silc_socket_set_heartbeat(sock, hearbeat_timeout, server,
- silc_server_perform_heartbeat,
- server->schedule);
+ /* Perform keepalive. */
+ if (param->keepalive_secs)
+ silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+ silc_server_perform_heartbeat,
+ server->schedule);
+
+ /* Perform Quality of Service */
+ if (param->qos)
+ silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
+ param->qos_limit_sec, param->qos_limit_usec,
+ server->schedule);
out:
silc_schedule_task_del_by_callback(server->schedule,
if (ret == -2)
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
+ available for this connection it will be set for output as well.
+ This call clears the output setting and sets it only for input. */
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
+
if (ret == -1) {
SILC_LOG_ERROR(("Error sending packet to connection "
"%s:%d [%s]", sock->hostname, sock->port,
sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
"Router")));
- 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
- available for this connection it will be set for output as well.
- This call clears the output setting and sets it only for input. */
- SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
- SILC_UNSET_OUTBUF_PENDING(sock);
-
- silc_buffer_clear(sock->outbuf);
+ SILC_SET_DISCONNECTING(sock);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_close_connection(server, sock);
+ }
return;
}
ret = silc_packet_receive(sock);
if (ret < 0) {
- if (ret == -1)
+ if (ret == -1) {
SILC_LOG_ERROR(("Error receiving packet from connection "
"%s:%d [%s] %s", sock->hostname, sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
"Router"), strerror(errno)));
+
+ SILC_SET_DISCONNECTING(sock);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_close_connection(server, sock);
+ }
return;
}
TRUE : FALSE, cipher, hmac, sequence,
silc_server_packet_parse, server);
- /* If this socket connection is not authenticated yet and the packet
- processing failed we will drop the connection since it can be
- a malicious flooder. */
- if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE &&
- (!sock->protocol || sock->protocol->protocol->type ==
- SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) {
- SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock));
- SILC_SET_DISCONNECTING(sock);
+ /* If processing failed the connection is closed. */
+ if (!ret) {
+ /* On packet processing errors we may close our primary router
+ connection but won't become primary router if we are the backup
+ since this is local error condition. */
+ if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
+ server->backup_noswitch = TRUE;
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
SilcServer server = (SilcServer)context;
SilcSocketConnection sock = parser_context->sock;
SilcIDListData idata = (SilcIDListData)sock->user_data;
+ bool ret;
if (idata)
idata->psn_receive = parser_context->packet->sequence + 1;
the idata->receive_key might have become valid in the last packet
and we want to call this processor with valid cipher. */
if (idata)
- silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ ret = silc_packet_receive_process(
+ sock, server->server_type == SILC_ROUTER ?
TRUE : FALSE, idata->receive_key,
idata->hmac_receive, idata->psn_receive,
silc_server_packet_parse, server);
else
- silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ ret = silc_packet_receive_process(
+ sock, server->server_type == SILC_ROUTER ?
TRUE : FALSE, NULL, NULL, 0,
silc_server_packet_parse, server);
+
+ if (!ret) {
+ /* On packet processing errors we may close our primary router
+ connection but won't become primary router if we are the backup
+ since this is local error condition. */
+ if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
+ server->backup_noswitch = TRUE;
+
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_close_connection(server, sock);
+ }
+
return FALSE;
}
char *cp;
int len;
- if (!sock)
+ if (!sock || SILC_IS_DISCONNECTED(sock))
return;
memset(buf, 0, sizeof(buf));
/* Remove client from all channels */
if (notify)
silc_server_remove_from_channels(server, NULL, client,
- TRUE, (char *)signoff, TRUE);
+ TRUE, (char *)signoff, TRUE, FALSE);
else
silc_server_remove_from_channels(server, NULL, client,
- FALSE, NULL, FALSE);
+ FALSE, NULL, FALSE, FALSE);
/* Remove this client from watcher list if it is */
silc_server_del_from_watcher_list(server, client);
sock->type != SILC_SOCKET_TYPE_ROUTER)
backup_router = NULL;
- if (server->server_shutdown)
+ if (server->server_shutdown || server->backup_noswitch)
backup_router = NULL;
/* If this was our primary router connection then we're lost to
} else if (backup_router) {
SILC_LOG_INFO(("Enabling the use of backup router %s",
backup_router->server_name));
- SILC_LOG_DEBUG(("Enabling the use of backup router %s",
- backup_router->server_name));
/* Mark this connection as replaced */
silc_server_backup_replaced_add(server, user_data->id,
backup_router);
+ } else if (server->server_type == SILC_SERVER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ /* Reconnect to the router (backup) */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router,
+ server, 1, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
if (!backup_router) {
server->server_name,
server->router->server_name));
}
+ server->backup_noswitch = FALSE;
/* Free the server entry */
silc_server_backup_del(server, user_data);
SilcClientEntry client,
bool notify,
const char *signoff_message,
- bool keygen)
+ bool keygen,
+ bool killed)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
}
silc_hash_table_del(client->channels, channel);
- silc_hash_table_del(channel->user_list, chl->client);
+ silc_hash_table_del(channel->user_list, client);
channel->user_count--;
/* If there is no global users on the channel anymore mark the channel
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
+ memset(chl, 'A', sizeof(*chl));
silc_free(chl);
/* Update statistics */
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
+ if (killed && clidp) {
+ /* Remove the client from channel's invite list */
+ if (channel->invite_list &&
+ silc_hash_table_count(channel->invite_list)) {
+ SilcBuffer ab;
+ SilcArgumentPayload iargs;
+ ab = silc_argument_payload_encode_one(NULL, clidp->data,
+ clidp->len, 3);
+ iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+ silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
+ silc_buffer_free(ab);
+ silc_argument_payload_free(iargs);
+ }
+ }
+
/* Don't create keys if we are shutting down */
if (server->server_shutdown)
continue;
return FALSE;
}
- silc_hash_table_del(client->channels, chl->channel);
- silc_hash_table_del(channel->user_list, chl->client);
+ silc_hash_table_del(client->channels, channel);
+ silc_hash_table_del(channel->user_list, client);
channel->user_count--;
/* If there is no global users on the channel anymore mark the channel
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
+ memset(chl, 'O', sizeof(*chl));
silc_free(chl);
/* Update statistics */
return;
}
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
-
silc_server_disconnect_remote(server, sock,
protocol ==
SILC_PROTOCOL_SERVER_CONNECTION_AUTH ?
SILC_STATUS_ERR_AUTH_FAILED :
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
"Connection timeout");
+
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
}
/* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
SilcChannelClientEntry chl;
SilcHashTableList htl;
SilcBuffer chidp, clidp, csidp;
- SilcBuffer tmp;
+ SilcBuffer tmp, fkey = NULL;
int len;
- unsigned char mode[4], *fkey = NULL;
- SilcUInt32 fkey_len = 0;
+ unsigned char mode[4];
char *hmac;
SILC_LOG_DEBUG(("Start"));
SILC_PUT32_MSB(channel->mode, mode);
hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
if (channel->founder_key)
- fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+ fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
tmp =
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
6, csidp->data, csidp->len,
channel->passphrase,
channel->passphrase ?
strlen(channel->passphrase) : 0,
- fkey, fkey_len);
+ fkey ? fkey->data : NULL,
+ fkey ? fkey->len : 0);
len = tmp->len;
*channel_modes =
silc_buffer_realloc(*channel_modes,
silc_buffer_put(*channel_modes, tmp->data, tmp->len);
silc_buffer_pull(*channel_modes, len);
silc_buffer_free(tmp);
- silc_free(fkey);
+ silc_buffer_free(fkey);
fkey = NULL;
- fkey_len = 0;
/* Now find all users on the channel */
silc_hash_table_list(channel->user_list, &htl);
/* CUMODE notify for mode change on the channel */
SILC_PUT32_MSB(chl->mode, mode);
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key)
- fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+ fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
4, csidp->data, csidp->len,
mode, sizeof(mode),
clidp->data, clidp->len,
- fkey, fkey_len);
+ fkey ? fkey->data : NULL,
+ fkey ? fkey->len : 0);
len = tmp->len;
*channel_users_modes =
silc_buffer_realloc(*channel_users_modes,
silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
silc_buffer_pull(*channel_users_modes, len);
silc_buffer_free(tmp);
- silc_free(fkey);
+ silc_buffer_free(fkey);
fkey = NULL;
- fkey_len = 0;
silc_buffer_free(clidp);
}
silc_hash_table_list_reset(&htl);
silc_server_announce_get_channel_topic(server, channel,
&(*channel_topics)[i]);
(*channel_users_modes_c)++;
+
+ silc_free(cid);
+
i++;
}
return buffer;
}
-/* Finds client entry by Client ID and if it is not found then resolves
- it using WHOIS command. */
-
-SilcClientEntry silc_server_get_client_resolve(SilcServer server,
- SilcClientID *client_id,
- bool always_resolve,
- bool *resolved)
-{
- SilcClientEntry client;
-
- if (resolved)
- *resolved = FALSE;
-
- client = silc_idlist_find_client_by_id(server->local_list, client_id,
- TRUE, NULL);
- if (!client) {
- client = silc_idlist_find_client_by_id(server->global_list,
- client_id, TRUE, NULL);
- if (!client && server->server_type == SILC_ROUTER)
- return NULL;
- }
-
- if (!client && server->standalone)
- return NULL;
-
- if (!client || !client->nickname || !client->username ||
- always_resolve) {
- SilcBuffer buffer, idp;
-
- if (client) {
- client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
- client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
- client->resolve_cmd_ident = ++server->cmd_ident;
- }
-
- idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
- server->cmd_ident, 1,
- 4, idp->data, idp->len);
- silc_server_packet_send(server, client ? client->router->connection :
- SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_COMMAND, 0,
- buffer->data, buffer->len, FALSE);
- silc_buffer_free(idp);
- silc_buffer_free(buffer);
-
- if (resolved)
- *resolved = TRUE;
-
- return NULL;
- }
-
- return client;
-}
-
/* A timeout callback for the re-key. We will be the initiator of the
re-key protocol. */
-SILC_TASK_CALLBACK(silc_server_rekey_callback)
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
{
SilcServer server = app_context;
SilcSocketConnection sock = (SilcSocketConnection)context;