Fixed server/backup router reconnecting
[silc.git] / apps / silcd / server.c
index 5b88aa2819317a602529758c28d1df301daa3bc3..bb5b3b279e819a72d240fa388f5b8fb7610d0e0a 100644 (file)
@@ -1263,13 +1263,10 @@ SILC_TASK_CALLBACK(silc_server_purge_expired_clients)
 
   silc_dlist_start(server->expired_clients);
   while ((client = silc_dlist_get(server->expired_clients))) {
-    if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      continue;
-
     /* For unregistered clients the created timestamp is actually
        unregistered timestamp.  Make sure client remains in history
        at least 500 seconds. */
-    if (curtime - client->data.created < 500)
+    if (client->data.created && curtime - client->data.created < 500)
       continue;
 
     id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
@@ -1356,13 +1353,21 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
 
   if (success == FALSE) {
     /* Authentication failed */
-    /* XXX retry connecting */
 
-    silc_server_disconnect_remote(server, sconn->sock,
-                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
     return;
   }
 
@@ -1384,11 +1389,11 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
                                      strdup(sconn->remote_host),
                                      SILC_SERVER, NULL, NULL, sconn->sock);
     if (!id_entry) {
-      silc_server_disconnect_remote(server, sconn->sock,
-                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
       if (sconn->callback)
        (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_free_sock_user_data(server, sconn->sock, NULL);
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
       return;
     }
 
@@ -1413,11 +1418,11 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
                             SILC_STR_DATA(server->server_name,
                                           strlen(server->server_name)),
                             SILC_STR_END)) {
-      silc_server_disconnect_remote(server, sconn->sock,
-                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
       if (sconn->callback)
        (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_free_sock_user_data(server, sconn->sock, NULL);
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
       return;
     }
 
@@ -1451,11 +1456,20 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
                                                  SILC_ID_SERVER),
                                      NULL, sconn->sock);
     if (!id_entry) {
-      silc_server_disconnect_remote(server, sconn->sock,
-                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+      /* Try reconnecting if configuration wants it */
+      if (!sconn->no_reconnect) {
+        silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_connect_to_router_retry,
+                                      sconn, 1, 0);
+        silc_dlist_del(server->conns, sconn);
+        return;
+      }
+
       if (sconn->callback)
        (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_free_sock_user_data(server, sconn->sock, NULL);
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
       return;
     }
 
@@ -1509,19 +1523,20 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
          silc_server_backup_add(server, server->id_entry, ip,
                                 sconn->remote_port, TRUE);
        }
+      }
 #if 0
-      } else {
+         else {
        /* We already have primary router.  Disconnect this connection */
        SILC_LOG_DEBUG(("We already have primary router, disconnect"));
        silc_idlist_del_server(server->global_list, id_entry);
-       silc_server_disconnect_remote(server, sconn->sock,
-                                     SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
        if (sconn->callback)
          (*sconn->callback)(server, NULL, sconn->callback_context);
        silc_server_free_sock_user_data(server, sconn->sock, NULL);
+       silc_server_disconnect_remote(server, sconn->sock,
+                                     SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
        return;
-#endif /* 0 */
       }
+#endif /* 0 */
     } else {
       /* Add this server to be our backup router */
       id_entry->server_type = SILC_BACKUP_ROUTER;
@@ -1532,11 +1547,11 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
     break;
 
   default:
-    silc_server_disconnect_remote(server, sconn->sock,
-                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
     return;
   }
 
@@ -1595,14 +1610,22 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
     /* SKE failed */
     SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
                    silc_ske_map_status(status), entry->hostname, entry->ip));
-
-    /* XXX retry connecting */
     silc_ske_free(ske);
-    silc_server_disconnect_remote(server, sconn->sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     return;
   }
 
@@ -1611,16 +1634,23 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
   /* Set the keys into use.  The data will be encrypted after this. */
   if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
                         &hmac_send, &hmac_receive, &hash)) {
+    silc_ske_free(ske);
 
-    /* XXX retry connecting */
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
 
     /* Error setting keys */
-    silc_ske_free(ske);
-    silc_server_disconnect_remote(server, sconn->sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     return;
   }
   silc_packet_set_keys(sconn->sock, send_key, receive_key, hmac_send,
@@ -1631,15 +1661,23 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
   connauth = silc_connauth_alloc(server->schedule, ske,
                                 server->config->conn_auth_timeout);
   if (!connauth) {
-    /* XXX retry connecting */
+    silc_ske_free(ske);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
 
     /** Error allocating auth protocol */
-    silc_ske_free(ske);
-    silc_server_disconnect_remote(server, sconn->sock,
-                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
     return;
   }
 
@@ -1691,6 +1729,16 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   if (!sconn->sock) {
     SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
     silc_stream_destroy(sconn->stream);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
@@ -1702,6 +1750,16 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, server->id,
                           0, NULL)) {
     silc_packet_stream_destroy(sconn->sock);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
@@ -1712,6 +1770,18 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   entry = silc_calloc(1, sizeof(*entry));
   if (!entry) {
     silc_packet_stream_destroy(sconn->sock);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1735,6 +1805,16 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   if (!ske) {
     silc_free(entry);
     silc_packet_stream_destroy(sconn->sock);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
@@ -1779,7 +1859,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 
   /* If we've reached max retry count, give up. */
   if ((sconn->retry_count > param->reconnect_count) &&
-      !param->reconnect_keep_trying) {
+      sconn->no_reconnect) {
     SILC_LOG_ERROR(("Could not connect, giving up"));
 
     if (sconn->callback)
@@ -1826,10 +1906,16 @@ static void silc_server_connection_established(SilcNetStatus status,
     SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
                    sconn->remote_host, sconn->remote_port,
                    silc_net_get_error_string(status)));
-
-    if (sconn->callback)
-      (*sconn->callback)(server, NULL, sconn->callback_context);
-    silc_server_connection_free(sconn);
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(sconn->server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+    } else {
+      if (sconn->callback)
+       (*sconn->callback)(server, NULL, sconn->callback_context);
+      silc_server_connection_free(sconn);
+    }
     break;
 
   default:
@@ -1880,6 +1966,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
       SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
                     (sconn->backup ? "backup router" : "router"),
                     sconn->remote_host, sconn->remote_port));
+      if (sconn->callback)
+       (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_connection_free(sconn);
       return;
     }
@@ -1896,6 +1984,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   if (!sconn->op) {
     SILC_LOG_ERROR(("Could not connect to router %s:%d",
                    sconn->remote_host, sconn->remote_port));
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1914,6 +2004,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
   SilcServer server = context;
   SilcServerConnection sconn;
   SilcServerConfigRouter *ptr;
+  SilcServerConfigConnParams *param;
 
   /* Don't connect if we are shutting down. */
   if (server->server_shutdown)
@@ -1989,6 +2080,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       }
     }
 
+    param = (ptr->param ? ptr->param : &server->config->param);
+
     /* Allocate connection object for hold connection specific stuff. */
     sconn = silc_calloc(1, sizeof(*sconn));
     if (!sconn)
@@ -2001,6 +2094,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
       sconn->backup_replace_port = ptr->backup_replace_port;
     }
+    sconn->no_reconnect = param->reconnect_keep_trying == FALSE;
 
     SILC_LOG_DEBUG(("Created connection %p", sconn));
 
@@ -3036,6 +3130,7 @@ void silc_server_free_client_data(SilcServer server,
     client->router = NULL;
     client->connection = NULL;
     client->data.created = silc_time();
+    silc_dlist_del(server->expired_clients, client);
     silc_dlist_add(server->expired_clients, client);
   } else {
     /* Delete directly since we're shutting down server */
@@ -3155,7 +3250,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
            /* We'll need to constantly try to reconnect to the primary
               router so that we'll see when it comes back online. */
-           silc_server_create_connection(server, FALSE, FALSE, ip, port,
+           silc_server_create_connection(server, TRUE, FALSE, ip, port,
                                         silc_server_backup_connected,
                                         NULL);
          }
@@ -3300,6 +3395,12 @@ void silc_server_free_sock_user_data(SilcServer server,
       SILC_LOG_DEBUG(("Freeing unknown connection data %p", entry));
 
       if (idata->sconn) {
+       if (server->router_conn == idata->sconn) {
+         if (!server->no_reconnect)
+           silc_server_create_connections(server);
+         server->router_conn = NULL;
+       }
+
        silc_server_connection_free(idata->sconn);
        idata->sconn = NULL;
       }
@@ -3975,6 +4076,7 @@ static void silc_server_announce_get_servers(SilcServer server,
   SilcIDCacheEntry id_cache;
   SilcServerEntry entry;
   SilcBuffer idp;
+  void *tmp;
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->servers, &list)) {
@@ -3991,11 +4093,14 @@ static void silc_server_announce_get_servers(SilcServer server,
 
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
 
-      *servers = silc_buffer_realloc(*servers,
-                                    (*servers ?
-                                     silc_buffer_truelen((*servers)) +
-                                     silc_buffer_len(idp) :
-                                     silc_buffer_len(idp)));
+      tmp = silc_buffer_realloc(*servers,
+                               (*servers ?
+                                silc_buffer_truelen((*servers)) +
+                                silc_buffer_len(idp) :
+                                silc_buffer_len(idp)));
+      if (!tmp)
+       return;
+      *servers = tmp;
       silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
       silc_buffer_put(*servers, idp->data, silc_buffer_len(idp));
       silc_buffer_pull(*servers, silc_buffer_len(idp));
@@ -4069,6 +4174,7 @@ static void silc_server_announce_get_clients(SilcServer server,
   SilcBuffer idp;
   SilcBuffer tmp;
   unsigned char mode[4];
+  void *tmp2;
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->clients, &list)) {
@@ -4087,12 +4193,17 @@ static void silc_server_announce_get_clients(SilcServer server,
                      silc_id_render(client->id, SILC_ID_CLIENT)));
 
       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+      if (!idp)
+       return;
 
-      *clients = silc_buffer_realloc(*clients,
-                                    (*clients ?
-                                     silc_buffer_truelen((*clients)) +
-                                     silc_buffer_len(idp) :
-                                     silc_buffer_len(idp)));
+      tmp2 = silc_buffer_realloc(*clients,
+                               (*clients ?
+                                silc_buffer_truelen((*clients)) +
+                                silc_buffer_len(idp) :
+                                silc_buffer_len(idp)));
+      if (!tmp2)
+       return;
+      *clients = tmp2;
       silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
       silc_buffer_put(*clients, idp->data, silc_buffer_len(idp));
       silc_buffer_pull(*clients, silc_buffer_len(idp));
@@ -4102,11 +4213,14 @@ static void silc_server_announce_get_clients(SilcServer server,
        silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
                                           2, idp->data, silc_buffer_len(idp),
                                           mode, 4);
-      *umodes = silc_buffer_realloc(*umodes,
-                                   (*umodes ?
-                                    silc_buffer_truelen((*umodes)) +
-                                    silc_buffer_len(tmp) :
-                                    silc_buffer_len(tmp)));
+      tmp2 = silc_buffer_realloc(*umodes,
+                                (*umodes ?
+                                 silc_buffer_truelen((*umodes)) +
+                                 silc_buffer_len(tmp) :
+                                 silc_buffer_len(tmp)));
+      if (!tmp2)
+       return;
+      *umodes = tmp2;
       silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
       silc_buffer_put(*umodes, tmp->data, silc_buffer_len(tmp));
       silc_buffer_pull(*umodes, silc_buffer_len(tmp));
@@ -4262,6 +4376,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
   int len;
   unsigned char mode[4], ulimit[4];
   char *hmac;
+  void *tmp2;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -4298,10 +4413,13 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                        SILC_CHANNEL_MODE_ULIMIT ?
                                        sizeof(ulimit) : 0));
   len = silc_buffer_len(tmp);
-  *channel_modes =
+  tmp2 =
     silc_buffer_realloc(*channel_modes,
                        (*channel_modes ?
                         silc_buffer_truelen((*channel_modes)) + len : len));
+  if (!tmp2)
+    return;
+  *channel_modes = tmp2;
   silc_buffer_pull_tail(*channel_modes,
                        ((*channel_modes)->end -
                         (*channel_modes)->data));
@@ -4326,10 +4444,13 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                             chidp->data,
                                             silc_buffer_len(chidp));
     len = silc_buffer_len(tmp);
-    *channel_users =
+    tmp2 =
       silc_buffer_realloc(*channel_users,
                          (*channel_users ?
                           silc_buffer_truelen((*channel_users)) + len : len));
+    if (!tmp2)
+      return;
+    *channel_users = tmp2;
     silc_buffer_pull_tail(*channel_users,
                          ((*channel_users)->end -
                           (*channel_users)->data));
@@ -4351,11 +4472,14 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                             fkey ? fkey->data : NULL,
                                             fkey ? silc_buffer_len(fkey) : 0);
     len = silc_buffer_len(tmp);
-    *channel_users_modes =
+    tmp2 =
       silc_buffer_realloc(*channel_users_modes,
                          (*channel_users_modes ?
                           silc_buffer_truelen((*channel_users_modes)) +
                           len : len));
+    if (!tmp2)
+      return;
+    *channel_users_modes = tmp2;
     silc_buffer_pull_tail(*channel_users_modes,
                          ((*channel_users_modes)->end -
                           (*channel_users_modes)->data));
@@ -4397,6 +4521,7 @@ void silc_server_announce_get_channels(SilcServer server,
   SilcUInt16 name_len;
   int len;
   int i = *channel_users_modes_c;
+  void *tmp;
   SilcBool announce;
 
   SILC_LOG_DEBUG(("Start"));
@@ -4420,11 +4545,15 @@ void silc_server_announce_get_channels(SilcServer server,
 
       if (announce) {
        len = 4 + name_len + id_len + 4;
-       *channels =
+       tmp =
          silc_buffer_realloc(*channels,
                              (*channels ?
                               silc_buffer_truelen((*channels)) +
                               len : len));
+       if (!tmp)
+         break;
+       *channels = tmp;
+
        silc_buffer_pull_tail(*channels,
                              ((*channels)->end - (*channels)->data));
        silc_buffer_format(*channels,
@@ -4445,15 +4574,23 @@ void silc_server_announce_get_channels(SilcServer server,
 
       if (announce) {
        /* Channel user modes */
-       *channel_users_modes = silc_realloc(*channel_users_modes,
-                                           sizeof(**channel_users_modes) *
-                                           (i + 1));
+       tmp = silc_realloc(*channel_users_modes,
+                           sizeof(**channel_users_modes) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_users_modes = tmp;
        (*channel_users_modes)[i] = NULL;
-       *channel_modes = silc_realloc(*channel_modes,
-                                     sizeof(**channel_modes) * (i + 1));
+       tmp = silc_realloc(*channel_modes,
+                          sizeof(**channel_modes) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_modes = tmp;
        (*channel_modes)[i] = NULL;
-       *channel_ids = silc_realloc(*channel_ids,
-                                     sizeof(**channel_ids) * (i + 1));
+       tmp = silc_realloc(*channel_ids,
+                          sizeof(**channel_ids) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_ids = tmp;
        (*channel_ids)[i] = NULL;
        silc_server_announce_get_channel_users(server, channel,
                                               &(*channel_modes)[i],
@@ -4462,18 +4599,27 @@ void silc_server_announce_get_channels(SilcServer server,
        (*channel_ids)[i] = channel->id;
 
        /* Channel's topic */
-       *channel_topics = silc_realloc(*channel_topics,
-                                      sizeof(**channel_topics) * (i + 1));
+       tmp = silc_realloc(*channel_topics,
+                          sizeof(**channel_topics) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_topics = tmp;
        (*channel_topics)[i] = NULL;
        silc_server_announce_get_channel_topic(server, channel,
                                               &(*channel_topics)[i]);
 
        /* Channel's invite and ban list */
-       *channel_invites = silc_realloc(*channel_invites,
-                                       sizeof(**channel_invites) * (i + 1));
+       tmp = silc_realloc(*channel_invites,
+                          sizeof(**channel_invites) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_invites = tmp;
        (*channel_invites)[i] = NULL;
-       *channel_bans = silc_realloc(*channel_bans,
-                                    sizeof(**channel_bans) * (i + 1));
+       tmp = silc_realloc(*channel_bans,
+                          sizeof(**channel_bans) * (i + 1));
+       if (!tmp)
+         break;
+       *channel_bans = tmp;
        (*channel_bans)[i] = NULL;
        silc_server_announce_get_inviteban(server, channel,
                                           &(*channel_invites)[i],