updates
[silc.git] / lib / silcclient / client.c
index ba3c70e9b92d1c12b2d6d2f05d0d647fc7c9a7f7..964df1805065791a8bff40d9b1adec99310ecbfa 100644 (file)
@@ -360,34 +360,26 @@ int silc_client_connect_to_server(SilcClient client, int port,
   return sock;
 }
 
-/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
-   key material between client and server.  This function can be called
-   directly if application is performing its own connecting and does not
-   use the connecting provided by this library. This function is normally
-   used only if the application performed the connecting outside the library.
-   The library however may use this internally. */
+/* Socket hostname and IP lookup callback that is called before actually
+   starting the key exchange.  The lookup is called from the function
+   silc_client_start_key_exchange. */
 
-bool silc_client_start_key_exchange(SilcClient client,
-                                   SilcClientConnection conn,
-                                   int fd)
+static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
+                                             void *context)
 {
+  SilcClientConnection conn = (SilcClientConnection)context;
+  SilcClient client = conn->client;
   SilcProtocol protocol;
   SilcClientKEInternalContext *proto_ctx;
-  void *context;
 
-  /* Allocate new socket connection object */
-  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
-
-  /* Sometimes when doing quick reconnects the new socket may be same as
-     the old one and there might be pending stuff for the old socket. 
-     If new one is same then those pending sutff might cause problems.
-     Make sure they do not do that. */
-  silc_schedule_task_del_by_fd(client->schedule, fd);
+  SILC_LOG_DEBUG(("Start"));
 
-  conn->nickname = (client->nickname ? strdup(client->nickname) :
-                   strdup(client->username));
+  /* XXX We should most likely use the resolved host name instead of the
+     one user provided for us. */
+  silc_free(conn->sock->hostname);
   conn->sock->hostname = strdup(conn->remote_host);
-  conn->sock->ip = strdup(conn->remote_host);
+  if (!conn->sock->ip)
+    conn->sock->ip = strdup(conn->remote_host);
   conn->sock->port = conn->remote_port;
 
   /* Allocate internal Key Exchange context. This is sent to the
@@ -408,7 +400,9 @@ bool silc_client_start_key_exchange(SilcClient client,
   if (!protocol) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
                               "Error: Could not start key exchange protocol");
-    return FALSE;
+    silc_net_close_connection(conn->sock->sock);
+    client->internal->ops->connect(client, conn, FALSE);
+    return;
   }
   conn->sock->protocol = protocol;
 
@@ -419,11 +413,38 @@ bool silc_client_start_key_exchange(SilcClient client,
      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
      later when outgoing data is available. */
   context = (void *)client;
-  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
+  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
 
   /* Execute the protocol */
   silc_protocol_execute(protocol, client->schedule, 0, 0);
-  return TRUE;
+}
+
+/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+   key material between client and server.  This function can be called
+   directly if application is performing its own connecting and does not
+   use the connecting provided by this library. This function is normally
+   used only if the application performed the connecting outside the library.
+   The library however may use this internally. */
+
+void silc_client_start_key_exchange(SilcClient client,
+                                   SilcClientConnection conn,
+                                   int fd)
+{
+  /* Allocate new socket connection object */
+  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
+
+  /* Sometimes when doing quick reconnects the new socket may be same as
+     the old one and there might be pending stuff for the old socket. 
+     If new one is same then those pending sutff might cause problems.
+     Make sure they do not do that. */
+  silc_schedule_task_del_by_fd(client->schedule, fd);
+
+  conn->nickname = (client->nickname ? strdup(client->nickname) :
+                   strdup(client->username));
+
+  /* Resolve the remote hostname and IP address for our socket connection */
+  silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
+                         conn, client->schedule);
 }
 
 /* Callback called when error has occurred during connecting to the server.
@@ -436,6 +457,8 @@ SILC_TASK_CALLBACK(silc_client_connect_failure)
   SilcClient client = (SilcClient)ctx->client;
 
   client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
+  if (ctx->packet)
+    silc_packet_context_free(ctx->packet);
   silc_free(ctx);
 }
 
@@ -493,10 +516,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
   silc_schedule_task_del(client->schedule, ctx->task);
   silc_free(ctx);
 
-  if (!silc_client_start_key_exchange(client, conn, fd)) {
-    silc_net_close_connection(fd);
-    client->internal->ops->connect(client, conn, FALSE);
-  }
+  silc_client_start_key_exchange(client, conn, fd);
 }
 
 /* Second part of the connecting to the server. This executed 
@@ -1040,7 +1060,8 @@ void silc_client_packet_parse_type(SilcClient client,
        
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+        if (proto_ctx->dest_id)
+          silc_free(proto_ctx->dest_id);
        proto_ctx->packet = silc_packet_context_dup(packet);
        proto_ctx->dest_id_type = packet->src_id_type;
        proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -1349,13 +1370,15 @@ void silc_client_close_connection(SilcClient client,
 
     /* Clear ID caches */
     if (conn->client_cache)
-      silc_idcache_del_all(conn->client_cache);
+      silc_idcache_free(conn->client_cache);
     if (conn->channel_cache)
-      silc_idcache_del_all(conn->channel_cache);
+      silc_idcache_free(conn->channel_cache);
     if (conn->server_cache)
-      silc_idcache_del_all(conn->server_cache);
+      silc_idcache_free(conn->server_cache);
 
     /* Free data (my ID is freed in above silc_client_del_client) */
+    if (conn->nickname)
+      silc_free(conn->nickname);
     if (conn->remote_host)
       silc_free(conn->remote_host);
     if (conn->local_id_data)
@@ -1486,7 +1509,7 @@ void silc_client_receive_new_id(SilcClient client,
   if (!conn->local_entry)
     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
 
-  conn->local_entry->nickname = conn->nickname;
+  conn->local_entry->nickname = strdup(conn->nickname);
   if (!conn->local_entry->username)
     conn->local_entry->username = strdup(client->username);
   if (!conn->local_entry->hostname)