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"));
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)
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;
}
}
+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);