Merged from silc_1_0_branch.
[silc.git] / lib / silcutil / silcsockconn.c
index 0f6672b8783ae8fe83c10f2b2c1b9e92347d9bab..6817c5daea20f98150f7c52b3e9f4a696bc97e3e 100644 (file)
 #include "silcincludes.h"
 
 /* Heartbeat context */
-struct SilcSocketConnectionHB {
-  uint32 heartbeat;
+struct SilcSocketConnectionHBStruct {
+  SilcUInt32 heartbeat;
   SilcSocketConnectionHBCb hb_callback;
   void *hb_context;
-  void *timeout_queue;
+  SilcSchedule schedule;
   SilcTask hb_task;
   SilcSocketConnection sock;
 };
 
+/* Internal async host lookup context. */
+typedef struct {
+  SilcSocketHostLookupCb callback;
+  void *context;
+  SilcSchedule schedule;
+  SilcSocketConnection sock;
+  bool port;
+} *SilcSocketHostLookup;
+
 /* Allocates a new socket connection object. The allocated object is 
    returned to the new_socket argument. */
 
@@ -63,10 +72,12 @@ void silc_socket_free(SilcSocketConnection sock)
     silc_buffer_free(sock->inbuf);
     silc_buffer_free(sock->outbuf);
     if (sock->hb) {
-      silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
-      silc_free(sock->hb->hb_context);
+      silc_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
       silc_free(sock->hb);
     }
+    silc_free(sock->qos);
+    silc_free(sock->ip);
+    silc_free(sock->hostname);
 
     memset(sock, 'F', sizeof(*sock));
     silc_free(sock);
@@ -95,11 +106,11 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
   if (hb->hb_callback)
     hb->hb_callback(hb->sock, hb->hb_context);
 
-  hb->hb_task = silc_task_register(hb->timeout_queue, hb->sock->sock, 
-                                  silc_socket_heartbeat,
-                                  context, hb->heartbeat, 0,
-                                  SILC_TASK_TIMEOUT,
-                                  SILC_TASK_PRI_LOW);
+  hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock, 
+                                      silc_socket_heartbeat,
+                                      context, hb->heartbeat, 0,
+                                      SILC_TASK_TIMEOUT,
+                                      SILC_TASK_PRI_LOW);
 }
 
 /* Sets the heartbeat timeout and prepares the socket for performing
@@ -108,18 +119,16 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
    `hb_callback' function that is called when the `heartbeat' timeout
    expires.  The callback `hb_context' won't be touched by the library
    but will be freed automatically when calling silc_socket_free.  The
-   `timeout_queue' is the application's scheduler timeout queue. */
+   `schedule' is the application's scheduler. */
 
 void silc_socket_set_heartbeat(SilcSocketConnection sock, 
-                              uint32 heartbeat,
+                              SilcUInt32 heartbeat,
                               void *hb_context,
                               SilcSocketConnectionHBCb hb_callback,
-                              void *timeout_queue)
+                              SilcSchedule schedule)
 {
-
   if (sock->hb) {
-    silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
-    silc_free(sock->hb->hb_context);
+    silc_schedule_task_del(schedule, sock->hb->hb_task);
     silc_free(sock->hb);
   }
 
@@ -127,11 +136,127 @@ void silc_socket_set_heartbeat(SilcSocketConnection sock,
   sock->hb->heartbeat = heartbeat;
   sock->hb->hb_context = hb_context;
   sock->hb->hb_callback = hb_callback;
-  sock->hb->timeout_queue = timeout_queue;
+  sock->hb->schedule = schedule;
   sock->hb->sock = sock;
-  sock->hb->hb_task = silc_task_register(timeout_queue, sock->sock,
-                                         silc_socket_heartbeat,
-                                         (void *)sock->hb, heartbeat, 0,
-                                         SILC_TASK_TIMEOUT,
-                                         SILC_TASK_PRI_LOW);
+  sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
+                                            silc_socket_heartbeat,
+                                            (void *)sock->hb, heartbeat, 0,
+                                            SILC_TASK_TIMEOUT,
+                                            SILC_TASK_PRI_LOW);
+}
+
+/* Sets a "Quality of Service" settings for socket connection `sock'.
+   The `read_rate' specifies the maximum read operations per second.
+   If more read operations are executed the limit will be applied for
+   the reading.  The `read_limit_bytes' specifies the maximum data
+   that is read.  It is guaranteed that silc_socket_read never returns
+   more that `read_limit_bytes' of data.  If more is read the limit
+   will be applied for the reading.  The `limit_sec' and `limit_usec'
+   specifies the limit that is applied if `read_rate' and/or 
+   `read_limit_bytes' is reached.  The `schedule' is the application's
+   scheduler. */
+
+void silc_socket_set_qos(SilcSocketConnection sock, 
+                        SilcUInt32 read_rate,
+                        SilcUInt32 read_limit_bytes,
+                        SilcUInt32 limit_sec,
+                        SilcUInt32 limit_usec,
+                        SilcSchedule schedule)
+{
+  if (!sock->qos) {
+    sock->qos = silc_calloc(1, sizeof(*sock->qos));
+    if (!sock->qos)
+      return;
+  }
+  sock->qos->read_rate = read_rate;
+  sock->qos->read_limit_bytes = read_limit_bytes;
+  sock->qos->limit_sec = limit_sec;
+  sock->qos->limit_usec = limit_usec;
+  sock->qos->schedule = schedule;
+  memset(&sock->qos->next_limit, 0, sizeof(sock->qos->next_limit));
+  sock->qos->cur_rate = 0;
+}
+
+/* Finishing timeout callback that will actually call the user specified
+   host lookup callback. This is executed back in the calling thread and
+   not in the lookup thread. */
+
+SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
+{
+  SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
+
+  SILC_UNSET_HOST_LOOKUP(lookup->sock);
+
+  /* If the reference counter is 1 we know that we are the only one
+     holding the socket and it thus is considered freed. The lookup
+     is cancelled also and we will not call the final callback. */
+  if (lookup->sock->users == 1) {
+    SILC_LOG_DEBUG(("Async host lookup was cancelled"));
+    silc_socket_free(lookup->sock);
+    silc_free(lookup);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Async host lookup finished"));
+
+  silc_socket_free(lookup->sock);
+
+  /* Call the final callback. */
+  if (lookup->callback)
+    lookup->callback(lookup->sock, lookup->context);
+
+  silc_free(lookup);
+}
+
+/* The thread function that performs the actual lookup. */
+
+static void *silc_socket_host_lookup_start(void *context)
+{
+  SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
+  SilcSocketConnection sock = lookup->sock;
+  SilcSchedule schedule = lookup->schedule;
+
+  if (lookup->port)
+    sock->port = silc_net_get_remote_port(sock->sock);
+
+  silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);  
+  if (!sock->hostname && sock->ip)
+    sock->hostname = strdup(sock->ip);
+
+  silc_schedule_task_add(schedule, sock->sock,
+                        silc_socket_host_lookup_finish, lookup, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_wakeup(schedule);
+
+  return NULL;
+}
+
+/* Performs asynchronous host name and IP address lookups for the
+   specified socket connection. This may be called when the socket
+   connection is created and the full IP address and fully qualified
+   domain name information is desired. The `callback' with `context'
+   will be called after the lookup is performed. The `schedule'
+   is the application's scheduler which the lookup routine needs. If
+   the socket connection is freed during the lookup the library will
+   automatically cancel the lookup and the `callback' will not be called. */
+
+void silc_socket_host_lookup(SilcSocketConnection sock,
+                            bool port_lookup,
+                            SilcSocketHostLookupCb callback,
+                            void *context,
+                            SilcSchedule schedule)
+{
+  SilcSocketHostLookup lookup;
+
+  SILC_LOG_DEBUG(("Performing async host lookup"));
+
+  lookup = silc_calloc(1, sizeof(*lookup));
+  lookup->sock = silc_socket_dup(sock);        /* Increase reference counter */
+  lookup->callback = callback;
+  lookup->context = context;
+  lookup->schedule = schedule;
+  lookup->port = port_lookup;
+
+  SILC_SET_HOST_LOOKUP(sock);
+  silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);
 }