int silc_server_init(SilcServer server)
{
- int *sock = NULL, sock_count = 0, i;
+ int *sock = NULL, sock_count, i;
SilcServerID *id;
SilcServerEntry id_entry;
SilcIDListPurge purge;
tmp = silc_net_create_server(server->config->listen_port->port,
server->config->listen_port->listener_ip);
+
if (tmp < 0) {
SILC_LOG_ERROR(("Could not create server listener: %s on %d",
server->config->listen_port->listener_ip,
goto err0;
}
- sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+ sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1));
sock[sock_count] = tmp;
sock_count++;
listen = listen->next;
silc_net_set_socket_nonblock(sock[i]);
server->sock = sock[i];
+ /* 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[i], SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+ server->sockets[sock[i]] = newsocket;
+
+ /* Perform name and address lookups to resolve the listenning address
+ and port. */
+ if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname,
+ &newsocket->ip)) {
+ if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+ !newsocket->ip) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+ newsocket->hostname ? newsocket->hostname :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
+ goto err0;
+ }
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ }
+ newsocket->port = silc_net_get_local_port(sock[i]);
+
/* Create a Server ID for the server. */
- silc_id_create_server_id(sock[i], server->rng, &id);
- if (!id) {
+ silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+ if (!id)
goto err0;
- }
server->id = id;
server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
}
id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
- /* 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[i], SILC_SOCKET_TYPE_SERVER, id_entry,
- &newsocket);
-
- server->sockets[sock[i]] = newsocket;
-
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname,
- &newsocket->ip)) {
- if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
- newsocket->hostname ? newsocket->hostname :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err0;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock[i]);
-
/* Put the allocated socket pointer also to the entry allocated above
for fast back-referencing to the socket list. */
- id_entry->connection = (void *)server->sockets[sock[i]];
+ newsocket->user_data = (void *)id_entry;
+ id_entry->connection = (void *)newsocket;
server->id_entry = id_entry;
}
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,
- (void *)purge, 600, 0,
+ (void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Clients global list */
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,
- (void *)purge, 300, 0,
+ (void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
SILC_LOG_DEBUG(("Server initialized"));
if (sconn->retry_count > server->params->retry_count &&
server->params->retry_keep_trying == FALSE) {
SILC_LOG_ERROR(("Could not connect to router, giving up"));
+ silc_free(sconn->remote_host);
+ silc_free(sconn);
return;
}
sconn->backup_replace_port = ptr->backup_replace_port;
}
+ if (!server->router_conn && !sconn->backup)
+ server->router_conn = sconn;
+
silc_schedule_task_add(server->schedule, fd,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
silc_free(sconn->backup_replace_ip);
silc_free(sconn);
}
+ if (sconn == server->router_conn)
+ server->router_conn = NULL;
/* Free the protocol object */
if (sock->protocol == protocol)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
+ silc_free(ctx->auth_data);
silc_free(ctx);
}
and other information is created after we have received NEW_CLIENT
packet from client. */
client = silc_idlist_add_client(server->local_list,
- NULL, NULL, NULL, NULL, NULL, sock);
+ NULL, NULL, NULL, NULL, NULL, sock, 0);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to cache"));
silc_free(sock->user_data);
if (sock->user_data)
silc_server_free_sock_user_data(server, sock);
+ else if (server->router_conn && server->router_conn->sock == sock &&
+ !server->router && server->standalone)
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router,
+ server, 1, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
silc_server_close_connection(server, sock);
return;
}
if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
packet->dst_id_type == SILC_ID_SERVER &&
sock->type != SILC_SOCKET_TYPE_CLIENT &&
- memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+ memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
/* Route the packet to fastest route for the destination ID */
void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
/* Check whether we have a backup router connection */
if (!backup_router || backup_router == user_data) {
silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router,
+ silc_server_connect_to_router,
server, 1, 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
}
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key, newhmac);
+ NULL, key, newhmac, 0);
if (!entry) {
silc_free(channel_name);
silc_cipher_free(key);
/* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key, newhmac);
+ NULL, key, newhmac, 0);
if (!entry) {
silc_free(channel_name);
return NULL;
SILC_LOG_DEBUG(("Start"));
/* Decode channel key payload */
- payload = silc_channel_key_payload_parse(key_payload);
+ payload = silc_channel_key_payload_parse(key_payload->data,
+ key_payload->len);
if (!payload) {
SILC_LOG_ERROR(("Bad channel key payload, dropped"));
channel = NULL;
}
}
+static SilcBuffer
+silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer p;
+
+ va_start(ap, argc);
+ p = silc_notify_payload_encode(notify, argc, ap);
+ va_end(ap);
+
+ return p;
+}
+
/* This function is used by router to announce existing servers to our
primary router when we've connected to it. If `creation_time' is non-zero
then only the servers that has been created after the `creation_time'
static void silc_server_announce_get_clients(SilcServer server,
SilcIDList id_list,
SilcBuffer *clients,
+ SilcBuffer *umodes,
unsigned long creation_time)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
SilcClientEntry client;
SilcBuffer idp;
+ SilcBuffer tmp;
+ unsigned char mode[4];
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->clients, &list)) {
silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
silc_buffer_put(*clients, idp->data, idp->len);
silc_buffer_pull(*clients, idp->len);
+
+ SILC_PUT32_MSB(client->mode, mode);
+ tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+ 2, idp->data, idp->len,
+ mode, 4);
+ *umodes = silc_buffer_realloc(*umodes,
+ (*umodes ?
+ (*umodes)->truelen + tmp->len :
+ tmp->len));
+ silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+ silc_buffer_put(*umodes, tmp->data, tmp->len);
+ silc_buffer_pull(*umodes, tmp->len);
+ silc_buffer_free(tmp);
+
silc_buffer_free(idp);
if (!silc_idcache_list_next(list, &id_cache))
SilcSocketConnection remote)
{
SilcBuffer clients = NULL;
+ SilcBuffer umodes = NULL;
SILC_LOG_DEBUG(("Announcing clients"));
/* Get clients in local list */
silc_server_announce_get_clients(server, server->local_list,
- &clients, creation_time);
+ &clients, &umodes, creation_time);
/* As router we announce our global list as well */
if (server->server_type == SILC_ROUTER)
silc_server_announce_get_clients(server, server->global_list,
- &clients, creation_time);
+ &clients, &umodes, creation_time);
if (clients) {
silc_buffer_push(clients, clients->data - clients->head);
silc_buffer_free(clients);
}
+
+ if (umodes) {
+ silc_buffer_push(umodes, umodes->data - umodes->head);
+ SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+
+ /* Send the packet */
+ silc_server_packet_send(server, remote,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ umodes->data, umodes->len, TRUE);
+
+ silc_buffer_free(umodes);
+ }
}
-static SilcBuffer
-silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+/* Returns channel's topic for announcing it */
+
+void silc_server_announce_get_channel_topic(SilcServer server,
+ SilcChannelEntry channel,
+ SilcBuffer *topic)
{
- va_list ap;
- SilcBuffer p;
+ SilcBuffer chidp;
- va_start(ap, argc);
- p = silc_notify_payload_encode(notify, argc, ap);
- va_end(ap);
-
- return p;
+ if (channel->topic) {
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+ chidp->data, chidp->len,
+ channel->topic,
+ strlen(channel->topic));
+ silc_buffer_free(chidp);
+ }
}
/* Returns assembled packets for channel users of the `channel'. */
SilcBuffer *channel_users,
SilcBuffer **channel_users_modes,
uint32 *channel_users_modes_c,
+ SilcBuffer **channel_topics,
SilcChannelID ***channel_ids,
unsigned long creation_time)
{
silc_buffer_pull(*channels, len);
}
+ /* Channel user modes */
*channel_users_modes = silc_realloc(*channel_users_modes,
sizeof(**channel_users_modes) *
(i + 1));
channel_users,
&(*channel_users_modes)[i]);
(*channel_ids)[i] = channel->id;
+
+ /* Channel's topic */
+ *channel_topics = silc_realloc(*channel_topics,
+ sizeof(**channel_topics) * (i + 1));
+ (*channel_topics)[i] = NULL;
+ silc_server_announce_get_channel_topic(server, channel,
+ &(*channel_topics)[i]);
i++;
if (!silc_idcache_list_next(list, &id_cache))
{
SilcBuffer channels = NULL, channel_users = NULL;
SilcBuffer *channel_users_modes = NULL;
+ SilcBuffer *channel_topics = NULL;
uint32 channel_users_modes_c = 0;
SilcChannelID **channel_ids = NULL;
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
+ &channel_topics,
&channel_ids, creation_time);
/* Get channels and channel users in global list */
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
+ &channel_topics,
&channel_ids, creation_time);
if (channels) {
silc_buffer_free(channel_users_modes[i]);
}
silc_free(channel_users_modes);
- silc_free(channel_ids);
}
+
+ if (channel_topics) {
+ int i;
+
+ for (i = 0; i < channel_users_modes_c; i++) {
+ if (!channel_topics[i])
+ continue;
+
+ silc_buffer_push(channel_topics[i],
+ channel_topics[i]->data -
+ channel_topics[i]->head);
+ SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data,
+ channel_topics[i]->len);
+ silc_server_packet_send_dest(server, remote,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel_ids[i], SILC_ID_CHANNEL,
+ channel_topics[i]->data,
+ channel_topics[i]->len,
+ FALSE);
+ silc_buffer_free(channel_topics[i]);
+ }
+ silc_free(channel_topics);
+ }
+
+ silc_free(channel_ids);
}
/* Failure timeout callback. If this is called then we will immediately
uint32 user_count)
{
int i;
+ uint16 idp_len;
+ uint32 mode;
+ SilcClientID *client_id;
+ SilcClientEntry client;
+ SilcIDCacheEntry cache;
+ bool global;
for (i = 0; i < user_count; i++) {
- uint16 idp_len;
- uint32 mode;
- SilcClientID *client_id;
- SilcClientEntry client;
-
/* Client ID */
SILC_GET16_MSB(idp_len, user_list->data + 2);
idp_len += 4;
silc_free(client_id);
continue;
}
+
+ global = FALSE;
/* Check if we have this client cached already. */
client = silc_idlist_find_client_by_id(server->local_list, client_id,
- server->server_type, NULL);
- if (!client)
+ server->server_type, &cache);
+ if (!client) {
client = silc_idlist_find_client_by_id(server->global_list,
client_id, server->server_type,
- NULL);
+ &cache);
+ global = TRUE;
+ }
if (!client) {
/* If router did not find such Client ID in its lists then this must
be bogus client or some router in the net is buggy. */
global. */
client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
- sock->user_data, NULL);
+ sock->user_data, NULL, 0);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
silc_free(client_id);
}
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ } else {
+ /* Found, if it is from global list we'll assure that we won't
+ expire it now that the entry is on channel. */
+ if (global)
+ cache->expire = 0;
}
silc_free(client_id);