silcd: Added heartbeat support
[silc.git] / apps / silcd / server.c
index f2153b359b673b6591f7677635c21b7c00b107c7..a07dee24f6f77e6533149ffddaa5400b049edaad 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2008 Pekka Riikonen
+  Copyright (C) 1997 - 2009 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -196,25 +196,23 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
 
   SILC_LOG_DEBUG(("End of stream received, sock %p", stream));
 
-  if (!idata)
-    return;
-
   if (server->router_conn && server->router_conn->sock == stream &&
       !server->router && server->standalone) {
-    if (idata->sconn && idata->sconn->callback)
+    if (idata && idata->sconn && idata->sconn->callback)
       (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_create_connections(server);
     silc_server_free_sock_user_data(server, stream, NULL);
   } else {
     /* If backup disconnected then mark that resuming will not be allowed */
-     if (server->server_type == SILC_ROUTER && !server->backup_router &&
+     if (idata &&
+        server->server_type == SILC_ROUTER && !server->backup_router &&
          idata->conn_type == SILC_CONN_SERVER) {
       SilcServerEntry server_entry = (SilcServerEntry)idata;
       if (server_entry->server_type == SILC_BACKUP_ROUTER)
         server->backup_closed = TRUE;
     }
 
-    if (idata->sconn && idata->sconn->callback)
+    if (idata && idata->sconn && idata->sconn->callback)
       (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_free_sock_user_data(server, stream, NULL);
   }
@@ -241,8 +239,8 @@ SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
     silc_server_free_sock_user_data(server, stream, NULL);
   } else {
     /* If backup disconnected then mark that resuming will not be allowed */
-     if (server->server_type == SILC_ROUTER && !server->backup_router &&
-         idata->conn_type == SILC_CONN_SERVER) {
+    if (server->server_type == SILC_ROUTER && !server->backup_router &&
+        idata->conn_type == SILC_CONN_SERVER) {
       SilcServerEntry server_entry = (SilcServerEntry)idata;
       if (server_entry->server_type == SILC_BACKUP_ROUTER)
         server->backup_closed = TRUE;
@@ -318,9 +316,16 @@ static void silc_server_packet_parse_type(SilcServer server,
 {
   SilcPacketType type = packet->type;
   SilcIDListData idata = silc_packet_get_context(sock);
+#ifdef SILC_DEBUG
+  const char *ip;
+  SilcUInt16 port;
+
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, NULL, &ip, &port);
+#endif /* SILC_DEBUG */
 
-  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
-                 silc_get_packet_name(type), packet->flags));
+  SILC_LOG_DEBUG(("Received %s packet [flags %d] from %s:%d",
+                 silc_get_packet_name(type), packet->flags, ip, port));
 
   /* Parse the packet type */
   switch (type) {
@@ -526,7 +531,7 @@ static void silc_server_packet_parse_type(SilcServer server,
 
   case SILC_PACKET_KEY_AGREEMENT:
     /*
-     * Received heartbeat.
+     * Received key agreement.
      */
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
@@ -2620,6 +2625,8 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   /* Add connection to server->conns so that we know we have connection
      to this peer. */
   sconn = silc_calloc(1, sizeof(*sconn));
+  if (!sconn)
+    goto out;
   sconn->server = server;
   sconn->sock = sock;
   sconn->remote_host = strdup(hostname);
@@ -2642,6 +2649,14 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
                               param->qos_rate_limit, param->qos_bytes_limit,
                               param->qos_limit_sec, param->qos_limit_usec);
 
+  /* Perform heartbeat */
+  if (param->keepalive_secs) {
+    SILC_LOG_DEBUG(("Perform heartbeat every %d seconds",
+                   param->keepalive_secs));
+    silc_schedule_task_add_timeout(server->schedule, silc_server_do_heartbeat,
+                                  sock, param->keepalive_secs, 0);
+  }
+
   silc_server_config_unref(&entry->cconfig);
   silc_server_config_unref(&entry->sconfig);
   silc_server_config_unref(&entry->rconfig);
@@ -2886,6 +2901,15 @@ static void silc_server_accept_new_connection(SilcNetStatus status,
   entry->op = silc_ske_responder(ske, packet_stream, &params);
 }
 
+/* Perform heartbeat */
+
+SILC_TASK_CALLBACK(silc_server_do_heartbeat)
+{
+  SilcServer server = app_context;
+  SilcPacketStream sock = context;
+  silc_server_send_heartbeat(server, sock);
+}
+
 
 /********************************** Rekey ***********************************/
 
@@ -3013,6 +3037,10 @@ static void silc_server_rekey(SilcServer server, SilcPacketStream sock,
     silc_packet_free(packet);
     return;
   }
+  if (idata->conn_type == SILC_CONN_UNKNOWN) {
+    silc_packet_free(packet);
+    return;
+  }
 
   SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s], sock %p",
                  idata->sconn->remote_host, idata->sconn->remote_port,
@@ -3222,6 +3250,8 @@ void silc_server_free_sock_user_data(SilcServer server,
 
   silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_rekey,
                                sock);
+  silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_heartbeat,
+                               sock);
 
   /* Cancel active protocols */
   if (idata) {
@@ -3234,7 +3264,7 @@ void silc_server_free_sock_user_data(SilcServer server,
         ((SilcUnknownEntry)idata)->op) {
       SILC_LOG_DEBUG(("Abort active protocol"));
       silc_async_abort(((SilcUnknownEntry)idata)->op, NULL, NULL);
-      idata->sconn->op = NULL;
+      ((SilcUnknownEntry)idata)->op = NULL;
     }
   }
 
@@ -5045,6 +5075,10 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                     server->stat.clients + 1));
+      server->stat.clients++;
     }
 
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {