Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcutil / silcsockconn.c
index e6a81a5907483ffabdd5daad368850c2b48ce819..9b44b7ed357ae1af084525d0443faba308996fe4 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 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
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -23,7 +22,7 @@
 
 /* Heartbeat context */
 struct SilcSocketConnectionHBStruct {
-  uint32 heartbeat;
+  SilcUInt32 heartbeat;
   SilcSocketConnectionHBCb hb_callback;
   void *hb_context;
   SilcSchedule schedule;
@@ -40,10 +39,10 @@ typedef struct {
   bool port;
 } *SilcSocketHostLookup;
 
-/* Allocates a new socket connection object. The allocated object is 
+/* Allocates a new socket connection object. The allocated object is
    returned to the new_socket argument. */
 
-void silc_socket_alloc(int sock, SilcSocketType type, void *user_data, 
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
                       SilcSocketConnection *new_socket)
 {
   SILC_LOG_DEBUG(("Allocating new socket connection object"));
@@ -73,10 +72,12 @@ void silc_socket_free(SilcSocketConnection sock)
     silc_buffer_free(sock->outbuf);
     if (sock->hb) {
       silc_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
-      silc_free(sock->hb->hb_context);
       silc_free(sock->hb);
     }
-
+    if (sock->qos) {
+      silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
+      silc_free(sock->qos);
+    }
     silc_free(sock->ip);
     silc_free(sock->hostname);
 
@@ -104,10 +105,14 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
   if (!hb->heartbeat)
     return;
 
+  if (SILC_IS_DISCONNECTING(hb->sock) ||
+      SILC_IS_DISCONNECTED(hb->sock))
+    return;
+
   if (hb->hb_callback)
     hb->hb_callback(hb->sock, hb->hb_context);
 
-  hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock, 
+  hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
                                       silc_socket_heartbeat,
                                       context, hb->heartbeat, 0,
                                       SILC_TASK_TIMEOUT,
@@ -122,15 +127,14 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
    but will be freed automatically when calling silc_socket_free.  The
    `schedule' is the application's scheduler. */
 
-void silc_socket_set_heartbeat(SilcSocketConnection sock, 
-                              uint32 heartbeat,
+void silc_socket_set_heartbeat(SilcSocketConnection sock,
+                              SilcUInt32 heartbeat,
                               void *hb_context,
                               SilcSocketConnectionHBCb hb_callback,
                               SilcSchedule schedule)
 {
   if (sock->hb) {
     silc_schedule_task_del(schedule, sock->hb->hb_task);
-    silc_free(sock->hb->hb_context);
     silc_free(sock->hb);
   }
 
@@ -147,6 +151,52 @@ void silc_socket_set_heartbeat(SilcSocketConnection sock,
                                             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)
+    return;
+
+  if (sock->qos && !read_rate && !read_limit_bytes &&
+      !limit_sec && !limit_usec && !schedule) {
+    silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
+    silc_free(sock->qos);
+    sock->qos = NULL;
+    return;
+  }
+  if (!schedule)
+    return;
+
+  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;
+  sock->qos->sock = sock;
+}
+
 /* 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. */
@@ -162,8 +212,8 @@ SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
      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_free(lookup);
     silc_socket_free(lookup->sock);
+    silc_free(lookup);
     return;
   }
 
@@ -184,18 +234,19 @@ 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);  
+  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(lookup->schedule, sock->sock,
+  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(lookup->schedule);
+  silc_schedule_wakeup(schedule);
 
   return NULL;
 }
@@ -219,6 +270,10 @@ void silc_socket_host_lookup(SilcSocketConnection sock,
 
   SILC_LOG_DEBUG(("Performing async host lookup"));
 
+  if (SILC_IS_DISCONNECTING(sock) ||
+      SILC_IS_DISCONNECTED(sock))
+    return;
+
   lookup = silc_calloc(1, sizeof(*lookup));
   lookup->sock = silc_socket_dup(sock);        /* Increase reference counter */
   lookup->callback = callback;