Call the connection callback in disconnection always as the last
[silc.git] / lib / silcclient / client.c
index c7e4e6d8cacb1807739d68c48ed94231efdd3b22..f52ff134d72d7d6223284e02c7480d6aaa6a5f44 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 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
@@ -59,12 +59,11 @@ static void silc_client_connection_finished(SilcFSMThread fsm,
   /* Signal client that we have finished */
   silc_atomic_sub_int16(&client->internal->conns, 1);
   client->internal->connection_closed = TRUE;
-  SILC_FSM_SEMA_POST(&client->internal->wait_event);
+  SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
 
   silc_fsm_free(fsm);
 }
 
-
 /* Packet FSM thread destructor */
 
 static void silc_client_packet_destructor(SilcFSMThread thread,
@@ -101,7 +100,6 @@ static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
   case SILC_PACKET_KEY_EXCHANGE_2:
   case SILC_PACKET_REKEY_DONE:
   case SILC_PACKET_CONNECTION_AUTH:
-  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
     return FALSE;
     break;
   }
@@ -134,20 +132,14 @@ static void silc_client_packet_eos(SilcPacketEngine engine,
                                   void *stream_context)
 {
   SilcClientConnection conn = stream_context;
-  SilcClient client = conn->client;
 
   SILC_LOG_DEBUG(("Remote disconnected connection"));
 
-  /* Call connection callback */
-  if (!conn->internal->callback_called)
-    conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, 0, NULL,
-                  conn->callback_context);
-  conn->internal->callback_called = TRUE;
-
   /* Signal to close connection */
+  conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 }
 
@@ -186,10 +178,13 @@ static void silc_client_connect_abort(SilcAsyncOperation op, void *context)
 
   SILC_LOG_DEBUG(("Connection %p aborted by application", conn));
 
+  /* Connection callback will not be called after user aborted connecting */
+  conn->callback = NULL;
+
   /* Signal to close connection */
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 }
 
@@ -210,14 +205,14 @@ SILC_FSM_STATE(silc_client_connection_st_start)
   connfsm = &conn->internal->fsm;
   silc_fsm_init(connfsm, conn, silc_client_connection_destructor,
                fsm, conn->internal->schedule);
-  silc_fsm_sema_init(&conn->internal->wait_event, connfsm, 0);
+  silc_fsm_event_init(&conn->internal->wait_event, connfsm);
   silc_fsm_start_sync(connfsm, silc_client_connection_st_run);
 
   /* Schedule any events set in initialization */
   if (conn->internal->connect)
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   if (conn->internal->key_exchange)
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
 
   /* Wait until this thread is terminated from the machine destructor */
   return SILC_FSM_WAIT;
@@ -233,7 +228,7 @@ SILC_FSM_STATE(silc_client_connection_st_run)
   SilcFSMThread thread;
 
   /* Wait for events */
-  SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
+  SILC_FSM_EVENT_WAIT(&conn->internal->wait_event);
 
   /* Process events */
   thread = &conn->internal->event_thread;
@@ -307,7 +302,7 @@ SILC_FSM_STATE(silc_client_connection_st_packet)
 
   case SILC_PACKET_FTP:
     /* File transfer packet */
-    //    silc_client_ftp(client, conn, packet);
+//    silc_fsm_next(fsm, silc_client_ftp);
     break;
 
   case SILC_PACKET_CHANNEL_KEY:
@@ -356,16 +351,15 @@ SILC_FSM_STATE(silc_client_connection_st_packet)
     break;
 
   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
-    /* Reply to connection authentication request to resolve authentication
-       method from server. */
-    //    silc_client_connection_auth_request(client, conn, packet);
+    /** Connection auth resolve reply */
+    silc_fsm_next(fsm, silc_client_connect_auth_request);
     break;
 
   case SILC_PACKET_REKEY:
     /* Signal to start rekey */
     conn->internal->rekey_responder = TRUE;
     conn->internal->rekeying = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
 
     silc_packet_free(packet);
     return SILC_FSM_FINISH;
@@ -382,8 +376,8 @@ SILC_FSM_STATE(silc_client_connection_st_packet)
 
 /* Disconnection event to close remote connection.  We close the connection
    and finish the connection machine in this state.  The connection context
-   is deleted in the machine destructor.  The connection callback must be
-   already called back to application before getting here. */
+   is deleted in the machine destructor.  The connection callback is called
+   in this state if it set. */
 
 SILC_FSM_STATE(silc_client_connection_st_close)
 {
@@ -421,13 +415,19 @@ SILC_FSM_STATE(silc_client_connection_st_close)
     return SILC_FSM_YIELD;
   }
 
+  /* Call the connection callback */
+  if (conn->callback)
+    conn->callback(conn->client, conn, conn->internal->status,
+                  conn->internal->error, conn->internal->disconnect_message,
+                  conn->callback_context);
+  silc_free(conn->internal->disconnect_message);
+
   SILC_LOG_DEBUG(("Closing remote connection"));
 
   /* Close connection */
   silc_packet_stream_destroy(conn->stream);
 
   SILC_LOG_DEBUG(("Finishing connection machine"));
-
   return SILC_FSM_FINISH;
 }
 
@@ -457,7 +457,6 @@ SILC_FSM_STATE(silc_client_error)
 SILC_FSM_STATE(silc_client_disconnect)
 {
   SilcClientConnection conn = fsm_context;
-  SilcClient client = conn->client;
   SilcPacket packet = state_context;
   SilcStatus status;
   char *message = NULL;
@@ -479,20 +478,18 @@ SILC_FSM_STATE(silc_client_disconnect)
                          silc_buffer_len(&packet->buffer));
 
   /* Call connection callback */
-  if (!conn->internal->callback_called)
-    conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, status,
-                  message, conn->callback_context);
-  conn->internal->callback_called = TRUE;
-
-  silc_free(message);
-  silc_packet_free(packet);
+  conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
+  conn->internal->error = status;
+  conn->internal->disconnect_message = message;
 
   /* Signal to close connection */
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 
+  silc_packet_free(packet);
+
   return SILC_FSM_FINISH;
 }
 
@@ -505,7 +502,7 @@ SILC_FSM_STATE(silc_client_st_run)
   SilcClient client = fsm_context;
 
   /* Wait for events */
-  SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
+  SILC_FSM_EVENT_WAIT(&client->internal->wait_event);
 
   /* Process events */
 
@@ -523,7 +520,7 @@ SILC_FSM_STATE(silc_client_st_run)
     client->internal->connection_closed = FALSE;
     if (silc_atomic_get_int16(&client->internal->conns) == 0 &&
        client->internal->stop)
-      SILC_FSM_SEMA_POST(&client->internal->wait_event);
+      SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
     return SILC_FSM_CONTINUE;
   }
 
@@ -638,7 +635,7 @@ silc_client_add_connection(SilcClient client,
     return NULL;
   }
 
-  conn->internal->ftp_sessions = silc_dlist_init();
+  //  conn->internal->ftp_sessions = silc_dlist_init();
 
   /* Initialize our async operation so that application may abort us
      while we're connecting. */
@@ -853,118 +850,10 @@ void silc_client_close_connection(SilcClient client,
   /* Signal to close connection */
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
-    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
   }
 }
 
-#if 0
-/* Processes incoming connection authentication method request packet.
-   It is a reply to our previously sent request. The packet can be used
-   to resolve the authentication method for the current session if the
-   client does not know it beforehand. */
-
-void silc_client_connection_auth_request(SilcClient client,
-                                        SilcClientConnection conn,
-                                        SilcPacketContext *packet)
-{
-  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
-  SilcUInt16 conn_type, auth_meth;
-  int ret;
-
-  /* If we haven't send our request then ignore this one. */
-  if (!conn->internal->connauth)
-    return;
-
-  /* Parse the payload */
-  ret = silc_buffer_unformat(packet->buffer,
-                            SILC_STR_UI_SHORT(&conn_type),
-                            SILC_STR_UI_SHORT(&auth_meth),
-                            SILC_STR_END);
-  if (ret == -1)
-    auth_meth = SILC_AUTH_NONE;
-
-  /* Call the request callback to notify application for received
-     authentication method information. */
-  if (conn->internal->connauth->callback)
-    (*conn->internal->connauth->callback)(client, conn, auth_meth,
-                                         conn->internal->connauth->context);
-
-  silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
-
-  silc_free(conn->internal->connauth);
-  conn->internal->connauth = NULL;
-}
-
-/* Timeout task callback called if the server does not reply to our
-   connection authentication method request in the specified time interval. */
-
-SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
-{
-  SilcClientConnection conn = (SilcClientConnection)context;
-  SilcClient client = conn->client;
-
-  if (!conn->internal->connauth)
-    return;
-
-  /* Call the request callback to notify application */
-  if (conn->internal->connauth->callback)
-    (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
-                                         conn->internal->connauth->context);
-
-  silc_free(conn->internal->connauth);
-  conn->internal->connauth = NULL;
-}
-
-/* This function can be used to request the current authentication method
-   from the server. This may be called when connecting to the server
-   and the client library requests the authentication data from the
-   application. If the application does not know the current authentication
-   method it can request it from the server using this function.
-   The `callback' with `context' will be called after the server has
-   replied back with the current authentication method. */
-
-void
-silc_client_request_authentication_method(SilcClient client,
-                                         SilcClientConnection conn,
-                                         SilcConnectionAuthRequest callback,
-                                         void *context)
-{
-  SilcClientConnAuthRequest connauth;
-  SilcBuffer packet;
-
-  assert(client && conn);
-  connauth = silc_calloc(1, sizeof(*connauth));
-  connauth->callback = callback;
-  connauth->context = context;
-
-  if (conn->internal->connauth)
-    silc_free(conn->internal->connauth);
-
-  conn->internal->connauth = connauth;
-
-  /* Assemble the request packet and send it to the server */
-  packet = silc_buffer_alloc(4);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
-                    SILC_STR_UI_SHORT(SILC_AUTH_NONE),
-                    SILC_STR_END);
-  silc_client_packet_send(client, conn->sock,
-                         SILC_PACKET_CONNECTION_AUTH_REQUEST,
-                         NULL, 0, NULL, NULL,
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
-
-  /* Register a timeout in case server does not reply anything back. */
-  connauth->timeout =
-    silc_schedule_task_add(client->schedule, conn->sock->sock,
-                          silc_client_request_authentication_method_timeout,
-                          conn,
-                          client->internal->params->connauth_request_secs, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-#endif /* 0 */
-
 /* Allocates new client object. This has to be done before client may
    work. After calling this one must call silc_client_init to initialize
    the client. The `application' is application specific user data pointer
@@ -997,9 +886,6 @@ SilcClient silc_client_alloc(SilcClientOperations *ops,
   if (params)
     memcpy(new_client->internal->params, params, sizeof(*params));
 
-  if (!new_client->internal->params->connauth_request_secs)
-    new_client->internal->params->connauth_request_secs = 2;
-
   new_client->internal->params->
     nickname_format[sizeof(new_client->internal->
                           params->nickname_format) - 1] = 0;
@@ -1121,12 +1007,12 @@ SilcBool silc_client_init(SilcClient client, const char *username,
   client->internal->running = running;
   client->internal->running_context = context;
   silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule);
-  silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
+  silc_fsm_event_init(&client->internal->wait_event, &client->internal->fsm);
   silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
 
   /* Signal the application when we are running */
   client->internal->run_callback = TRUE;
-  SILC_FSM_SEMA_POST(&client->internal->wait_event);
+  SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
 
   return TRUE;
 }
@@ -1163,5 +1049,5 @@ void silc_client_stop(SilcClient client, SilcClientStopped stopped,
 
   /* Signal to stop */
   client->internal->stop = TRUE;
-  SILC_FSM_SEMA_POST(&client->internal->wait_event);
+  SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
 }