Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[silc.git] / lib / silcutil / unix / silcunixsocketstream.c
index 046c795c7e247b82d3212fe555d84d5f68098387..60d458d4a19bb39be74a42dbd3ca625cf7ee32a6 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2008 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
@@ -80,6 +80,8 @@ int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
       if (errno == EAGAIN || errno == EINTR) {
        SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
        silc_schedule_set_listen_fd(sock->schedule, sock->sock,
+                                   silc_schedule_get_fd_events(sock->schedule,
+                                                               sock->sock) |
                                    SILC_TASK_READ, FALSE);
        return -1;
       }
@@ -104,8 +106,9 @@ int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
   /* If QoS was applied, return the data that was pending. */
   if (sock->qos->applied && sock->qos->data_len) {
     memcpy(buf, qosbuf, sock->qos->data_len);
+    len = sock->qos->data_len;
     sock->qos->data_len = 0;
-    return sock->qos->data_len;
+    return len;
   }
 
   /* If we have active QoS data pending, return with no data */
@@ -114,7 +117,8 @@ int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
     return -1;
   }
 
-  /* Read the data from the socket.  Never read more than the max limit. */
+  /* Read the data from the socket.  The qosbuf size is always the max
+     read limit size. */
   len = (buf_len < sock->qos->read_limit_bytes ? buf_len :
         sock->qos->read_limit_bytes);
   len = read(sock->sock, qosbuf, len);
@@ -122,6 +126,8 @@ int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
     if (errno == EAGAIN || errno == EINTR) {
       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
       silc_schedule_set_listen_fd(sock->schedule, sock->sock,
+                                 silc_schedule_get_fd_events(sock->schedule,
+                                                             sock->sock) |
                                  SILC_TASK_READ, FALSE);
       return -1;
     }
@@ -146,7 +152,7 @@ int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
   /* If we have passed the rate time limit, set our new time limit,
      and zero the rate limit.  This limits reads per second. */
   silc_gettimeofday(&curtime);
-  if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
+  if (silc_compare_timeval(&curtime, &sock->qos->next_limit) > 0) {
     curtime.tv_sec++;
     sock->qos->next_limit = curtime;
     sock->qos->cur_rate = 0;
@@ -245,7 +251,7 @@ SilcBool silc_socket_get_error(SilcStream sock, char *error,
   memcpy(error, err, strlen(err));
   return TRUE;
 }
-#endif /* 0 */
+#endif
 
 /* Closes socket */
 
@@ -253,7 +259,12 @@ SilcBool silc_socket_stream_close(SilcStream stream)
 {
   SilcSocketStream socket_stream = stream;
 
-  silc_schedule_unset_listen_fd(socket_stream->schedule, socket_stream->sock);
+  if (socket_stream->schedule) {
+    silc_schedule_unset_listen_fd(socket_stream->schedule,
+                                 socket_stream->sock);
+    silc_schedule_task_del_by_fd(socket_stream->schedule,
+                                socket_stream->sock);
+  }
   silc_net_close_connection(socket_stream->sock);
 
   return TRUE;
@@ -290,10 +301,10 @@ void silc_socket_stream_destroy(SilcStream stream)
 
 /* Sets stream notification callback for the stream */
 
-void silc_socket_stream_notifier(SilcStream stream,
-                                SilcSchedule schedule,
-                                SilcStreamNotifier callback,
-                                void *context)
+SilcBool silc_socket_stream_notifier(SilcStream stream,
+                                    SilcSchedule schedule,
+                                    SilcStreamNotifier callback,
+                                    void *context)
 {
   SilcSocketStream socket_stream = stream;
 
@@ -303,21 +314,31 @@ void silc_socket_stream_notifier(SilcStream stream,
   socket_stream->notifier_context = context;
   socket_stream->schedule = schedule;
 
-  if (socket_stream->notifier) {
+  if (socket_stream->notifier && socket_stream->schedule) {
+    /* Set the socket to non-blocking mode */
+    silc_net_set_socket_nonblock(socket_stream->sock);
+
     /* Add the socket to scheduler.  Safe to call if already added. */
-    silc_schedule_task_add_fd(socket_stream->schedule, socket_stream->sock,
-                             silc_socket_stream_io, socket_stream);
+    if (!silc_schedule_task_add_fd(socket_stream->schedule,
+                                  socket_stream->sock,
+                                  silc_socket_stream_io, socket_stream))
+      return FALSE;
 
     /* Initially set socket for reading */
-    silc_schedule_set_listen_fd(socket_stream->schedule, socket_stream->sock,
-                               SILC_TASK_READ, FALSE);
-    silc_schedule_wakeup(socket_stream->schedule);
-  } else {
+    if (!silc_schedule_set_listen_fd(socket_stream->schedule,
+                                    socket_stream->sock,
+                                    SILC_TASK_READ, FALSE))
+      return FALSE;
+  } else if (socket_stream->schedule) {
     /* Unschedule the socket */
     silc_schedule_unset_listen_fd(socket_stream->schedule,
                                  socket_stream->sock);
     silc_schedule_task_del_by_fd(socket_stream->schedule,
                                 socket_stream->sock);
-    silc_schedule_wakeup(socket_stream->schedule);
   }
+
+  if (socket_stream->schedule)
+    silc_schedule_wakeup(socket_stream->schedule);
+
+  return TRUE;
 }