Fixed UMODE_CHANGE notify handling.
Fixed backup router issues after resuming protocol is completed.
Connections that were unconfigured in rehash are now closed
automatically.
+Mon Jun 24 17:47:52 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added functions silc_server_send_opers and
+ silc_server_send_opers_notify to send packets stricly
+ to operators. Added macro SILC_SERVER_SEND_OPERS macro
+ to send variable argument notify to operators.
+ Affected files silcd/packet_send.[ch] and silcd/server.h.
+
+ * Removed UMODE rights checking with UMODE_CHANGE notify.
+ Affected file silcd/packet_receive.c.
+
+ * Server/router operator now receives notify when network
+ switches to backup router and when it resumes the use of
+ primary router. Affected file silcd/server.c and
+ silcd/server_backup.c.
+
+ * Fixed the updating of client information after backup
+ resuming protocol is over; update all except local clients
+ to the new primary router. The affected file is
+ silcd/server_util.c.
+
+ * Added support for closing active connections in rehash
+ that were unconfigured by the user. Supports currently
+ closing server and router connections. Affected file
+ silcd/server.c.
+
Sun Jun 23 17:32:31 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
* Don't do SILC_STRING_LANGUAGE encoding if the outbuffer
cell use it. When primary goes down, also those that are
not using it (are not connected locally) are signoffed.
- o Configure use of backup router on normal server using HUP.
-
- o Configure use of backup router on router using HUP.
-
o Rewrite SILC_LOG_DEBUG's in silcd/server_backup.c.
o Testing
goto out;
SILC_GET32_MSB(mode, tmp);
- /* Check that mode changing is allowed. */
- if (!silc_server_check_umode_rights(server, client, mode)) {
- SILC_LOG_DEBUG(("UMODE change is not allowed"));
- goto out;
- }
-
/* Remove internal resumed flag if client is marked detached now */
if (mode & SILC_UMODE_DETACHED)
client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
silc_buffer_clear(sock->outbuf);
}
}
+
+/* Send packet to clients that are known to be operators. If server
+ is router and `route' is TRUE then the packet would go to all operators
+ in the SILC network. If `route' is FALSE then only local operators
+ (local for server and cell wide for router). If `local' is TRUE then
+ only locally connected operators receive the packet. If `local' is
+ TRUE then `route' is ignored. If server is normal server and `route'
+ is FALSE it is equivalent to `local' being TRUE. */
+
+void silc_server_send_opers(SilcServer server,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ bool route, bool local,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send)
+{
+ SilcIDCacheList list = NULL;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcClientEntry client = NULL;
+ SilcSocketConnection sock;
+ SilcServerEntry *routed = NULL;
+ SilcUInt32 routed_count = 0;
+ bool gone = FALSE;
+ int k;
+
+ SILC_LOG_DEBUG(("Sending %s packet to operators",
+ silc_get_packet_name(type)));
+
+ /* If local was requested send only locally connected operators. */
+ if (local || (server->server_type == SILC_SERVER && !route)) {
+ if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ client = (SilcClientEntry)id_cache->context;
+ if (!client->router && SILC_IS_LOCAL(client) &&
+ (client->mode & SILC_UMODE_SERVER_OPERATOR ||
+ client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+
+ /* Send the packet to locally connected operator */
+ silc_server_packet_send_dest(server, client->connection, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+ return;
+ }
+
+ if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ client = (SilcClientEntry)id_cache->context;
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+ goto next;
+
+ if (server->server_type != SILC_SERVER && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ goto next;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ goto next;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ goto next;
+ }
+
+ if (client->router || !client->connection)
+ goto next;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ next:
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+
+ if (!silc_idcache_get_all(server->global_list->clients, &list) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ client = (SilcClientEntry)id_cache->context;
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+ goto nextg;
+
+ if (server->server_type != SILC_SERVER && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ goto nextg;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ goto nextg;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ goto nextg;
+ }
+
+ if (client->router || !client->connection)
+ goto nextg;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ nextg:
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+ silc_free(routed);
+}
+
+/* Send a notify packet to operators */
+
+void silc_server_send_opers_notify(SilcServer server,
+ bool route,
+ bool local,
+ SilcNotifyType type,
+ SilcUInt32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0,
+ route, local, packet->data, packet->len,
+ FALSE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
SilcPacketContext *packet);
void silc_server_packet_send_clients(SilcServer server,
SilcHashTable clients,
- SilcPacketType type,
+ SilcPacketType type,
SilcPacketFlags flags,
bool route,
unsigned char *data,
SilcAuthMethod auth_meth);
void silc_server_packet_queue_purge(SilcServer server,
SilcSocketConnection sock);
+void silc_server_send_opers(SilcServer server,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ bool route, bool local,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send);
+void silc_server_send_opers_notify(SilcServer server,
+ bool route,
+ bool local,
+ SilcNotifyType type,
+ SilcUInt32 argc, ...);
#endif
#include "server_internal.h"
/* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
SILC_TASK_CALLBACK(silc_server_connect_router);
SILC_TASK_CALLBACK(silc_server_connect_to_router);
return FALSE;
}
+/* Task callback to close a socket connection after rehash */
+
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+{
+ SilcServer server = context;
+ SilcSocketConnection sock = server->sockets[fd];
+
+ if (!sock)
+ return;
+
+ SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+ 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")));
+ silc_schedule_task_del_by_context(server->schedule, sock);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ "This connection is removed from "
+ "configuration");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+}
+
/* This function basically reads the config file again and switches the config
object pointed by the server object. After that, we have to fix various
things such as the server_name and the listening ports.
silc_pkcs_private_key_set(server->pkcs, server->private_key);
}
+ /* Check for unconfigured server and router connections and close
+ connections that were unconfigured. */
+
+ if (server->config->routers) {
+ SilcServerConfigRouter *ptr;
+ SilcServerConfigRouter *newptr;
+ bool found;
+
+ for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+ found = FALSE;
+
+ /* 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 &&
+ newptr->initiator == ptr->initiator) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Remove this connection */
+ SilcSocketConnection sock;
+ sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+ ptr->host, ptr->port);
+ if (sock && !SILC_IS_LISTENER(sock))
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+ }
+ }
+
+ if (server->config->servers) {
+ SilcServerConfigServer *ptr;
+ SilcServerConfigServer *newptr;
+ bool found;
+
+ for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+ found = FALSE;
+
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+ if (!strcmp(newptr->host, ptr->host)) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Remove this connection */
+ SilcSocketConnection sock;
+ sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
+ ptr->host, 0);
+ if (sock && !SILC_IS_LISTENER(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,
if (server->server_type == SILC_SERVER)
silc_server_update_channels_by_server(server, user_data,
backup_router);
+
+ /* Send notify about primary router going down to local operators */
+ if (server->backup_router)
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_NONE,
+ ("%s switched to backup router %s "
+ "(we are primary router now)",
+ server->server_name, server->server_name));
+ else
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_NONE,
+ ("%s switched to backup router %s",
+ server->server_name,
+ server->router->server_name));
}
/* Free the server entry */
silc_server_send_notify(server, sock, FALSE, \
type, 1, __fmt__, strlen(__fmt__)); \
silc_free(__fmt__); \
-} while(0);
+} while(0)
+
+/* Send notify to operators */
+#define SILC_SERVER_SEND_OPERS(server, route, local, type, fmt) \
+do { \
+ char *__fmt__ = silc_format fmt; \
+ silc_server_send_opers_notify(server, route, local, \
+ type, 1, __fmt__, strlen(__fmt__)); \
+ silc_free(__fmt__); \
+} while(0)
/* Check whether rekey protocol is active */
#define SILC_SERVER_IS_REKEY(sock) \
router */
silc_server_update_servers_by_server(server, backup_router, router,
FALSE);
- silc_server_update_clients_by_server(server, backup_router,
- router, TRUE, FALSE);
+ silc_server_update_clients_by_server(server, NULL, router,
+ FALSE, FALSE);
if (server->server_type == SILC_SERVER)
silc_server_update_channels_by_server(server, backup_router, router);
silc_server_backup_replaced_del(server, backup_router);
silc_server_announce_channels(server, 0, router->connection);
}
+ /* Send notify about primary router going down to local operators */
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_NONE,
+ ("%s resumed the use of primary router %s",
+ server->server_name,
+ server->router->server_name));
+
/* Protocol has ended, call the final callback */
if (protocol->final_callback)
silc_protocol_execute_final(protocol, server->schedule);
be the new source. This function also removes the clients that are
*really* originated from `from' if `remove_from' is TRUE. These are
clients that the `from' owns, and not just clients that are behind
- the `from'. */
+ the `from'. If `from' is NULL then all non-local clients are switched
+ to `to'. */
void silc_server_update_clients_by_server(SilcServer server,
SilcServerEntry from,
SILC_LOG_DEBUG(("Client->router (global) %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
- if (client->router == from) {
- /* Skip clients that are *really* owned by the `from' */
- if (remove_from && SILC_ID_COMPARE(from->id, client->id,
- client->id->ip.data_len)) {
- SILC_LOG_DEBUG(("Found really owned client, skip it"));
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (resolve_real_server) {
- client->router =
- silc_server_update_clients_by_real_server(server, from, client,
- local, id_cache);
- if (!client->router)
+ if (from) {
+ if (client->router == from) {
+ /* Skip clients that are *really* owned by the `from' */
+ if (remove_from && SILC_ID_COMPARE(from->id, client->id,
+ client->id->ip.data_len)) {
+ SILC_LOG_DEBUG(("Found really owned client, skip it"));
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ if (resolve_real_server) {
+ client->router =
+ silc_server_update_clients_by_real_server(server, from, client,
+ local, id_cache);
+ if (!client->router)
+ client->router = to;
+ } else {
client->router = to;
- } else {
- client->router = to;
+ }
}
+ } else {
+ /* All are changed */
+ client->router = to;
}
if (!silc_idcache_list_next(list, &id_cache))
SILC_LOG_DEBUG(("Client->router (local) %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
- if (client->router == from) {
- /* Skip clients that are *really* owned by the `from' */
- if (remove_from && SILC_ID_COMPARE(from->id, client->id,
- client->id->ip.data_len)) {
- SILC_LOG_DEBUG(("Found really owned client, skip it"));
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (resolve_real_server) {
- client->router =
- silc_server_update_clients_by_real_server(server, from, client,
- local, id_cache);
- if (!client->router)
- client->router = from; /* on local list put old from */
- } else {
- client->router = to;
+ if (from) {
+ if (client->router == from) {
+ /* Skip clients that are *really* owned by the `from' */
+ if (remove_from && SILC_ID_COMPARE(from->id, client->id,
+ client->id->ip.data_len)) {
+ SILC_LOG_DEBUG(("Found really owned client, skip it"));
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ if (resolve_real_server) {
+ client->router =
+ silc_server_update_clients_by_real_server(server, from, client,
+ local, id_cache);
+ if (!client->router)
+ client->router = from; /* on local list put old from */
+ } else {
+ client->router = to;
+ }
}
+ } else {
+ /* All are changed */
+ client->router = to;
}
if (!silc_idcache_list_next(list, &id_cache))
return TRUE;
}
+
+/* Find active socket connection by the IP address and port indicated by
+ `ip' and `port', and socket connection type of `type'. */
+
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+ SilcSocketType type,
+ const char *ip, SilcUInt16 port)
+{
+ int i;
+
+ for (i = 0; i < server->config->param.connections_max; i++) {
+ if (!server->sockets[i])
+ continue;
+ if (!strcmp(server->sockets[i]->ip, ip) &&
+ (!port || server->sockets[i]->port == port) &&
+ server->sockets[i]->type == type)
+ return server->sockets[i];
+ }
+
+ return NULL;
+}
be the new source. This function also removes the clients that are
*really* originated from `from' if `remove_from' is TRUE. These are
clients that the `from' owns, and not just clients that are behind
- the `from'. */
+ the `from'. If `from' is NULL then all non-local clients are switched
+ to `to'. */
void silc_server_update_clients_by_server(SilcServer server,
SilcServerEntry from,
SilcServerEntry to,
SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
SilcSocketType type);
-/* Find number of sockets by IP address indicated by remote host, indicatd
+/* Find number of sockets by IP address indicated by remote host, indicated
by `ip' or `hostname', `port', and `type'. Returns 0 if socket connections
does not exist. If `ip' is provided then `hostname' is ignored. */
SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
SilcChannelClientEntry chl,
SilcUInt32 forced_mode);
+/* Find active socket connection by the IP address and port indicated by
+ `ip' and `port', and socket connection type of `type'. */
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+ SilcSocketType type,
+ const char *ip, SilcUInt16 port);
+
#endif /* SERVER_UTIL_H */