diff options
author | ajs <ajs> | 2005-02-28 20:52:15 +0000 |
---|---|---|
committer | ajs <ajs> | 2005-02-28 20:52:15 +0000 |
commit | 719e97414a7ca1a4d49d72816b9e1bd2155d157d (patch) | |
tree | 6c3d4456e89d1a837322566eee065e492b325e6c | |
parent | 27da3988c30c333cd75cffc5565682366bb99513 (diff) |
2005-02-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* zserv.c: Must include network.h and buffer.h for non-blocking I/O.
Remove global message_queue and t_write (need separate buffering for
each client).
(zebra_server_dequeue,zebra_server_enqueue) Remove functions
related to old buggy buffering code.
(zserv_delayed_close) New thread callback function to delete a client.
(zserv_flush_data) New thread callback function to flush buffered
data to client.
(zebra_server_send_message) Rewritten to use buffer_write (so
buffering of writes and non-blocking I/O work properly).
(zsend_interface_add,zsend_interface_delete,zsend_interface_address,
zsend_interface_update) Return 0 instead of -1 if !client->ifinfo
(this is not really an error). Return value from
zebra_server_send_message.
(zsend_route_multipath,zsend_ipv4_nexthop_lookup,
zsend_ipv4_import_lookup) Return value from zebra_server_send_message.
(zsend_ipv6_nexthop_lookup) Fix scope to static, and return value
from zebra_server_send_message.
(zsend_router_id_update) Must use zebra_server_send_message instead
of deprecated writen function. Return 0 instead of -1 if this client
is not subscribed to router-id updates (since this is not really
an error).
(zread_interface_add) Change type to static int. If
zsend_interface_add fails or zsend_interface_address fails, return -1
immediately (since the client has had an I/O error).
(zread_interface_delete,zread_ipv4_add,zread_ipv4_delete,
zread_ipv6_add,zread_ipv6_delete,zread_router_id_delete) Return 0
to indicate success.
(zread_ipv4_nexthop_lookup) Return value from
zsend_ipv4_nexthop_lookup.
(zread_ipv4_import_lookup) Return value from zsend_ipv4_import_lookup.
(zebra_read_ipv6) Remove unused function.
(zread_ipv6_nexthop_lookup) Return value from
zsend_ipv6_nexthop_lookup.
(zread_router_id_add) Return value from zsend_router_id_update.
(zebra_client_close) Call buffer_free(client->wb) and
thread_cancel(client->t_suicide).
(zebra_client_create) Allocate client->wb using buffer_new.
(zebra_client_read) Support non-blocking I/O by using stream_read_try.
Use ZEBRA_HEADER_SIZE instead of 3.
(zebra_accept) Fix bug: reset accept thread at top. Make client
socket non-blocking using the set_nonblocking function.
(config_write_forwarding) Fix scope to static.
(zebra_init) Remove initialization code for old buggy write buffering.
* zserv.h: Add 2 new fields to struct zserv: struct buffer *wb
(to enable buffered writes with non-blocking I/), and
struct thread *t_suicide to support delayed close on I/O
errors.
* router-id.h: Remove prototypes for zread_router_id_add and
zread_router_id_delete (their scope should be static to zserv.c).
-rw-r--r-- | zebra/ChangeLog | 53 | ||||
-rw-r--r-- | zebra/router-id.h | 3 | ||||
-rw-r--r-- | zebra/zserv.c | 354 | ||||
-rw-r--r-- | zebra/zserv.h | 6 |
4 files changed, 215 insertions, 201 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog index f29d2eac..a93f886e 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,56 @@ +2005-02-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + + * zserv.c: Must include network.h and buffer.h for non-blocking I/O. + Remove global message_queue and t_write (need separate buffering for + each client). + (zebra_server_dequeue,zebra_server_enqueue) Remove functions + related to old buggy buffering code. + (zserv_delayed_close) New thread callback function to delete a client. + (zserv_flush_data) New thread callback function to flush buffered + data to client. + (zebra_server_send_message) Rewritten to use buffer_write (so + buffering of writes and non-blocking I/O work properly). + (zsend_interface_add,zsend_interface_delete,zsend_interface_address, + zsend_interface_update) Return 0 instead of -1 if !client->ifinfo + (this is not really an error). Return value from + zebra_server_send_message. + (zsend_route_multipath,zsend_ipv4_nexthop_lookup, + zsend_ipv4_import_lookup) Return value from zebra_server_send_message. + (zsend_ipv6_nexthop_lookup) Fix scope to static, and return value + from zebra_server_send_message. + (zsend_router_id_update) Must use zebra_server_send_message instead + of deprecated writen function. Return 0 instead of -1 if this client + is not subscribed to router-id updates (since this is not really + an error). + (zread_interface_add) Change type to static int. If + zsend_interface_add fails or zsend_interface_address fails, return -1 + immediately (since the client has had an I/O error). + (zread_interface_delete,zread_ipv4_add,zread_ipv4_delete, + zread_ipv6_add,zread_ipv6_delete,zread_router_id_delete) Return 0 + to indicate success. + (zread_ipv4_nexthop_lookup) Return value from + zsend_ipv4_nexthop_lookup. + (zread_ipv4_import_lookup) Return value from zsend_ipv4_import_lookup. + (zebra_read_ipv6) Remove unused function. + (zread_ipv6_nexthop_lookup) Return value from + zsend_ipv6_nexthop_lookup. + (zread_router_id_add) Return value from zsend_router_id_update. + (zebra_client_close) Call buffer_free(client->wb) and + thread_cancel(client->t_suicide). + (zebra_client_create) Allocate client->wb using buffer_new. + (zebra_client_read) Support non-blocking I/O by using stream_read_try. + Use ZEBRA_HEADER_SIZE instead of 3. + (zebra_accept) Fix bug: reset accept thread at top. Make client + socket non-blocking using the set_nonblocking function. + (config_write_forwarding) Fix scope to static. + (zebra_init) Remove initialization code for old buggy write buffering. + * zserv.h: Add 2 new fields to struct zserv: struct buffer *wb + (to enable buffered writes with non-blocking I/), and + struct thread *t_suicide to support delayed close on I/O + errors. + * router-id.h: Remove prototypes for zread_router_id_add and + zread_router_id_delete (their scope should be static to zserv.c). + 2005-02-24 Andrew J. Schorr <ajschorr@alumni.princeton.edu> * redistribute.c: (zebra_check_addr,is_default, diff --git a/zebra/router-id.h b/zebra/router-id.h index 7f7a8c3b..be12bf50 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -37,7 +37,4 @@ extern void router_id_init(void); extern void router_id_write(struct vty *); extern void router_id_get(struct prefix *); -extern void zread_router_id_add(struct zserv *, u_short); -extern void zread_router_id_delete(struct zserv *, u_short); - #endif diff --git a/zebra/zserv.c b/zebra/zserv.c index e74248b1..caebe490 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -34,6 +34,8 @@ #include "log.h" #include "zclient.h" #include "privs.h" +#include "network.h" +#include "buffer.h" #include "zebra/zserv.h" #include "zebra/router-id.h" @@ -77,102 +79,74 @@ static const char *zebra_command_str [] = "ZEBRA_ROUTER_ID_UPDATE" }; -struct zebra_message_queue -{ - struct nsm_message_queue *next; - struct nsm_message_queue *prev; - u_char *buf; - u_int16_t length; - u_int16_t written; -}; +static void zebra_client_close (struct zserv *client); -struct thread *t_write; -struct fifo message_queue; - -int -zebra_server_dequeue (struct thread *t) +static int +zserv_delayed_close(struct thread *thread) { - int sock; - int nbytes; - struct zebra_message_queue *queue; - - sock = THREAD_FD (t); - t_write = NULL; - - queue = (struct zebra_message_queue *) FIFO_HEAD (&message_queue); - if (queue) - { - nbytes = write (sock, queue->buf + queue->written, - queue->length - queue->written); - - if (nbytes <= 0) - { - if (errno != EAGAIN) - return -1; - } - else if (nbytes != (queue->length - queue->written)) - { - queue->written += nbytes; - } - else - { - FIFO_DEL (queue); - XFREE (MTYPE_TMP, queue->buf); - XFREE (MTYPE_TMP, queue); - } - } - - if (FIFO_TOP (&message_queue)) - THREAD_WRITE_ON (zebrad.master, t_write, zebra_server_dequeue, - NULL, sock); + struct zserv *client = THREAD_ARG(thread); + client->t_suicide = NULL; + zebra_client_close(client); return 0; } -/* Enqueu message. */ -void -zebra_server_enqueue (int sock, u_char *buf, unsigned long length, - unsigned long written) -{ - struct zebra_message_queue *queue; - - queue = XCALLOC (MTYPE_TMP, sizeof (struct zebra_message_queue)); - queue->buf = XMALLOC (MTYPE_TMP, length); - memcpy (queue->buf, buf, length); - queue->length = length; - queue->written = written; - - FIFO_ADD (&message_queue, queue); - - THREAD_WRITE_ON (zebrad.master, t_write, zebra_server_dequeue, NULL, sock); -} - -int -zebra_server_send_message (int sock, u_char *buf, unsigned long length) +static int +zserv_flush_data(struct thread *thread) { - int nbytes; + struct zserv *client = THREAD_ARG(thread); - if (FIFO_TOP (&message_queue)) + client->t_write = NULL; + if (client->t_suicide) { - zebra_server_enqueue (sock, buf, length, 0); - return 0; + zebra_client_close(client); + return -1; } - - /* Send message. */ - nbytes = write (sock, buf, length); - - if (nbytes <= 0) + switch (buffer_flush_available(client->wb, client->sock)) { - if (errno == EAGAIN) - zebra_server_enqueue (sock, buf, length, 0); - else - return -1; + case BUFFER_ERROR: + zlog_warn("%s: buffer_flush_available failed on zserv client fd %d, " + "closing", __func__, client->sock); + zebra_client_close(client); + break; + case BUFFER_PENDING: + client->t_write = thread_add_write(zebrad.master, zserv_flush_data, + client, client->sock); + break; + case BUFFER_EMPTY: + break; } - /* It's clear that nbytes is positive at this point. */ - else if ((unsigned) nbytes != length) - zebra_server_enqueue (sock, buf, length, nbytes); + return 0; +} +static int +zebra_server_send_message(struct zserv *client) +{ + if (client->t_suicide) + return -1; + switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), + stream_get_endp(client->obuf))) + { + case BUFFER_ERROR: + zlog_warn("%s: buffer_write failed to zserv client fd %d, closing", + __func__, client->sock); + /* Schedule a delayed close since many of the functions that call this + one do not check the return code. They do not allow for the + possibility that an I/O error may have caused the client to be + deleted. */ + client->t_suicide = thread_add_event(zebrad.master, zserv_delayed_close, + client, 0); + return -1; + break; + case BUFFER_EMPTY: + THREAD_OFF(client->t_write); + break; + case BUFFER_PENDING: + THREAD_WRITE_ON(zebrad.master, client->t_write, + zserv_flush_data, client, client->sock); + break; + } return 0; } @@ -194,7 +168,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) /* Check this client need interface information. */ if (! client->ifinfo) - return -1; + return 0; s = client->obuf; stream_reset (s); @@ -225,9 +199,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } /* Interface deletion from zebra daemon. */ @@ -244,7 +216,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) /* Check this client need interface information. */ if (! client->ifinfo) - return -1; + return 0; s = client->obuf; stream_reset (s); @@ -266,9 +238,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) /* Write packet length. */ stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message (client); } #endif /* (defined(RTM_IFANNOUNCE) || defined(HAVE_LINUX_RTNETLINK_H)) */ @@ -320,7 +290,7 @@ zsend_interface_address (int cmd, struct zserv *client, /* Check this client need interface information. */ if (! client->ifinfo) - return -1; + return 0; s = client->obuf; stream_reset (s); @@ -357,9 +327,7 @@ zsend_interface_address (int cmd, struct zserv *client, /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } /* @@ -379,7 +347,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) /* Check this client need interface information. */ if (! client->ifinfo) - return -1; + return 0; s = client->obuf; stream_reset (s); @@ -403,9 +371,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } /* @@ -531,13 +497,11 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } #ifdef HAVE_IPV6 -int +static int zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) { struct stream *s; @@ -598,9 +562,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } #endif /* HAVE_IPV6 */ @@ -660,9 +622,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } static int @@ -721,9 +681,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) stream_putw_at (s, 0, stream_get_endp (s)); - zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); - - return 0; + return zebra_server_send_message(client); } /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ @@ -735,7 +693,7 @@ zsend_router_id_update (struct zserv *client, struct prefix *p) /* Check this client need interface information. */ if (!client->ridinfo) - return -1; + return 0; s = client->obuf; stream_reset (s); @@ -755,12 +713,12 @@ zsend_router_id_update (struct zserv *client, struct prefix *p) /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); - return writen (client->sock, s->data, stream_get_endp (s)); + return zebra_server_send_message(client); } /* Register zebra server interface information. Send current all interface and address information. */ -static void +static int zread_interface_add (struct zserv *client, u_short length) { struct listnode *ifnode; @@ -779,23 +737,27 @@ zread_interface_add (struct zserv *client, u_short length) if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) continue; - zsend_interface_add (client, ifp); + if (zsend_interface_add (client, ifp) < 0) + return -1; for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { c = getdata (cnode); - if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL)) - zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, - ifp, c); + if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL) && + (zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, + ifp, c) < 0)) + return -1; } } + return 0; } /* Unregister zebra server interface information. */ -static void +static int zread_interface_delete (struct zserv *client, u_short length) { client->ifinfo = 0; + return 0; } /* This function support multiple nexthop. */ @@ -803,7 +765,7 @@ zread_interface_delete (struct zserv *client, u_short length) * Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update rib and * add kernel route. */ -static void +static int zread_ipv4_add (struct zserv *client, u_short length) { int i; @@ -878,10 +840,11 @@ zread_ipv4_add (struct zserv *client, u_short length) rib->metric = stream_getl (s); rib_add_ipv4_multipath (&p, rib); + return 0; } /* Zebra server IPv4 prefix delete function. */ -static void +static int zread_ipv4_delete (struct zserv *client, u_short length) { int i; @@ -951,20 +914,21 @@ zread_ipv4_delete (struct zserv *client, u_short length) rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table); + return 0; } /* Nexthop lookup for IPv4. */ -static void +static int zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) { struct in_addr addr; addr.s_addr = stream_get_ipv4 (client->ibuf); - zsend_ipv4_nexthop_lookup (client, addr); + return zsend_ipv4_nexthop_lookup (client, addr); } /* Nexthop lookup for IPv4. */ -static void +static int zread_ipv4_import_lookup (struct zserv *client, u_short length) { struct prefix_ipv4 p; @@ -973,12 +937,12 @@ zread_ipv4_import_lookup (struct zserv *client, u_short length) p.prefixlen = stream_getc (client->ibuf); p.prefix.s_addr = stream_get_ipv4 (client->ibuf); - zsend_ipv4_import_lookup (client, &p); + return zsend_ipv4_import_lookup (client, &p); } #ifdef HAVE_IPV6 /* Zebra server IPv6 prefix add function. */ -static void +static int zread_ipv6_add (struct zserv *client, u_short length) { int i; @@ -1039,10 +1003,11 @@ zread_ipv6_add (struct zserv *client, u_short length) rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); else rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0); + return 0; } /* Zebra server IPv6 prefix delete function. */ -static void +static int zread_ipv6_delete (struct zserv *client, u_short length) { int i; @@ -1102,46 +1067,10 @@ zread_ipv6_delete (struct zserv *client, u_short length) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0); + return 0; } -void -zebra_read_ipv6 (int command, struct zserv *client, u_short length) -{ - u_char type; - u_char flags; - struct in6_addr nexthop, *gate; - unsigned int ifindex; - - type = stream_getc (client->ibuf); - flags = stream_getc (client->ibuf); - stream_get (&nexthop, client->ibuf, sizeof (struct in6_addr)); - - while (STREAM_READABLE (client->ibuf)) - { - int size; - struct prefix_ipv6 p; - - ifindex = stream_getl (client->ibuf); - - memset (&p, 0, sizeof (struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = stream_getc (client->ibuf); - size = PSIZE(p.prefixlen); - stream_get (&p.prefix, client->ibuf, size); - - if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - gate = NULL; - else - gate = &nexthop; - - if (command == ZEBRA_IPV6_ROUTE_ADD) - rib_add_ipv6 (type, flags, &p, gate, ifindex, 0); - else - rib_delete_ipv6 (type, flags, &p, gate, ifindex, 0); - } -} - -static void +static int zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) { struct in6_addr addr; @@ -1150,12 +1079,12 @@ zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) stream_get (&addr, client->ibuf, 16); printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); - zsend_ipv6_nexthop_lookup (client, &addr); + return zsend_ipv6_nexthop_lookup (client, &addr); } #endif /* HAVE_IPV6 */ /* Register zebra server router-id information. Send current router-id */ -void +static int zread_router_id_add (struct zserv *client, u_short length) { struct prefix p; @@ -1165,14 +1094,15 @@ zread_router_id_add (struct zserv *client, u_short length) router_id_get (&p); - zsend_router_id_update (client,&p); + return zsend_router_id_update (client,&p); } /* Unregister zebra server router-id information. */ -void +static int zread_router_id_delete (struct zserv *client, u_short length) { client->ridinfo = 0; + return 0; } /* Close zebra client. */ @@ -1191,12 +1121,16 @@ zebra_client_close (struct zserv *client) stream_free (client->ibuf); if (client->obuf) stream_free (client->obuf); + if (client->wb) + buffer_free(client->wb); /* Release threads. */ if (client->t_read) thread_cancel (client->t_read); if (client->t_write) thread_cancel (client->t_write); + if (client->t_suicide) + thread_cancel (client->t_suicide); /* Free client structure. */ listnode_delete (zebrad.client_list, client); @@ -1215,6 +1149,7 @@ zebra_client_create (int sock) client->sock = sock; client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + client->wb = buffer_new(0); /* Set table number. */ client->rtm_table = zebrad.rtm_table_default; @@ -1241,41 +1176,68 @@ zebra_client_read (struct thread *thread) client = THREAD_ARG (thread); client->t_read = NULL; - /* Read length and command. */ - nbyte = stream_read (client->ibuf, sock, 3); - if (nbyte <= 0) + if (client->t_suicide) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug ("connection closed socket [%d]", sock); - zebra_client_close (client); + zebra_client_close(client); return -1; } + + /* Read length and command (if we don't have it already). */ + if (stream_get_endp(client->ibuf) < ZEBRA_HEADER_SIZE) + { + if (((nbyte = stream_read_try (client->ibuf, sock, + ZEBRA_HEADER_SIZE)) == 0) || + (nbyte == -1)) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug ("connection closed socket [%d]", sock); + zebra_client_close (client); + return -1; + } + if (stream_get_endp(client->ibuf) < ZEBRA_HEADER_SIZE) + { + /* Try again later. */ + zebra_event (ZEBRA_READ, sock, client); + return 0; + } + } + + /* Reset to read from the beginning of the incoming packet. */ + stream_set_getp(client->ibuf, 0); + length = stream_getw (client->ibuf); command = stream_getc (client->ibuf); - if (length < 3) + if (length < ZEBRA_HEADER_SIZE) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug ("length %d is less than 3 ", length); + zlog_debug ("length %d is less than %d ", length, ZEBRA_HEADER_SIZE); zebra_client_close (client); return -1; } - length -= 3; - /* Read rest of data. */ - if (length) + if (stream_get_endp(client->ibuf) < length) { - nbyte = stream_read (client->ibuf, sock, length); - if (nbyte <= 0) + nbyte = stream_read_try (client->ibuf, sock, + length-stream_get_endp(client->ibuf)); + if ((nbyte == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed [%d] when reading zebra data", sock); zebra_client_close (client); return -1; } + if (stream_get_endp(client->ibuf) < length) + { + /* Try again later. */ + zebra_event (ZEBRA_READ, sock, client); + return 0; + } } + length -= ZEBRA_HEADER_SIZE; + /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("zebra message comes from socket [%d]", sock); @@ -1340,9 +1302,15 @@ zebra_client_read (struct thread *thread) break; } + if (client->t_suicide) + { + /* No need to wait for thread callback, just kill immediately. */ + zebra_client_close(client); + return -1; + } + stream_reset (client->ibuf); zebra_event (ZEBRA_READ, sock, client); - return 0; } @@ -1351,7 +1319,6 @@ zebra_client_read (struct thread *thread) static int zebra_accept (struct thread *thread) { - int val; int accept_sock; int client_sock; struct sockaddr_in client; @@ -1359,6 +1326,9 @@ zebra_accept (struct thread *thread) accept_sock = THREAD_FD (thread); + /* Reregister myself. */ + zebra_event (ZEBRA_SERV, accept_sock, NULL); + len = sizeof (struct sockaddr_in); client_sock = accept (accept_sock, (struct sockaddr *) &client, &len); @@ -1369,20 +1339,11 @@ zebra_accept (struct thread *thread) } /* Make client socket non-blocking. */ - /* XXX: We dont requeue failed writes, so this leads to inconsistencies. - * for now socket must remain blocking, regardless of risk of deadlocks. - */ - /* - val = fcntl (client_sock, F_GETFL, 0); - fcntl (client_sock, F_SETFL, (val | O_NONBLOCK)); - */ + set_nonblocking(client_sock); /* Create new zebra client. */ zebra_client_create (client_sock); - /* Register myself. */ - zebra_event (ZEBRA_SERV, accept_sock, NULL); - return 0; } @@ -1718,7 +1679,7 @@ DEFUN (no_ipv6_forwarding, #endif /* HAVE_IPV6 */ /* IPForwarding configuration write function. */ -int +static int config_write_forwarding (struct vty *vty) { /* FIXME: Find better place for that. */ @@ -1779,7 +1740,4 @@ zebra_init () install_element (CONFIG_NODE, &ipv6_forwarding_cmd); install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd); #endif /* HAVE_IPV6 */ - - FIFO_INIT(&message_queue); - t_write = NULL; } diff --git a/zebra/zserv.h b/zebra/zserv.h index 620e24dd..445dc766 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -41,10 +41,16 @@ struct zserv struct stream *ibuf; struct stream *obuf; + /* Buffer of data waiting to be written to client. */ + struct buffer *wb; + /* Threads for read/write. */ struct thread *t_read; struct thread *t_write; + /* Thread for delayed close. */ + struct thread *t_suicide; + /* default routing table this client munges */ int rtm_table; |