]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Defined sk_close() which closes the socket safely even if called from
authorMartin Mares <mj@ucw.cz>
Thu, 30 Mar 2000 10:43:37 +0000 (10:43 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 30 Mar 2000 10:43:37 +0000 (10:43 +0000)
socket hook. Replaces the SK_DELETED hack.

Squashed a couple of bugs in handling of TCP sockets.

lib/socket.h
sysdep/unix/io.c
sysdep/unix/main.c

index 65ba9a204a392c19224e6f70ddd2246246358731..147e5ce152f719d3211c5cd0217d03e3926c15ea 100644 (file)
@@ -38,10 +38,12 @@ typedef struct birdsock {
 
   int fd;                              /* System-dependent data */
   node n;
+  int entered;
 } sock;
 
 sock *sk_new(pool *);                  /* Allocate new socket */
 int sk_open(sock *);                   /* Open socket */
+void sk_close(sock *);                 /* Safe close of socket even from socket hook */
 int sk_send(sock *, unsigned len);     /* Send data, <0=err, >0=ok, 0=sleep */
 int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
 void sk_dump_all(void);
@@ -66,7 +68,7 @@ sk_send_buffer_empty(sock *sk)
 #define SK_MAGIC       7          /* Internal use by sysdep code */
 #define SK_UNIX_PASSIVE        8
 #define SK_UNIX                9
-#define SK_DELETED     10         /* Set to this if you want to delete socket from err_hook */
+#define SK_DELETED     10         /* Internal use by sk_close */
 
 /*
  *  Multicast sockets are slightly different from the other ones:
index 69f3f066d4369ebe4c1fa2d1b038a60da7664c5c..0925609b881d87164072bfebe356cd7a298c091c 100644 (file)
@@ -336,7 +336,10 @@ sk_free(resource *r)
   sock *s = (sock *) r;
 
   if (s->fd >= 0)
-    rem_node(&s->n);
+    {
+      close(s->fd);
+      rem_node(&s->n);
+    }
 }
 
 static void
@@ -382,6 +385,7 @@ sk_new(pool *p)
   s->tbsize = 0;
   s->err_hook = NULL;
   s->fd = -1;
+  s->entered = 0;
   return s;
 }
 
@@ -477,9 +481,9 @@ sk_alloc_bufs(sock *s)
 static void
 sk_tcp_connected(sock *s)
 {
-  s->rx_hook(s, 0);
   s->type = SK_TCP;
   sk_alloc_bufs(s);
+  s->tx_hook(s);
 }
 
 static int
@@ -524,6 +528,8 @@ sk_open(sock *s)
   switch (type)
     {
     case SK_TCP_ACTIVE:
+      s->ttx = "";                     /* Force s->ttx != s->tpos */
+      /* Fall thru */
     case SK_TCP_PASSIVE:
       fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
       break;
@@ -625,6 +631,7 @@ sk_open(sock *s)
     case SK_MAGIC:
       break;
     default:
+      sk_alloc_bufs(s);
 #ifdef IPV6
 #ifdef IPV6_MTU_DISCOVER
       {
@@ -644,7 +651,6 @@ sk_open(sock *s)
 #endif
     }
 
-  sk_alloc_bufs(s);
   add_tail(&sock_list, &s->n);
   return 0;
 
@@ -686,6 +692,15 @@ bad:
   return -1;
 }
 
+void
+sk_close(sock *s)
+{
+  if (s->entered)
+    s->type = SK_DELETED;
+  else
+    rfree(s);
+}
+
 static int
 sk_maybe_write(sock *s)
 {
@@ -767,19 +782,6 @@ sk_read(sock *s)
 {
   switch (s->type)
     {
-    case SK_TCP_ACTIVE:
-      {
-       sockaddr sa;
-       fill_in_sockaddr(&sa, s->daddr, s->dport);
-       if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
-         sk_tcp_connected(s);
-       else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
-         {
-           log(L_ERR "connect: %m");
-           s->err_hook(s, errno);
-         }
-       return 0;
-      }
     case SK_TCP_PASSIVE:
       {
        sockaddr sa;
@@ -816,6 +818,8 @@ sk_read(sock *s)
       }
     case SK_MAGIC:
       return s->rx_hook(s, 0);
+    case SK_DELETED:
+      return 0;
     default:
       {
        sockaddr sa;
@@ -842,8 +846,27 @@ sk_read(sock *s)
 static void
 sk_write(sock *s)
 {
-  while (s->ttx != s->tbuf && sk_maybe_write(s) > 0)
-    s->tx_hook(s);
+  switch (s->type)
+    {
+    case SK_TCP_ACTIVE:
+      {
+       sockaddr sa;
+       fill_in_sockaddr(&sa, s->daddr, s->dport);
+       if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
+         sk_tcp_connected(s);
+       else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
+         {
+           log(L_ERR "connect: %m");
+           s->err_hook(s, errno);
+         }
+       break;
+      }
+    case SK_DELETED:
+      return;
+    default:
+      while (s->ttx != s->tbuf && sk_maybe_write(s) > 0)
+       s->tx_hook(s);
+    }
 }
 
 void
@@ -965,6 +988,7 @@ io_loop(void)
          WALK_LIST_DELSAFE(n, p, sock_list)
            {
              s = SKIP_BACK(sock, n, n);
+             s->entered = 1;
              if (FD_ISSET(s->fd, &rd))
                {
                  FD_CLR(s->fd, &rd);
@@ -976,6 +1000,7 @@ io_loop(void)
                  FD_CLR(s->fd, &wr);
                  sk_write(s);
                }
+             s->entered = 0;
              if (s->type == SK_DELETED)
                rfree(s);
            }
index c6f489362e4115072d76bf75eee219c2b0906cbe..dcd921f0490e3e3b909beaba6ae826c58c6d5dd2 100644 (file)
@@ -236,8 +236,8 @@ cli_err(sock *s, int err)
     log(L_INFO "CLI connection dropped: %s", strerror(err));
   else
     log(L_INFO "CLI connection closed");
-  s->type = SK_DELETED;
   cli_free(s->data);
+  sk_close(s);
 }
 
 static int