diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2010-01-13 00:32:42 +0000 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2010-02-03 01:53:43 +0100 |
commit | 997f7268f2940e56ed47e353c6872ca53be6efad (patch) | |
tree | b287e470529d87b57837a4799ad66899aef3e774 | |
parent | b32d20cfdabab1ae8deec25b608fb23056b38f8d (diff) | |
download | quagga-997f7268f2940e56ed47e353c6872ca53be6efad.tar.bz2 quagga-997f7268f2940e56ed47e353c6872ca53be6efad.tar.xz |
BGP: leave peer socket in non-blocking mode (mostly)
Rather than toggling socket in/out of non-block mode,
just leave it in nonblocking mode.
Also, only handle non-blocking and errno's correctly.
On write errno is only set if return is less than zero;
otherwise errno is from last failed system call.
On read errno is only set if return is less than zero.
Use convient ERRNO_IO_RETRY() macro to check for AGAIN/INTR etc.
One exception is in bgp_notify which only happens just
before close.
-rw-r--r-- | bgpd/bgp_network.c | 1 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 35 |
2 files changed, 15 insertions, 21 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 9e3427d2..4c79aa63 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -150,6 +150,7 @@ bgp_accept (struct thread *thread) zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } + set_nonblocking (bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b29bc1f0..aa0f9c50 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -597,7 +597,6 @@ bgp_write (struct thread *thread) struct stream *s; int num; unsigned int count = 0; - int write_errno; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); @@ -619,36 +618,26 @@ bgp_write (struct thread *thread) s = bgp_write_packet (peer); if (! s) return 0; - - /* XXX: FIXME, the socket should be NONBLOCK from the start - * status shouldnt need to be toggled on each write - */ - val = fcntl (peer->fd, F_GETFL, 0); - fcntl (peer->fd, F_SETFL, val|O_NONBLOCK); /* Number of bytes to be sent. */ writenum = stream_get_endp (s) - stream_get_getp (s); /* Call write() system call. */ num = write (peer->fd, STREAM_PNT (s), writenum); - write_errno = errno; - fcntl (peer->fd, F_SETFL, val); - if (num <= 0) + if (num < 0) { - /* Partial write. */ - if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) - break; + /* write failed either retry needed or error */ + if (ERRNO_IO_RETRY(errno)) + break; BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } + if (num != writenum) { + /* Partial write */ stream_forward_getp (s, num); - - if (write_errno == EAGAIN) - break; - continue; } @@ -705,7 +694,7 @@ bgp_write (struct thread *thread) static int bgp_write_notify (struct peer *peer) { - int ret; + int ret, val; u_char type; struct stream *s; @@ -715,7 +704,10 @@ bgp_write_notify (struct peer *peer) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); - /* I'm not sure fd is writable. */ + /* Put socket in blocking mode. */ + val = fcntl (peer->fd, F_GETFL, 0); + fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); + ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); if (ret <= 0) { @@ -2237,12 +2229,13 @@ bgp_read_packet (struct peer *peer) return 0; /* Read packet from fd. */ - nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize); + nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occured. */ if (nbytes < 0) { - if (errno == EAGAIN) + /* Transient error should retry */ + if (nbytes == -2) return -1; plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", |