More client library rewrites (key agreement, plus other).
[silc.git] / lib / silcclient / client_register.c
index 5d12f79bfff7671e31f6122b1fbd4d4fa63d170f..b0ddc907d61b0eab2ebf1c6a2cfbe1c872dafaea 100644 (file)
@@ -36,9 +36,21 @@ typedef struct {
   SilcBool success;
 } *SilcClientResumeSession;
 
-
 /************************ Static utility functions **************************/
 
+/* Command callback.  Nothing interesting to do here. */
+
+static SilcBool
+silc_client_register_command_called(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcCommand command,
+                                   SilcStatus status,
+                                   SilcStatus error,
+                                   void *context,
+                                   va_list ap)
+{
+  return TRUE;
+}
 
 /****************************** NEW_ID packet *******************************/
 
@@ -60,6 +72,9 @@ SILC_FSM_STATE(silc_client_new_id)
                                silc_buffer_len(&packet->buffer), &id))
     goto out;
 
+  SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
+                                             SILC_ID_CLIENT)));
+
   /* Create local client entry */
   conn->local_entry = silc_client_add_client(client, conn,
                                             client->username,
@@ -74,8 +89,14 @@ SILC_FSM_STATE(silc_client_new_id)
   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
 
   /* Save cache entry */
-  silc_idcache_find_by_id_one(conn->internal->client_cache, conn->local_id,
-                             &conn->internal->local_entry);
+  silc_mutex_lock(conn->internal->lock);
+  if (!silc_idcache_find_by_id_one(conn->internal->client_cache,
+                                  conn->local_id,
+                                  &conn->internal->local_entry)) {
+    silc_mutex_unlock(conn->internal->lock);
+    goto out;
+  }
+  silc_mutex_unlock(conn->internal->lock);
 
   /* Save remote ID */
   if (packet->src_id_len) {
@@ -90,6 +111,10 @@ SILC_FSM_STATE(silc_client_new_id)
                             &conn->remote_id);
   }
 
+  /* Set IDs to the packet stream */
+  silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
+                     conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
+
   /* Signal connection that new ID was received so it can continue
      with the registering. */
   if (conn->internal->registering)
@@ -129,7 +154,8 @@ SILC_FSM_STATE(silc_client_st_register)
 
   /** Wait for new ID */
   conn->internal->registering = TRUE;
-  silc_fsm_next_later(fsm, silc_client_st_register_complete, 15, 0);
+  silc_fsm_next_later(fsm, silc_client_st_register_complete,
+                     conn->internal->retry_timer, 0);
   return SILC_FSM_WAIT;
 }
 
@@ -141,9 +167,21 @@ SILC_FSM_STATE(silc_client_st_register_complete)
   SilcClient client = conn->client;
 
   if (!conn->local_id) {
-    /** Timeout, ID not received */
-    conn->internal->registering = FALSE;
-    silc_fsm_next(fsm, silc_client_st_register_error);
+    if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
+      /** Timeout, ID not received */
+      conn->internal->registering = FALSE;
+      conn->internal->retry_count = 0;
+      conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
+      silc_fsm_next(fsm, silc_client_st_register_error);
+      return SILC_FSM_CONTINUE;
+    }
+
+    /** Resend registering packet */
+    silc_fsm_next(fsm, silc_client_st_register);
+    conn->internal->retry_timer = ((conn->internal->retry_timer *
+                                  SILC_CLIENT_RETRY_MUL) +
+                                  (silc_rng_get_rn16(client->rng) %
+                                   SILC_CLIENT_RETRY_RAND));
     return SILC_FSM_CONTINUE;
   }
 
@@ -151,21 +189,22 @@ SILC_FSM_STATE(silc_client_st_register_complete)
 
   /* Issue IDENTIFY command for itself to get resolved hostname
      correctly from server. */
-  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, NULL, NULL,
+  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+                          silc_client_register_command_called, NULL,
                           1, 5, silc_buffer_data(conn->internal->local_idp),
                           silc_buffer_len(conn->internal->local_idp));
 
-  /* Send NICK command if the nickname was set by the application (and is
-     not same as the username).  Send this with little timeout. */
+  /* Call NICK command if the nickname was set by the application (and is
+     not same as the username). */
   if (conn->internal->params.nickname &&
       !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
-    silc_client_command_send(client, conn, SILC_COMMAND_NICK, NULL, NULL,
-                            1, 1, conn->internal->params.nickname,
-                            strlen(conn->internal->params.nickname));
+    silc_client_command_call(client, conn, NULL,
+                            "NICK", conn->internal->params.nickname, NULL);
 
   /* Issue INFO command to fetch the real server name and server
      information and other stuff. */
-  silc_client_command_send(client, conn, SILC_COMMAND_INFO, NULL, NULL,
+  silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+                          silc_client_register_command_called, NULL,
                           1, 2, silc_buffer_data(conn->internal->remote_idp),
                           silc_buffer_len(conn->internal->remote_idp));
 
@@ -174,20 +213,32 @@ SILC_FSM_STATE(silc_client_st_register_complete)
                 conn->callback_context);
 
   conn->internal->registering = FALSE;
+  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+
   return SILC_FSM_FINISH;
 }
 
+/* Error registering to network */
+
 SILC_FSM_STATE(silc_client_st_register_error)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
 
-  /* XXX */
-  /* Close connection */
+  SILC_LOG_DEBUG(("Error registering to network"));
 
+  /* Signal to close connection */
+  if (!conn->internal->disconnected) {
+    conn->internal->disconnected = TRUE;
+    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+  }
+
+  /* Call connect callback */
   conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
                 conn->callback_context);
 
+  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+
   return SILC_FSM_FINISH;
 }