{
*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;
}
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);
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
}
return TRUE;
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 */
silc_pkcs_private_key_set(server->pkcs, server->private_key);
/* Initialize the scheduler */
- server->schedule = silc_schedule_init(server->config->param.connections_max);
+ server->schedule = silc_schedule_init(server->config->param.connections_max,
+ server);
if (!server->schedule)
goto err;
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);
/* Clients local list */
server->purge_i = purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->local_list->clients;
- purge->schedule = server->schedule;
purge->timeout = 600;
- silc_schedule_task_add(purge->schedule, 0,
- silc_idlist_purge,
+ silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
(void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Clients global list */
server->purge_g = purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->global_list->clients;
- purge->schedule = server->schedule;
purge->timeout = 300;
- silc_schedule_task_add(purge->schedule, 0,
- silc_idlist_purge,
+ silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
(void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* If we are normal server we'll retrieve network statisticial information
once in a while from the router. */
if (server->server_type == SILC_SERVER)
- silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+ silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
server, 10, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_LOW);
/* Check whether new config has this one too */
for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
- if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+ if (silc_string_compare(newptr->host, ptr->host) &&
+ newptr->port == ptr->port &&
newptr->initiator == ptr->initiator) {
found = TRUE;
break;
}
}
- if (!found) {
+ if (!found && ptr->host) {
/* Remove this connection */
SilcSocketConnection sock;
sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
/* Check whether new config has this one too */
for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
- if (!strcmp(newptr->host, ptr->host)) {
+ if (silc_string_compare(newptr->host, ptr->host)) {
found = TRUE;
break;
}
}
- if (!found) {
+ if (!found && ptr->host) {
/* Remove this connection */
SilcSocketConnection sock;
sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
}
}
+ if (server->config->clients) {
+ SilcServerConfigClient *ptr;
+ SilcServerConfigClient *newptr;
+ bool found;
+
+ for (ptr = server->config->clients; ptr; ptr = ptr->next) {
+ found = FALSE;
+
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
+ if (silc_string_compare(newptr->host, ptr->host)) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found && ptr->host) {
+ /* Remove this connection */
+ SilcSocketConnection sock;
+ sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT,
+ ptr->host, 0);
+ if (sock)
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+ }
+ }
+
/* Go through all configured routers after rehash */
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router,
SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
{
+ SilcServer server = app_context;
SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServer server = sconn->server;
SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
SilcServerConfigConnParams *param =
(conn->param ? conn->param : &server->config->param);
SILC_TASK_CALLBACK(silc_server_connect_router)
{
+ SilcServer server = app_context;
SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServer server = sconn->server;
SilcServerConfigRouter *rconn;
int sock;
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
- sconn->server = server;
sconn->remote_host = strdup(ptr->host);
sconn->remote_port = ptr->port;
sconn->backup = ptr->backup_router;
SilcSocketConnection sock = ctx->sock;
SilcServerEntry id_entry = NULL;
SilcBuffer packet;
- SilcServerHBContext hb_context;
unsigned char *id_string;
SilcUInt32 id_len;
SilcIDListData idata;
/* Perform keepalive. The `hb_context' will be freed automatically
when finally calling the silc_socket_free function. */
- hb_context = silc_calloc(1, sizeof(*hb_context));
- hb_context->server = server;
- silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context,
+ silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
silc_server_perform_heartbeat,
server->schedule);
/* Register re-key timeout */
idata->rekey->timeout = param->key_exchange_rekey;
- idata->rekey->context = (void *)server;
silc_schedule_task_add(server->schedule, sock->sock,
silc_server_rekey_callback,
(void *)sock, idata->rekey->timeout, 0,
/* 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 */
SilcServerConfigDeny *deny;
int port;
- context = (void *)server;
-
/* Check whether we could resolve both IP and FQDN. */
if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
server->config->require_reverse_lookup)) {
However, this doesn't set the scheduler for outgoing traffic, it
will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
later when outgoing data is available. */
+ context = (void *)server;
SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
(SilcServerConnAuthInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
SilcSocketConnection sock = ctx->sock;
- SilcServerHBContext hb_context;
SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
void *id_entry;
SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
/* Perform keepalive. The `hb_context' will be freed automatically
when finally calling the silc_socket_free function. */
- hb_context = silc_calloc(1, sizeof(*hb_context));
- hb_context->server = server;
- silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context,
+ silc_socket_set_heartbeat(sock, hearbeat_timeout, server,
silc_server_perform_heartbeat,
server->schedule);
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;
(sock->protocol && sock->protocol->protocol &&
(sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) {
- silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+ silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
parser_context);
/* Reprocess data since we'll return FALSE here. This is because
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;
}
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
/* Packets from servers are parsed immediately */
- silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+ silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
parser_context);
break;
default:
if (sock->protocol) {
SilcServerFailureContext f;
f = silc_calloc(1, sizeof(*f));
- f->server = server;
- f->sock = sock;
+ f->sock = silc_socket_dup(sock);
/* We will wait 5 seconds to process this failure packet */
silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_failure_callback, (void *)f, 5, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_server_failure_callback, (void *)f, 5, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
break;
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
- sconn->server = server;
sconn->remote_host = strdup(remote_host);
sconn->remote_port = port;
sconn->no_reconnect = TRUE;
char *cp;
int len;
- if (!sock)
+ if (!sock || SILC_IS_DISCONNECTED(sock))
return;
memset(buf, 0, sizeof(buf));
silc_server_close_connection(server, sock);
}
-typedef struct {
- SilcServer server;
- SilcClientEntry client;
-} *FreeClientInternal;
-
SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
{
- FreeClientInternal i = (FreeClientInternal)context;
+ SilcServer server = app_context;
+ SilcClientEntry client = context;
- assert(!silc_hash_table_count(i->client->channels));
+ assert(!silc_hash_table_count(client->channels));
- silc_idlist_del_data(i->client);
- silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
- silc_free(i);
+ silc_idlist_del_data(client);
+ silc_idcache_purge_by_context(server->local_list->clients, client);
}
/* Frees client data and notifies about client's signoff. */
{
SILC_LOG_DEBUG(("Freeing client data"));
-#if 1
- if (!client->router && !client->connection &&
- !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- SILC_LOG_ERROR(("****** freeing data for already unregistered client -s"));
- SILC_LOG_ERROR(("****** Contact Pekka"));
- SILC_LOG_ERROR(("****** freeing data for already unregistered client -e"));
- return;
- }
-#endif
-
/* If there is pending outgoing data for the client then purge it
to the network before removing the client entry. */
silc_server_packet_queue_purge(server, sock);
into history (for WHOWAS command) for 5 minutes, unless we're
shutting down server. */
if (!server->server_shutdown) {
- FreeClientInternal i = silc_calloc(1, sizeof(*i));
- i->server = server;
- i->client = client;
silc_schedule_task_add(server->schedule, 0,
silc_server_free_client_data_timeout,
- (void *)i, 300, 0,
+ client, 300, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
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
silc_server_remove_servers_by_server(server, user_data, TRUE);
/* Remove the clients that this server owns as they will become
- invalid now too. */
- silc_server_remove_clients_by_server(server, user_data,
- user_data, TRUE);
+ invalid now too. For backup router the server is actually
+ coming from the primary router, so mark that as the owner
+ of this entry. */
+ if (server->server_type == SILC_BACKUP_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER)
+ silc_server_remove_clients_by_server(server, server->router,
+ user_data, TRUE);
+ else
+ silc_server_remove_clients_by_server(server, user_data,
+ user_data, TRUE);
/* Remove channels owned by this server */
if (server->server_type == SILC_SERVER)
server->server_name,
server->router->server_name));
}
+ server->backup_noswitch = FALSE;
/* Free the server entry */
silc_server_backup_del(server, user_data);
}
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 */
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 */
SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
{
+ SilcServer server = app_context;
SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
- SilcServer server = (SilcServer)rekey->context;
rekey->task = NULL;
if (server->server_type == SILC_ROUTER) {
if (!channel->rekey)
channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
- channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
channel->rekey->key_len = key_len;
if (channel->rekey->task)
if (!channel) {
channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
if (!channel) {
- SILC_LOG_ERROR(("Received key for non-existent channel %s",
- silc_id_render(id, SILC_ID_CHANNEL)));
+ if (server->server_type == SILC_ROUTER)
+ SILC_LOG_ERROR(("Received key for non-existent channel %s",
+ silc_id_render(id, SILC_ID_CHANNEL)));
goto out;
}
}
if (server->server_type == SILC_ROUTER) {
if (!channel->rekey)
channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
- channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
if (channel->rekey->task)
silc_schedule_task_del(server->schedule, channel->rekey->task);
void silc_server_perform_heartbeat(SilcSocketConnection sock,
void *hb_context)
{
- SilcServerHBContext hb = (SilcServerHBContext)hb_context;
+ SilcServer server = hb_context;
SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname,
sock->port, sock->ip));
/* Send the heartbeat */
- silc_server_send_heartbeat(hb->server, sock);
+ silc_server_send_heartbeat(server, sock);
}
/* Returns assembled of all servers in the given ID list. The packet's
SILC_TASK_CALLBACK(silc_server_failure_callback)
{
+ SilcServer server = app_context;
SilcServerFailureContext f = (SilcServerFailureContext)context;
if (f->sock->protocol) {
f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
+ silc_protocol_execute(f->sock->protocol, server->schedule, 0, 0);
}
+ silc_socket_free(f->sock);
silc_free(f);
}
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)
{
+ SilcServer server = app_context;
SilcSocketConnection sock = (SilcSocketConnection)context;
SilcIDListData idata = (SilcIDListData)sock->user_data;
- SilcServer server = (SilcServer)idata->rekey->context;
SilcProtocol protocol;
SilcServerRekeyInternalContext *proto_ctx;