More client library rewrites (key agreement, plus other).
[silc.git] / lib / silcclient / client_connect.c
index 3b656229e65fcd605a7212c658314d9e089f304c..7c50d2b9e199b549364c65f9b6ef336e1fa16b2d 100644 (file)
 
 /************************** Types and definitions ***************************/
 
-/* Public key verification context */
-typedef struct {
-  SilcSKE ske;
-  SilcSKEVerifyCbCompletion completion;
-  void *completion_context;
-} *VerifyKeyContext;
-
-
 /************************ Static utility functions **************************/
 
 /* Callback called after connected to remote host */
@@ -42,6 +34,7 @@ static void silc_client_connect_callback(SilcNetStatus status,
   SilcClientConnection conn = silc_fsm_get_context(fsm);
   SilcClient client = conn->client;
 
+  conn->internal->op = NULL;
   if (conn->internal->verbose) {
     switch (status) {
     case SILC_NET_OK:
@@ -173,6 +166,7 @@ static void silc_client_ke_completion(SilcSKE ske,
   SilcCipher send_key, receive_key;
   SilcHmac hmac_send, hmac_receive;
 
+  conn->internal->op = NULL;
   if (status != SILC_SKE_STATUS_OK) {
     /* Key exchange failed */
     SILC_LOG_DEBUG(("Error during key exchange with %s: %s (%d)",
@@ -267,6 +261,22 @@ static void silc_client_connect_auth_completion(SilcConnAuth connauth,
   SILC_FSM_CALL_CONTINUE(fsm);
 }
 
+/* Connection timeout callback */
+
+SILC_TASK_CALLBACK(silc_client_connect_timeout)
+{
+  SilcClientConnection conn = context;
+  SilcClient client = conn->client;
+
+  SILC_LOG_DEBUG(("Connection timeout"));
+
+  conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_TIMEOUT, 0, NULL,
+                conn->callback_context);
+
+  silc_fsm_next(&conn->internal->event_thread, silc_client_st_connect_error);
+  silc_fsm_continue_sync(&conn->internal->event_thread);
+}
+
 /*************************** Connect remote host ****************************/
 
 /* Creates a connection to remote host */
@@ -282,6 +292,12 @@ SILC_FSM_STATE(silc_client_st_connect)
   /** Connect */
   silc_fsm_next(fsm, silc_client_st_connect_set_stream);
 
+  /* Add connection timeout */
+  if (conn->internal->params.timeout_secs)
+    silc_schedule_task_add_timeout(conn->internal->schedule,
+                                  silc_client_connect_timeout, conn,
+                                  conn->internal->params.timeout_secs, 0);
+
   if (conn->internal->params.udp) {
     SilcStream stream;
 
@@ -295,7 +311,9 @@ SILC_FSM_STATE(silc_client_st_connect)
     }
 
     /* Connect (UDP) */
-    stream = silc_net_udp_connect(conn->internal->params.local_ip,
+    stream = silc_net_udp_connect(conn->internal->params.bind_ip ?
+                                 conn->internal->params.bind_ip :
+                                 conn->internal->params.local_ip,
                                  conn->internal->params.local_port,
                                  conn->remote_host, conn->remote_port,
                                  conn->internal->schedule);
@@ -305,7 +323,8 @@ SILC_FSM_STATE(silc_client_st_connect)
                                               stream, fsm));
   } else {
     /* Connect (TCP) */
-    SILC_FSM_CALL(silc_net_tcp_connect(NULL, conn->remote_host,
+    SILC_FSM_CALL(conn->internal->op = silc_net_tcp_connect(
+                                      NULL, conn->remote_host,
                                       conn->remote_port,
                                       conn->internal->schedule,
                                       silc_client_connect_callback, fsm));
@@ -386,8 +405,9 @@ SILC_FSM_STATE(silc_client_st_connect_key_exchange)
     /** Run key exchange (TCP) */
     silc_fsm_next(fsm, silc_client_st_connect_auth);
 
-  SILC_FSM_CALL(silc_ske_initiator(conn->internal->ske, conn->stream,
-                                  &params, NULL));
+  SILC_FSM_CALL(conn->internal->op = silc_ske_initiator(conn->internal->ske,
+                                                       conn->stream,
+                                                       &params, NULL));
 }
 
 /* For UDP/IP connections, set up the UDP session after successful key
@@ -481,7 +501,8 @@ SILC_FSM_STATE(silc_client_st_connect_auth_start)
 
   /** Start connection authentication */
   silc_fsm_next(fsm, silc_client_st_connected);
-  SILC_FSM_CALL(silc_connauth_initiator(connauth, SILC_CONN_CLIENT,
+  SILC_FSM_CALL(conn->internal->op = silc_connauth_initiator(
+                                       connauth, SILC_CONN_CLIENT,
                                        conn->internal->params.auth_method,
                                        conn->internal->params.auth,
                                        conn->internal->params.auth_len,
@@ -515,6 +536,8 @@ SILC_FSM_STATE(silc_client_st_connected)
     return SILC_FSM_CONTINUE;
   }
 
+  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+
   /* Call connection callback */
   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
                 conn->callback_context);
@@ -526,9 +549,15 @@ SILC_FSM_STATE(silc_client_st_connected)
 
 SILC_FSM_STATE(silc_client_st_connect_error)
 {
+  SilcClientConnection conn = fsm_context;
+
+  /* Signal to close connection */
+  if (!conn->internal->disconnected) {
+    conn->internal->disconnected = TRUE;
+    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+  }
 
-  /* XXX */
-  /* Close connection */
+  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
 
   return SILC_FSM_FINISH;
 }