summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2010-01-13 00:32:42 +0000
committerDavid Lamparter <equinox@diac24.net>2010-02-03 01:53:43 +0100
commit997f7268f2940e56ed47e353c6872ca53be6efad (patch)
treeb287e470529d87b57837a4799ad66899aef3e774
parentb32d20cfdabab1ae8deec25b608fb23056b38f8d (diff)
downloadquagga-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.c1
-rw-r--r--bgpd/bgp_packet.c35
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",