diff options
author | Martin Mares <mj@ucw.cz> | 2000-03-30 12:43:37 +0200 |
---|---|---|
committer | Martin Mares <mj@ucw.cz> | 2000-03-30 12:43:37 +0200 |
commit | 320f41735795b51c51a9f5c976a2335a9ec96e32 (patch) | |
tree | 5f4bdd3981d1d99bf4c91d14cfa1c639ebfd772e /sysdep/unix/io.c | |
parent | 3a6337ecb2f6e5c8454a8416214c60432611aaa6 (diff) | |
download | bird-320f41735795b51c51a9f5c976a2335a9ec96e32.tar bird-320f41735795b51c51a9f5c976a2335a9ec96e32.zip |
Defined sk_close() which closes the socket safely even if called from
socket hook. Replaces the SK_DELETED hack.
Squashed a couple of bugs in handling of TCP sockets.
Diffstat (limited to 'sysdep/unix/io.c')
-rw-r--r-- | sysdep/unix/io.c | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 69f3f06..0925609 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -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); } |