diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/memtypes.c | 3 | ||||
-rw-r--r-- | lib/mqueue.c | 103 | ||||
-rw-r--r-- | lib/mqueue.h | 55 | ||||
-rw-r--r-- | lib/qafi_safi.h | 151 | ||||
-rw-r--r-- | lib/qpselect.c | 2 | ||||
-rw-r--r-- | lib/qpselect.h | 30 | ||||
-rw-r--r-- | lib/qpthreads.c | 50 | ||||
-rw-r--r-- | lib/qpthreads.h | 4 | ||||
-rw-r--r-- | lib/sockopt.c | 181 | ||||
-rw-r--r-- | lib/sockunion.c | 378 | ||||
-rw-r--r-- | lib/sockunion.h | 23 | ||||
-rw-r--r-- | lib/stream.c | 373 | ||||
-rw-r--r-- | lib/stream.h | 21 | ||||
-rw-r--r-- | lib/symtab.h | 16 | ||||
-rw-r--r-- | lib/zebra.h | 33 |
16 files changed, 993 insertions, 432 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 8f518f05..d6d3022a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -31,7 +31,7 @@ pkginclude_HEADERS = \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h symtab.h heap.h \ qtime.h qpthreads.h mqueue.h qpselect.h qtimers.h qpnexus.h \ - command_queue.h qlib_init.h + command_queue.h qlib_init.h qafi_safi.h EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt diff --git a/lib/memtypes.c b/lib/memtypes.c index 81acb205..c55a2cb7 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -114,6 +114,9 @@ struct memory_list memory_list_bgp[] = { MTYPE_PEER_GROUP, "Peer group" }, { MTYPE_PEER_DESC, "Peer description" }, { MTYPE_PEER_PASSWORD, "Peer password string" }, + { MTYPE_BGP_SESSION, "BGP session" }, + { MTYPE_BGP_CONNECTION, "BGP connection" }, + { MTYPE_BGP_NOTIFY, "BGP notification" }, { MTYPE_ATTR, "BGP attribute" }, { MTYPE_ATTR_EXTRA, "BGP extra attributes" }, { MTYPE_AS_PATH, "BGP aspath" }, diff --git a/lib/mqueue.c b/lib/mqueue.c index 5afe902a..1e5e8be5 100644 --- a/lib/mqueue.c +++ b/lib/mqueue.c @@ -85,6 +85,13 @@ * For specific revoke, arg0 is assumed to identify the messages to be * revoked. * + *============================================================================== + * Local Queues + * + * A local queue may be used within a thread to requeue messages for later + * processing. + * + * Local queues are very simple FIFO queues. */ /*============================================================================== @@ -93,7 +100,8 @@ * TODO: how to shut down a message queue... for reset/exit ? */ -/* Initialise new Message Queue, if required (mq == NULL) allocating it. +/*------------------------------------------------------------------------------ + * Initialise new Message Queue, if required (mq == NULL) allocating it. * * For mqt_cond_xxx type queues, sets the default timeout interval and the * initial timeout time to now + that interval. @@ -143,7 +151,59 @@ mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type) return mq ; } ; -/* Set new timeout interval (or unset by setting <= 0) +/*------------------------------------------------------------------------------ + * Initialise new Local Message Queue, if required (lmq == NULL) allocating it. + * + * Returns address of Local Message Queue + */ +extern mqueue_local_queue +mqueue_local_init_new(mqueue_local_queue lmq) +{ + if (lmq == NULL) + lmq = XCALLOC(MTYPE_MQUEUE_QUEUE, sizeof(struct mqueue_local_queue)) ; + else + memset(lmq, 0, sizeof(struct mqueue_local_queue)) ; + + /* Zeroising the structure is enough to initialise: + * + * * head -- NULL + * * tail -- NULL + */ + + return lmq ; +} ; + +/*------------------------------------------------------------------------------ + * Reset Local Message Queue, and if required free it. + * + * Dequeues entries and dispatches them "mqb_revoke", to empty the queue. + * + * See: mqueue_local_reset_keep(lmq) + * mqueue_local_reset_free(lmq) + * + * Returns address of Local Message Queue + */ +extern mqueue_local_queue +mqueue_local_reset(mqueue_local_queue lmq, int free_structure) +{ + mqueue_block mqb ; + + while ((mqb = lmq->head) != NULL) + { + lmq->head = mqb->next ; + mqueue_dispatch_destroy(mqb) ; + } ; + + if (free_structure) + XFREE(MTYPE_MQUEUE_QUEUE, lmq) ; /* sets lmq = NULL */ + else + memset(lmq, 0, sizeof(struct mqueue_local_queue)) ; + + return lmq ; +} ; + +/*------------------------------------------------------------------------------ + * Set new timeout interval (or unset by setting <= 0) * * Sets the next timeout to be the time now + new interval (or never). * @@ -260,7 +320,8 @@ mqueue_block_new_lot(void) static void mqueue_kick_signal(mqueue_queue mq, unsigned n) ; static void mqueue_dequeue_signal(mqueue_queue mq, mqueue_thread_signal mtsig) ; -/* Enqueue message. +/*------------------------------------------------------------------------------ + * Enqueue message. * * If priority != 0, will enqueue after any previously enqueued priority * messages. @@ -283,7 +344,6 @@ static void mqueue_dequeue_signal(mqueue_queue mq, mqueue_thread_signal mtsig) ; * NB: this works perfectly well if !qpthreads enabled. Of course, there can * never be any waiters... so no kicking is ever done. */ - void mqueue_enqueue(mqueue_queue mq, mqueue_block mqb, int priority) { @@ -353,7 +413,8 @@ mqueue_enqueue(mqueue_queue mq, mqueue_block mqb, int priority) qpt_mutex_unlock(&mq->mutex) ; } ; -/* Dequeue message. +/*------------------------------------------------------------------------------ + * Dequeue message. * * If the queue is empty and wait != 0 (and qpthreads_enabled), will wait for a * message. In which case for: @@ -378,7 +439,6 @@ mqueue_enqueue(mqueue_queue mq, mqueue_block mqb, int priority) * * Returns a message block if one is available. (And not otherwise.) */ - mqueue_block mqueue_dequeue(mqueue_queue mq, int wait, void* arg) { @@ -471,7 +531,8 @@ done: return mqb ; } ; -/* No longer waiting for a signal -- does nothing if !qpthreads_enabled. +/*------------------------------------------------------------------------------ + * No longer waiting for a signal -- does nothing if !qpthreads_enabled. * * Returns true <=> signal has been kicked * @@ -507,6 +568,34 @@ mqueue_done_waiting(mqueue_queue mq, mqueue_thread_signal mtsig) return kicked ; } ; +/*------------------------------------------------------------------------------ + * Enqueue message on local queue + */ +extern void +mqueue_local_enqueue(mqueue_local_queue lmq, mqueue_block mqb) +{ + if (lmq->head == NULL) + lmq->head = mqb ; + else + lmq->tail->next = mqb ; + lmq->tail = mqb ; + mqb->next = NULL ; +} ; + +/*------------------------------------------------------------------------------ + * Dequeue message from local queue -- returns NULL if empty + */ +extern mqueue_block +mqueue_local_dequeue(mqueue_local_queue lmq) +{ + mqueue_block mqb = lmq->head ; + + if (mqb != NULL) + lmq->head = mqb->next ; + + return mqb ; +} ; + /*============================================================================== * Message queue signal handling */ diff --git a/lib/mqueue.h b/lib/mqueue.h index 7d649efe..fb28eea1 100644 --- a/lib/mqueue.h +++ b/lib/mqueue.h @@ -50,7 +50,7 @@ typedef union enum mqb_flag { - mqb_revoke = 0, + mqb_destroy = 0, mqb_action = 1 } ; @@ -122,37 +122,60 @@ struct mqueue_queue } kick ; } ; +typedef struct mqueue_local_queue* mqueue_local_queue ; + +struct mqueue_local_queue +{ + mqueue_block head ; /* NULL => list is empty */ + mqueue_block tail ; /* last message (if not empty) */ +} ; + /*============================================================================== * Functions */ -void +extern void mqueue_initialise(void) ; -mqueue_queue +extern mqueue_queue mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type) ; -void +extern mqueue_local_queue +mqueue_local_init_new(mqueue_local_queue lmq) ; + +extern mqueue_local_queue +mqueue_local_reset(mqueue_local_queue lmq, int free_structure) ; + +#define mqueue_local_reset_keep(lmq) mqueue_local_reset(lmq, 0) +#define mqueue_local_reset_free(lmq) mqueue_local_reset(lmq, 1) + +extern void mqueue_set_timeout_interval(mqueue_queue mq, qtime_t interval) ; -mqueue_thread_signal +extern mqueue_thread_signal mqueue_thread_signal_init(mqueue_thread_signal mqt, qpt_thread_t thread, int signum) ; -mqueue_block +extern mqueue_block mqb_init_new(mqueue_block mqb, mqueue_action action, void* arg0) ; -void +extern void mqb_free(mqueue_block mqb) ; -void +extern void mqueue_enqueue(mqueue_queue mq, mqueue_block mqb, int priority) ; -mqueue_block +extern mqueue_block mqueue_dequeue(mqueue_queue mq, int wait, void* arg) ; -int +extern int mqueue_done_waiting(mqueue_queue mq, mqueue_thread_signal mtsig) ; +extern void +mqueue_local_enqueue(mqueue_local_queue lmq, mqueue_block mqb) ; + +extern mqueue_block +mqueue_local_dequeue(mqueue_local_queue lmq) ; + /*============================================================================== * Access functions for mqueue_block fields -- mqb_set_xxx/mqb_get_xxx * @@ -217,6 +240,18 @@ mqb_dispatch(mqueue_block mqb, mqb_flag_t flag) mqb->action(mqb, flag) ; } ; +Inline void +mqb_dispatch_action(mqueue_block mqb) +{ + mqb->action(mqb, mqb_action) ; +} ; + +Inline void +mqb_dispatch_destroy(mqueue_block mqb) +{ + mqb->action(mqb, mqb_destroy) ; +} ; + Inline void* mqb_get_arg0(mqueue_block mqb) { diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h new file mode 100644 index 00000000..bf0f0360 --- /dev/null +++ b/lib/qafi_safi.h @@ -0,0 +1,151 @@ +/* Quagga AFI/SAFI + * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro + * Copyright (C) 2009 Chris Hall (GMCH), Highwayman + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _QUAGGA_AFI_SAFI_H +#define _QUAGGA_AFI_SAFI_H + +#include <stdint.h> +#include "lib/zassert.h" + +/*============================================================================== + * Generic AFI and SAFI types. + */ +typedef uint16_t afi_t; +typedef uint8_t safi_t; + +/*============================================================================== + * iAFI and iSAFI + * + * These are the standard IANA registered AFI and SAFI values that Quagga is + * at all interested in. + */ + +typedef enum iAFI iAFI_t ; + +enum iAFI +{ + iAFI_Reserved = 0, /* No meaning defined by IANA */ + + iAFI_IP = 1, /* IP (IP version 4) */ + iAFI_IP6 = 2, /* IP6 (IP version 6) */ + + iAFI_IPV4 = iAFI_IP, /* locally AKA */ + iAFI_IPV6 = iAFI_IP6 /* locally AKA */ +} ; + + +typedef enum iSAFI iSAFI_t ; + +enum iSAFI +{ + iSAFI_Reserved = 0, /* No meaning defined by IANA */ + + iSAFI_Unicast = 1, /* unicast forwarding */ + iSAFI_Multicast = 2, /* multicast forwarding */ + + iSAFI_Unused = 3, /* also Reserved by IANA */ + + iSAFI_MPLS_VPN = 128 /* MPLS-labeled VPN address */ +} ; + +/*============================================================================== + * qAFI and qSAFI + * + * These are the AFI and SAFI values that Quagga uses internally. + * + * They are almost the same as the IANA numbers, but different where that + * is required to produce a dense set. + */ + +typedef enum qAFI qAFI_t ; + +enum qAFI +{ + qAFI_min = 0, /* minimum valid qAFI */ + qAFI_undef = 0, /* undefined AFI */ + + qAFI_first = 1, /* first real qAFI */ + + qAFI_IP = 1, + qAFI_IP6 = 2, + + qAFI_last = 2, /* last real qAFI */ + + qAFI_max = 2, /* maximum valid qAFI */ + qAFI_count, /* number of distinct qAFI */ + + qAFI_IPV4 = qAFI_IP, + qAFI_IPV6 = qAFI_IP6 +} ; + +typedef enum qSAFI qSAFI_t ; + +enum qSAFI +{ + qSAFI_min = 1, /* minimum valid qSAFI */ + qSAFI_undef = 0, /* undefined SAFI */ + + qSAFI_first = 1, /* first real qSAFI */ + + qSAFI_Unicast = 1, + qSAFI_Multicast = 2, + qSAFI_Unused = 3, + qSAFI_MPLS_VPN = 4, + + qSAFI_last = 4, /* last real qSAFI */ + + qSAFI_max = 4, /* maximum valid qSAFI */ + qSAFI_count /* number of distinct qSAFI */ +} ; + +/*============================================================================== + * Quagga AFI/SAFI values -- original macro definitions + */ + +/* Address family numbers from RFC1700. */ +#define AFI_IP 1 +#define AFI_IP6 2 +#define AFI_MAX 3 + +CONFIRM( (AFI_IP == qAFI_IP) + && (AFI_IP == iAFI_IP) ) ; +CONFIRM( (AFI_IP6 == qAFI_IP6) + && (AFI_IP6 == iAFI_IP6) ) ; +CONFIRM(AFI_MAX == qAFI_count) ; + +/* Subsequent Address Family Identifier. */ +#define SAFI_UNICAST 1 +#define SAFI_MULTICAST 2 +#define SAFI_UNICAST_MULTICAST 3 +#define SAFI_MPLS_VPN 4 +#define SAFI_MAX 5 + +CONFIRM( (SAFI_UNICAST == qSAFI_Unicast) + && (SAFI_UNICAST == iSAFI_Unicast) ) ; +CONFIRM( (SAFI_MULTICAST == qSAFI_Multicast) + && (SAFI_MULTICAST == iSAFI_Multicast) ) ; +CONFIRM( (SAFI_UNICAST_MULTICAST == qSAFI_Unused) + && (SAFI_UNICAST_MULTICAST == iSAFI_Unused) ) ; +CONFIRM(SAFI_MPLS_VPN == qSAFI_MPLS_VPN) ; +CONFIRM(SAFI_MAX == qSAFI_count) ; + +#endif /* _QUAGGA_AFI_SAFI_H */ diff --git a/lib/qpselect.c b/lib/qpselect.c index fb02f0fa..a281a61d 100644 --- a/lib/qpselect.c +++ b/lib/qpselect.c @@ -457,6 +457,8 @@ qps_file_init_new(qps_file qf, qps_file template) * actions[] -- all set to NULL */ + qf->fd = fd_undef ; /* no fd set yet */ + if (template != NULL) memcpy(qf->actions, template->actions, sizeof(qf->actions)) ; diff --git a/lib/qpselect.h b/lib/qpselect.h index 1e67d174..aec56c38 100644 --- a/lib/qpselect.h +++ b/lib/qpselect.h @@ -67,6 +67,9 @@ enum qps_mbits /* "mode" bits: error/read/write */ typedef enum qps_mbits qps_mbit_t ; +/* "fd_undef" -- used when fd is undefined */ +enum { fd_undef = -1 } ; + /* Forward references */ typedef struct qps_selection* qps_selection ; typedef struct qps_file* qps_file ; @@ -205,4 +208,31 @@ qps_set_action(qps_file qf, qps_mnum_t mnum, qps_action* action) ; void qps_disable_modes(qps_file qf, qps_mbit_t mbits) ; +Inline void* +qps_file_info(qps_file qf) +{ + return qf->file_info ; +} ; + +Inline int +qps_file_fd(qps_file qf) +{ + return qf->fd ; +} ; + +Inline int +qps_file_unset_fd(qps_file qf) +{ + int fd = qf->fd ; + qf->fd = fd_undef ; + + return fd ; +} ; + +Inline void +qps_set_file_info(qps_file qf, void* info) +{ + qf->file_info = info ; +} ; + #endif /* _ZEBRA_QPSELECT_H */ diff --git a/lib/qpthreads.c b/lib/qpthreads.c index ba6e20be..e7b39f6d 100644 --- a/lib/qpthreads.c +++ b/lib/qpthreads.c @@ -24,6 +24,7 @@ #include "config.h" #include <signal.h> +#include <string.h> #include "qpthreads.h" #include "memory.h" @@ -56,14 +57,34 @@ * A big Global Switch -- qpthreads_enabled -- is used to control whether the * system is pthreaded or not. * + * The initial state is qpthreads_enabled == false (0). + * + * The function qpt_set_qpthreads_enabled() should be called when the + * application has decided whether to use qpthreads or not. (But does not have + * to call this if it is happy to proceed in the default -- disabled -- state.) + * * If this is never set, then the system runs without pthreads, and all the * mutex and condition variable functions are NOPs. This allows, for example, * mutex operations to be placed where they are needed for thread-safety, * without affecting the code when running without pthreads. * - * Before the first thread is created and before any mutexes or condition - * variables are initialised, the qpthreads_enabled MUST be set. And it MUST - * not be changed again ! + * There are a very few operations which require qpthreads_enabled: + * + * * qpt_thread_attr_init + * * qpt_thread_create + * + * A few operations "freeze" the state of qpthreads_enabled. Any call of these + * before qpthreads are enabled, causes the state to be frozen, disabled. This + * means that any later attempt to enable qpthreads will be refused. These + * operations are: + * + * * qpt_mutex_init_new + * * qpt_cond_init_new + * + * This allows the application to decide as late as possible (but no later) + * whether to enable pthreads. If a mutex or a condition variable has been + * initialised before the application gets around to enabling qpthreads, that + * will be trapped when qpthreads is finally enabled. * * Pthread Requirements * ==================== @@ -231,25 +252,27 @@ enum qpthreads_enabled_state qpt_state_set_enabled = 3, } ; -static enum qpthreads_enabled_state qpthreads_enabled_state = qpt_state_unset ; +static enum qpthreads_enabled_state qpthreads_enabled_state = qpt_state_unset ; int qpthreads_enabled_flag = 0 ; /* Function to set qpthreads_enabled, one way or the other. * + * Returns: true <=> successful set the required state. + * false <=> it is too late to enable qpthreads :-( + * * NB: can repeatedly set to the same state, but not change state once set. */ -void +extern int qpt_set_qpthreads_enabled(int how) { - switch (qpthreads_enabled_state) { case qpt_state_unset: break ; case qpt_state_set_frozen: if (how != 0) - zabort("Too late to enable qpthreads") ; + return 0 ; break ; case qpt_state_set_disabled: if (how != 0) @@ -266,6 +289,7 @@ qpt_set_qpthreads_enabled(int how) qpthreads_enabled_flag = (how != 0) ; qpthreads_enabled_state = (how != 0) ? qpt_state_set_enabled : qpt_state_set_disabled ; + return 1 ; } ; /* Get state of qpthreads_enabled, and freeze if not yet explictly set. @@ -490,7 +514,11 @@ qpt_mutex_init_new(qpt_mutex mx, enum qpt_mutex_options opts) int err ; if (!qpthreads_enabled_freeze) - return mx ; + { + if (mx != NULL) + memset(mx, 0x0F, sizeof(qpt_mutex_t)) ; + return mx ; + } ; if (mx == NULL) mx = XMALLOC(MTYPE_QPT_MUTEX, sizeof(qpt_mutex_t)) ; @@ -592,7 +620,11 @@ qpt_cond_init_new(qpt_cond cv, enum qpt_cond_options opts) int err ; if (!qpthreads_enabled_freeze) - return cv ; + { + if (cv != NULL) + memset(cv, 0x0F, sizeof(qpt_cond_t)) ; + return cv ; + } ; if (cv == NULL) cv = XMALLOC(MTYPE_QPT_COND, sizeof(qpt_cond_t)) ; diff --git a/lib/qpthreads.h b/lib/qpthreads.h index 2fbbea9a..aaf8e5dd 100644 --- a/lib/qpthreads.h +++ b/lib/qpthreads.h @@ -67,7 +67,7 @@ * * Early in the morning a decision may be made to enable qpthreads -- that must * be done before any threads are created (or will zabort) and before any - * mutexes and condition variables are initialised. + * mutexes and condition variables are initialised (or it will be too late). * * Use: qpthreads_enabled -- to test for the enabled-ness * qpthreads_enabled_freeze -- to test and freeze unset if not yet enabled @@ -131,7 +131,7 @@ qpt_thread_join(qpt_thread_t thread_id) ; */ private int qpthreads_enabled_flag ; /* DO NOT WRITE TO THIS PLEASE */ -private void +private int qpt_set_qpthreads_enabled(int how) ; /* qpthreads_enabled := how */ private int diff --git a/lib/sockopt.c b/lib/sockopt.c index 55c6226b..1f84aaca 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #include <zebra.h> @@ -28,7 +28,7 @@ int setsockopt_so_recvbuf (int sock, int size) { int ret; - + if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int))) < 0) zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s", @@ -42,7 +42,7 @@ setsockopt_so_sendbuf (const int sock, int size) { int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (int)); - + if (ret < 0) zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s", sock, size, safe_strerror (errno)); @@ -71,8 +71,8 @@ getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) { struct cmsghdr *cmsg; void *ptr = NULL; - - for (cmsg = ZCMSG_FIRSTHDR(msgh); + + for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh, cmsg)) if (cmsg->cmsg_level == level && cmsg->cmsg_type) @@ -87,7 +87,7 @@ int setsockopt_ipv6_pktinfo (int sock, int val) { int ret; - + #ifdef IPV6_RECVPKTINFO /*2292bis-01*/ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); if (ret < 0) @@ -162,7 +162,7 @@ int setsockopt_ipv6_multicast_loop (int sock, int val) { int ret; - + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof (val)); if (ret < 0) @@ -174,9 +174,9 @@ static int getsockopt_ipv6_ifindex (struct msghdr *msgh) { struct in6_pktinfo *pktinfo; - + pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO); - + return pktinfo->ipi6_ifindex; } #endif /* HAVE_IPV6 */ @@ -204,8 +204,8 @@ getsockopt_ipv6_ifindex (struct msghdr *msgh) * allow leaves, or implicitly leave all groups joined to down interfaces. */ int -setsockopt_multicast_ipv4(int sock, - int optname, +setsockopt_multicast_ipv4(int sock, + int optname, struct in_addr if_addr /* required */, unsigned int mcast_addr, unsigned int ifindex /* optional: if non-zero, may be @@ -216,7 +216,7 @@ setsockopt_multicast_ipv4(int sock, /* This is better because it uses ifindex directly */ struct ip_mreqn mreqn; int ret; - + switch (optname) { case IP_MULTICAST_IF: @@ -226,12 +226,12 @@ setsockopt_multicast_ipv4(int sock, if (mcast_addr) mreqn.imr_multiaddr.s_addr = mcast_addr; - + if (ifindex) mreqn.imr_ifindex = ifindex; else mreqn.imr_address = if_addr; - + ret = setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) @@ -264,7 +264,7 @@ setsockopt_multicast_ipv4(int sock, /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ /* Add your favourite OS here! */ -#else /* #if OS_TYPE */ +#else /* #if OS_TYPE */ /* standard BSD API */ struct in_addr m; @@ -281,7 +281,7 @@ setsockopt_multicast_ipv4(int sock, switch (optname) { case IP_MULTICAST_IF: - return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); + return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); break; case IP_ADD_MEMBERSHIP: @@ -289,7 +289,7 @@ setsockopt_multicast_ipv4(int sock, memset (&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = mcast_addr; mreq.imr_interface = m; - + ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) { @@ -308,7 +308,7 @@ setsockopt_multicast_ipv4(int sock, } return ret; break; - + default: /* Can out and give an understandable error */ errno = EINVAL; @@ -359,7 +359,7 @@ int setsockopt_ifindex (int af, int sock, int val) { int ret = -1; - + switch (af) { case AF_INET: @@ -375,7 +375,7 @@ setsockopt_ifindex (int af, int sock, int val) } return ret; } - + /* * Requires: msgh is not NULL and points to a valid struct msghdr, which * may or may not have control data about the incoming interface. @@ -392,12 +392,12 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) #if defined(IP_PKTINFO) /* Linux pktinfo based ifindex retrieval */ struct in_pktinfo *pktinfo; - - pktinfo = + + pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO); /* XXX Can pktinfo be NULL? Clean up post 0.98. */ ifindex = pktinfo->ipi_ifindex; - + #elif defined(IP_RECVIF) /* retrieval based on IP_RECVIF */ @@ -412,7 +412,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) #ifndef SUNOS_5 /* BSD */ - sdl = + sdl = (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); if (sdl != NULL) ifindex = sdl->sdl_index; @@ -424,7 +424,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) * enable it fails with errno=99, and the struct msghdr has * controllen 0. */ - ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); + ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); if (ifindex_p != NULL) ifindex = *ifindex_p; else @@ -442,7 +442,7 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) #warning "Some daemons may fail to operate correctly!" ifindex = 0; -#endif /* IP_PKTINFO */ +#endif /* IP_PKTINFO */ return ifindex; } @@ -452,7 +452,7 @@ int getsockopt_ifindex (int af, struct msghdr *msgh) { int ifindex = 0; - + switch (af) { case AF_INET: @@ -473,7 +473,7 @@ getsockopt_ifindex (int af, struct msghdr *msgh) void sockopt_iphdrincl_swab_htosys (struct ip *iph) { - /* BSD and derived take iph in network order, except for + /* BSD and derived take iph in network order, except for * ip_len and ip_off */ #ifndef HAVE_IP_HDRINCL_BSD_ORDER @@ -495,9 +495,19 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph) iph->ip_id = ntohs(iph->ip_id); } +/*============================================================================== + * Set TCP MD5 signature socket option. + * + * Returns: 0 => OK + * errno => failed. + * + * NB: returns ENOSYS if TCP MD5 is not supported + */ int sockopt_tcp_signature (int sock, union sockunion *su, const char *password) { + int ret ; + #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX) /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's * version of the Quagga patch (based on work by Rick Payne, and Bruce @@ -513,50 +523,49 @@ sockopt_tcp_signature (int sock, union sockunion *su, const char *password) void *key; /* MD5 Key */ } cmd; struct in_addr *addr = &su->sin.sin_addr; - + cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL); cmd.address = addr->s_addr; - cmd.keylen = (password != NULL ? strlen (password) : 0); - cmd.key = password; - - return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); - + cmd.keylen = (password != NULL ? strlen (password) : 0); + cmd.key = password; + + ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd) ; + + return (ret >= 0) ? 0 : errno ; + #elif HAVE_DECL_TCP_MD5SIG - int ret; #ifndef GNU_LINUX /* * XXX Need to do PF_KEY operation here to add/remove an SA entry, * and add/remove an SP entry for this peer's packet flows also. */ - int md5sig = password && *password ? 1 : 0; + int md5sig = password && *password ? 1 : 0; #else - int keylen = password ? strlen (password) : 0; - struct tcp_md5sig md5sig; - union sockunion *su2, *susock; - + int keylen = password ? strlen (password) : 0 ; + struct tcp_md5sig md5sig ; + union sockunion *su2 ; + union sockunion susock ; + /* Figure out whether the socket and the sockunion are the same family.. * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think.. */ - if (!(susock = sockunion_getsockname (sock))) - return -1; - - if (susock->sa.sa_family == su->sa.sa_family) - su2 = su; + if ((ret = sockunion_getsockname(sock, &susock)) != 0) + return ret ; + + if (susock.sa.sa_family == su->sa.sa_family) + su2 = su ; else { /* oops.. */ - su2 = susock; - + su2 = &susock ; + if (su2->sa.sa_family == AF_INET) - { - sockunion_free (susock); - return 0; - } - + return 0 ; /* TODO: find out what this is doing ?? */ + #ifdef HAVE_IPV6 /* If this does not work, then all users of this sockopt will need to * differentiate between IPv4 and IPv6, and keep seperate sockets for - * each. + * each. * * Sadly, it doesn't seem to work at present. It's unknown whether * this is a bug or not. @@ -572,26 +581,74 @@ sockopt_tcp_signature (int sock, union sockunion *su, const char *password) } #endif } - + memset (&md5sig, 0, sizeof (md5sig)); memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2)); md5sig.tcpm_keylen = keylen; if (keylen) memcpy (md5sig.tcpm_key, password, keylen); - sockunion_free (susock); + #endif /* GNU_LINUX */ - if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0) + + ret = setsockopt(sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig) ; + if (ret < 0) { + ret = errno ; /* ENOENT is harmless. It is returned when we clear a password for which one was not previously set. */ - if (ENOENT == errno) - ret = 0; + if (ret == ENOENT) + ret = 0 ; else zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s", - sock, safe_strerror(errno)); + sock, safe_strerror(ret)); } - return ret; + else + ret = 0 ; /* no error */ + #else /* HAVE_TCP_MD5SIG */ - return -2; + + ret = ENOSYS ; /* TCP MD5 is not supported */ + #endif /* !HAVE_TCP_MD5SIG */ -} + + return ret; +} ; + +/*============================================================================== + * Set TTL for socket (only used in bgpd) + * + * Returns: 0 : OK (so far so good) + * != 0 : error number (from errno or otherwise) + */ + +int +sockopt_ttl (int family, int sock, int ttl) +{ + char* msg ; + int ret ; + + ret = 0 ; + +#ifdef IP_TTL + if (family == AF_INET) + { + ret = setsockopt (sock, IPPROTO_IP, IP_TTL,(void*)&ttl, sizeof(int)); + msg = "can't set sockopt IP_TTL %d to socket %d" ; + } +#endif /* IP_TTL */ +#ifdef HAVE_IPV6 + if (family == AF_INET6) + { + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + (void*)&ttl, sizeof(int)); + msg = "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d" ; + } +#endif /* HAVE_IPV6 */ + + ret = (ret < 0) ? errno : 0 ; + + if (ret != 0) + zlog (NULL, LOG_WARNING, msg, ttl, sock) ; + + return ret ; +} ; diff --git a/lib/sockunion.c b/lib/sockunion.c index 6a40f332..c33a5713 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #include <zebra.h> @@ -28,6 +28,8 @@ #include "str.h" #include "log.h" +#include "symtab.h" + #ifndef HAVE_INET_ATON int inet_aton (const char *cp, struct in_addr *inaddr) @@ -95,13 +97,13 @@ inet_ntop (int family, const void *addrptr, char *strptr, size_t len) { unsigned char *p = (unsigned char *) addrptr; - if (family == AF_INET) + if (family == AF_INET) { char temp[INET_ADDRSTRLEN]; snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - if (strlen(temp) >= len) + if (strlen(temp) >= len) { errno = ENOSPC; return NULL; @@ -231,49 +233,57 @@ static void sockunion_normalise_mapped (union sockunion *su) { struct sockaddr_in sin; - + #ifdef HAVE_IPV6 - if (su->sa.sa_family == AF_INET6 + if (su->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) { memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; - sin.sin_port = su->sin6.sin6_port; + sin.sin_port = su->sin6.sin6_port; memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + memset (su, 0, sizeof(union sockunion)) ; memcpy (su, &sin, sizeof (struct sockaddr_in)); } #endif /* HAVE_IPV6 */ } -/* Return socket of sockunion. */ -int -sockunion_socket (union sockunion *su) -{ - int sock; - - sock = socket (su->sa.sa_family, SOCK_STREAM, 0); - if (sock < 0) - { - zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror (errno)); - return -1; - } - - return sock; -} - -/* Return accepted new socket file descriptor. */ +/*------------------------------------------------------------------------------ + * Return accepted new socket file descriptor. + * + * The following errors should be ignored: + * + * EAGAIN, EWOULDBLOCK or ECONNABORTED -- connection aborted before got + * around to it (or not ready, anyway). + * + * EINTR -- the usual suspect. + * + * Returns: >= 0 -- OK, this is the fd (socket) + * -1 -- error -- not one of the above + * -2 -- error -- one of the above + */ int sockunion_accept (int sock, union sockunion *su) { socklen_t len; - int client_sock; + int ret ; - len = sizeof (union sockunion); - client_sock = accept (sock, (struct sockaddr *) su, &len); - - sockunion_normalise_mapped (su); - return client_sock; -} + len = sizeof(union sockunion); + memset(su, 0, len) ; + ret = accept(sock, (struct sockaddr *)su, &len) ; + + if (client_sock >= 0) + { + sockunion_normalise_mapped(su); + return ret ; /* OK -- got socket */ + } ; + + ret = errno ; + return ( (ret == EAGAIN) + || (ret == EWOULDBLOCK) + || (ret == ECONNABORTED) + || (ret == EINTR) ) ? -2 : -1 ; +} ; /* Return sizeof union sockunion. */ static int @@ -302,7 +312,7 @@ sockunion_log (union sockunion *su) { static char buf[SU_ADDRSTRLEN]; - switch (su->sa.sa_family) + switch (su->sa.sa_family) { case AF_INET: snprintf (buf, SU_ADDRSTRLEN, "%s", inet_ntoa (su->sin.sin_addr)); @@ -320,35 +330,59 @@ sockunion_log (union sockunion *su) return (XSTRDUP (MTYPE_TMP, buf)); } -/* sockunion_connect returns - -1 : error occured - 0 : connect success - 1 : connect is in progress */ -enum connect_result -sockunion_connect (int fd, union sockunion *peersu, unsigned short port, - unsigned int ifindex) +/*============================================================================== + * Return socket of sockunion. (only used in bgpd) + * + * Returns: -1 : failed -- see errno + * otherwise : socket + */ +int +sockunion_socket (union sockunion *su) { - int ret; - int val; - union sockunion su; + int sockfd ; - memcpy (&su, peersu, sizeof (union sockunion)); + sockfd = socket(su->sa.sa_family, SOCK_STREAM, 0); + if (sockfd < 0) + { + zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror(errno)) ; + return -1; + } + + return sockfd ; +} + +/*============================================================================== + * Initiate a connection (only used in bgpd) + * + * Reports EINPROGRESS as success. + * + * Returns: 0 : OK (so far so good) + * != 0 : error number (from errno or otherwise) + */ +extern int +sockunion_connect(int fd, union sockunion* peer_su, unsigned short port, + unsigned int ifindex) +{ + union sockunion su ; + int ret ; + + memcpy(&su, peer_su, sizeof(union sockunion)) ; switch (su.sa.sa_family) { case AF_INET: - su.sin.sin_port = port; + su.sin.sin_port = htons(port) ; break; #ifdef HAVE_IPV6 case AF_INET6: - su.sin6.sin6_port = port; + su.sin6.sin6_port = htons(port) ; #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) { #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ #ifdef MUSICA - su.sin6.sin6_scope_id = ifindex; + su.sin6.sin6_scope_id = ifindex; #endif #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ #ifndef MUSICA @@ -358,37 +392,18 @@ sockunion_connect (int fd, union sockunion *peersu, unsigned short port, #endif /* KAME */ break; #endif /* HAVE_IPV6 */ - } - - /* Make socket non-block. */ - val = fcntl (fd, F_GETFL, 0); - fcntl (fd, F_SETFL, val|O_NONBLOCK); - - /* Call connect function. */ - ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); - - /* Immediate success */ - if (ret == 0) - { - fcntl (fd, F_SETFL, val); - return connect_success; } - /* If connect is in progress then return 1 else it's real error. */ - if (ret < 0) - { - if (errno != EINPROGRESS) - { - zlog_info ("can't connect to %s fd %d : %s", - sockunion_log (&su), fd, safe_strerror (errno)); - return connect_error; - } - } + ret = connect(fd, (struct sockaddr *)&su, sockunion_sizeof(&su)) ; - fcntl (fd, F_SETFL, val); + if ((ret == 0) || ((ret = errno) != EINPROGRESS)) + return 0 ; /* instant success or EINPROGRESS as expected */ - return connect_in_progress; -} + zlog_info("can't connect to %s fd %d : %s", + sockunion_log (&su), fd, safe_strerror(ret)) ; + + return ret ; +} ; /* Make socket from sockunion union. */ int @@ -409,7 +424,7 @@ sockunion_stream_socket (union sockunion *su) /* Bind socket to specified address. */ int -sockunion_bind (int sock, union sockunion *su, unsigned short port, +sockunion_bind (int sock, union sockunion *su, unsigned short port, union sockunion *su_addr) { int size = 0; @@ -443,7 +458,7 @@ sockunion_bind (int sock, union sockunion *su, unsigned short port, } } #endif /* HAVE_IPV6 */ - + ret = bind (sock, (struct sockaddr *)su, size); if (ret < 0) @@ -458,7 +473,7 @@ sockopt_reuseaddr (int sock) int ret; int on = 1; - ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)); if (ret < 0) { @@ -475,7 +490,7 @@ sockopt_reuseport (int sock) int ret; int on = 1; - ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof (on)); if (ret < 0) { @@ -492,41 +507,6 @@ sockopt_reuseport (int sock) } #endif /* 0 */ -int -sockopt_ttl (int family, int sock, int ttl) -{ - int ret; - -#ifdef IP_TTL - if (family == AF_INET) - { - ret = setsockopt (sock, IPPROTO_IP, IP_TTL, - (void *) &ttl, sizeof (int)); - if (ret < 0) - { - zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock); - return -1; - } - return 0; - } -#endif /* IP_TTL */ -#ifdef HAVE_IPV6 - if (family == AF_INET6) - { - ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, - (void *) &ttl, sizeof (int)); - if (ret < 0) - { - zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d", - ttl, sock); - return -1; - } - return 0; - } -#endif /* HAVE_IPV6 */ - return 0; -} - /* If same family and same prefix return 1. */ int sockunion_same (union sockunion *su1, union sockunion *su2) @@ -555,12 +535,19 @@ sockunion_same (union sockunion *su1, union sockunion *su2) return 0; } -/* After TCP connection is established. Get local address and port. */ -union sockunion * -sockunion_getsockname (int fd) +/*------------------------------------------------------------------------------ + * After TCP connection is established. Get local or remote address and port. + * + * Returns: 0 => OK + * != 0 => failed, value = errno + * + * NB: returns EAFNOSUPPORT if don't recognise the address family. + */ +static int +sockunion_get_name(int fd, union sockunion* su, int local) { int ret; - socklen_t len; + union { struct sockaddr sa; @@ -569,82 +556,74 @@ sockunion_getsockname (int fd) struct sockaddr_in6 sin6; #endif /* HAVE_IPV6 */ char tmp_buffer[128]; - } name; - union sockunion *su; + } name ; + + socklen_t len = sizeof(name) ; - memset (&name, 0, sizeof name); - len = sizeof name; + memset(&name, 0, len); + memset(su, 0, sizeof(union sockunion)) ; + + if (local) + ret = getsockname(fd, (struct sockaddr *)&name, &len) ; + else + ret = getpeername(fd, (struct sockaddr *)&name, &len) ; - ret = getsockname (fd, (struct sockaddr *)&name, &len); if (ret < 0) { - zlog_warn ("Can't get local address and port by getsockname: %s", - safe_strerror (errno)); - return NULL; + ret = errno ; + zlog_warn ("Can't get %s address and port: %s", + local ? "local" : "remote", safe_strerror(ret)) ; + return ret ; } - if (name.sa.sa_family == AF_INET) - { - su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); - memcpy (su, &name, sizeof (struct sockaddr_in)); - return su; - } + switch (name.sa.sa_family) + { + case AF_INET: + memcpy(su, &name, sizeof (struct sockaddr_in)) ; + break ; + #ifdef HAVE_IPV6 - if (name.sa.sa_family == AF_INET6) - { - su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); - memcpy (su, &name, sizeof (struct sockaddr_in6)); - sockunion_normalise_mapped (su); - return su; - } + case AF_INET6: + memcpy(su, &name, sizeof (struct sockaddr_in6)) ; + sockunion_normalise_mapped(su) ; + break ; #endif /* HAVE_IPV6 */ - return NULL; -} -/* After TCP connection is established. Get remote address and port. */ -union sockunion * -sockunion_getpeername (int fd) + default: + ret = EAFNOSUPPORT ; + } ; + + return ret ; +} ; + +/*------------------------------------------------------------------------------ + * After TCP connection is established. Get local address and port. + * + * Returns: 0 => OK + * != 0 => failed, value = errno + * + * NB: returns EAFNOSUPPORT if don't recognise the socket's address family. + */ +int +sockunion_getsockname(int fd, union sockunion* su_local) { - int ret; - socklen_t len; - union - { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef HAVE_IPV6 - struct sockaddr_in6 sin6; -#endif /* HAVE_IPV6 */ - char tmp_buffer[128]; - } name; - union sockunion *su; + return sockunion_get_name(fd, su_local, 1) ; +} ; - memset (&name, 0, sizeof name); - len = sizeof name; - ret = getpeername (fd, (struct sockaddr *)&name, &len); - if (ret < 0) - { - zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s", - safe_strerror (errno)); - return NULL; - } +/*------------------------------------------------------------------------------ + * After TCP connection is established. Get remote address and port. + * + * Returns: 0 => OK + * != 0 => failed, value = errno + * + * NB: returns EAFNOSUPPORT if don't recognise the socket's address family. + */ +int +sockunion_getpeername (int fd, union sockunion* su_remote) +{ + return sockunion_get_name(fd, su_remote, 0) ; +} ; - if (name.sa.sa_family == AF_INET) - { - su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); - memcpy (su, &name, sizeof (struct sockaddr_in)); - return su; - } -#ifdef HAVE_IPV6 - if (name.sa.sa_family == AF_INET6) - { - su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); - memcpy (su, &name, sizeof (struct sockaddr_in6)); - sockunion_normalise_mapped (su); - return su; - } -#endif /* HAVE_IPV6 */ - return NULL; -} /* Print sockunion structure */ static void __attribute__ ((unused)) @@ -653,7 +632,7 @@ sockunion_print (union sockunion *su) if (su == NULL) return; - switch (su->sa.sa_family) + switch (su->sa.sa_family) { case AF_INET: printf ("%s\n", inet_ntoa (su->sin.sin_addr)); @@ -744,3 +723,42 @@ sockunion_free (union sockunion *su) { XFREE (MTYPE_SOCKUNION, su); } + +/*============================================================================== + * Clear a given sockunion -- ie zeroise it + */ +extern void +sockunion_clear(union sockunion* su) +{ + memset(su, 0, sizeof(union sockunion)) ; +} ; + +/*============================================================================== + * Symbol Table Hash function -- for symbols whose name is an address. + */ + +extern void +sockunion_symbol_hash(symbol_hash p_hash, const void* name) +{ + const union sockunion* su = name ; + + switch (su->sa.sa_family) + { + case AF_INET: + confirm(sizeof(p_hash->hash) == sizeof(su->sin.sin_addr.s_addr)) ; + p_hash->hash = su->sin.sin_addr.s_addr ; + p_hash->name = (const void*)&su->sin.sin_addr.s_addr ; + p_hash->name_len = sizeof(su->sin.sin_addr.s_addr) ; + p_hash->name_copy_len = sizeof(su->sin.sin_addr.s_addr) ; + break ; + +#ifdef HAVE_IPV6 + case AF_INET6: + symbol_hash_bytes(p_hash, (const void*)&su->sin6.sin6_addr, + sizeof(su->sin6.sin6_addr)) ; + break ; +#endif /* HAVE_IPV6 */ + default: + zabort("Unknown address family") ; + } ; +} ; diff --git a/lib/sockunion.h b/lib/sockunion.h index 96b9a0d4..2009da2f 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -17,12 +17,14 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #ifndef _ZEBRA_SOCKUNION_H #define _ZEBRA_SOCKUNION_H +#include "symtab.h" + #if 0 union sockunion { struct sockinet { @@ -38,7 +40,7 @@ union sockunion { #define su_port su_si.si_port #endif /* 0 */ -union sockunion +union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -99,21 +101,21 @@ extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); extern int sockopt_reuseaddr (int); extern int sockopt_reuseport (int); -extern int sockunion_bind (int sock, union sockunion *, +extern int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); extern int sockopt_ttl (int family, int sock, int ttl); extern int sockunion_socket (union sockunion *su); extern const char *inet_sutop (union sockunion *su, char *str); -extern enum connect_result sockunion_connect (int fd, union sockunion *su, - unsigned short port, - unsigned int); -extern union sockunion *sockunion_getsockname (int); -extern union sockunion *sockunion_getpeername (int); +extern int sockunion_connect (int fd, union sockunion *su, unsigned short port, + unsigned int) ; +extern int sockunion_getsockname (int, union sockunion*); +extern int sockunion_getpeername (int, union sockunion*); extern union sockunion *sockunion_dup (union sockunion *); extern void sockunion_free (union sockunion *); +extern void sockunion_clear(union sockunion*); #ifndef HAVE_INET_NTOP -extern const char * inet_ntop (int family, const void *addrptr, +extern const char * inet_ntop (int family, const void *addrptr, char *strptr, size_t len); #endif /* HAVE_INET_NTOP */ @@ -125,4 +127,7 @@ extern int inet_pton (int family, const char *strptr, void *addrptr); extern int inet_aton (const char *cp, struct in_addr *inaddr); #endif +extern void +sockunion_symbol_hash(symbol_hash p_hash, const void* name) ; + #endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/stream.c b/lib/stream.c index 983330ff..36bbba1e 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #include <stddef.h> @@ -29,7 +29,7 @@ #include "prefix.h" #include "log.h" -/* Tests whether a position is valid */ +/* Tests whether a position is valid */ #define GETP_VALID(S,G) \ ((G) <= (S)->endp) #define PUT_AT_VALID(S,G) GETP_VALID(S,G) @@ -92,24 +92,24 @@ stream_new (size_t size) struct stream *s; assert (size > 0); - + if (size == 0) { zlog_warn ("stream_new(): called with 0 size!"); return NULL; } - + s = XCALLOC (MTYPE_STREAM, sizeof (struct stream)); if (s == NULL) return s; - + if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL) { XFREE (MTYPE_STREAM, s); return NULL; } - + s->size = size; return s; } @@ -120,7 +120,7 @@ stream_free (struct stream *s) { if (!s) return; - + XFREE (MTYPE_STREAM_DATA, s->data); XFREE (MTYPE_STREAM, s); } @@ -129,15 +129,15 @@ struct stream * stream_copy (struct stream *new, struct stream *src) { STREAM_VERIFY_SANE (src); - + assert (new != NULL); assert (STREAM_SIZE(new) >= src->endp); new->endp = src->endp; new->getp = src->getp; - + memcpy (new->data, src->data, src->endp); - + return new; } @@ -154,30 +154,52 @@ stream_dup (struct stream *s) return (stream_copy (new, s)); } +struct stream * +stream_dup_pending (struct stream *s) +{ + struct stream *new; + int new_endp ; + + STREAM_VERIFY_SANE (s); + + new_endp = s->endp - s->getp ; + if ( (new = stream_new(new_endp)) == NULL) + return NULL; + + assert (STREAM_SIZE(new) >= new_endp); + + new->endp = new_endp ; + new->getp = 0 ; + + memcpy (new->data, s->data + s->getp, new_endp) ; + + return new ; +} + size_t stream_resize (struct stream *s, size_t newsize) { u_char *newdata; STREAM_VERIFY_SANE (s); - + newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize); - + if (newdata == NULL) return s->size; - + s->data = newdata; s->size = newsize; - + if (s->endp > s->size) s->endp = s->size; if (s->getp > s->endp) s->getp = s->endp; - + STREAM_VERIFY_SANE (s); - + return s->size; } - + size_t stream_get_getp (struct stream *s) { @@ -204,7 +226,7 @@ void stream_set_getp (struct stream *s, size_t pos) { STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, pos)) { STREAM_BOUND_WARN (s, "set getp"); @@ -219,13 +241,13 @@ void stream_forward_getp (struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, s->getp + size)) { STREAM_BOUND_WARN (s, "seek getp"); return; } - + s->getp += size; } @@ -233,28 +255,28 @@ void stream_forward_endp (struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); - + if (!ENDP_VALID (s, s->endp + size)) { STREAM_BOUND_WARN (s, "seek endp"); return; } - + s->endp += size; } - + /* Copy from stream to destination. */ void stream_get (void *dst, struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); - + if (STREAM_READABLE(s) < size) { STREAM_BOUND_WARN (s, "get"); return; } - + memcpy (dst, s->data + s->getp, size); s->getp += size; } @@ -264,7 +286,7 @@ u_char stream_getc (struct stream *s) { u_char c; - + STREAM_VERIFY_SANE (s); if (STREAM_READABLE(s) < sizeof (u_char)) @@ -273,7 +295,7 @@ stream_getc (struct stream *s) return 0; } c = s->data[s->getp++]; - + return c; } @@ -284,15 +306,15 @@ stream_getc_from (struct stream *s, size_t from) u_char c; STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, from + sizeof (u_char))) { STREAM_BOUND_WARN (s, "get char"); return 0; } - + c = s->data[from]; - + return c; } @@ -309,10 +331,10 @@ stream_getw (struct stream *s) STREAM_BOUND_WARN (s, "get "); return 0; } - + w = s->data[s->getp++] << 8; w |= s->data[s->getp++]; - + return w; } @@ -323,16 +345,16 @@ stream_getw_from (struct stream *s, size_t from) u_int16_t w; STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, from + sizeof (u_int16_t))) { STREAM_BOUND_WARN (s, "get "); return 0; } - + w = s->data[from++] << 8; w |= s->data[from]; - + return w; } @@ -343,18 +365,18 @@ stream_getl_from (struct stream *s, size_t from) u_int32_t l; STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, from + sizeof (u_int32_t))) { STREAM_BOUND_WARN (s, "get long"); return 0; } - + l = s->data[from++] << 24; l |= s->data[from++] << 16; l |= s->data[from++] << 8; l |= s->data[from]; - + return l; } @@ -364,18 +386,18 @@ stream_getl (struct stream *s) u_int32_t l; STREAM_VERIFY_SANE(s); - + if (STREAM_READABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "get long"); return 0; } - + l = s->data[s->getp++] << 24; l |= s->data[s->getp++] << 16; l |= s->data[s->getp++] << 8; l |= s->data[s->getp++]; - + return l; } @@ -386,22 +408,22 @@ stream_getq_from (struct stream *s, size_t from) uint64_t q; STREAM_VERIFY_SANE(s); - + if (!GETP_VALID (s, from + sizeof (uint64_t))) { STREAM_BOUND_WARN (s, "get quad"); return 0; } - + q = ((uint64_t) s->data[from++]) << 56; q |= ((uint64_t) s->data[from++]) << 48; q |= ((uint64_t) s->data[from++]) << 40; - q |= ((uint64_t) s->data[from++]) << 32; + q |= ((uint64_t) s->data[from++]) << 32; q |= ((uint64_t) s->data[from++]) << 24; q |= ((uint64_t) s->data[from++]) << 16; q |= ((uint64_t) s->data[from++]) << 8; q |= ((uint64_t) s->data[from++]); - + return q; } @@ -411,22 +433,22 @@ stream_getq (struct stream *s) uint64_t q; STREAM_VERIFY_SANE(s); - + if (STREAM_READABLE (s) < sizeof (uint64_t)) { STREAM_BOUND_WARN (s, "get quad"); return 0; } - + q = ((uint64_t) s->data[s->getp++]) << 56; q |= ((uint64_t) s->data[s->getp++]) << 48; q |= ((uint64_t) s->data[s->getp++]) << 40; - q |= ((uint64_t) s->data[s->getp++]) << 32; + q |= ((uint64_t) s->data[s->getp++]) << 32; q |= ((uint64_t) s->data[s->getp++]) << 24; q |= ((uint64_t) s->data[s->getp++]) << 16; q |= ((uint64_t) s->data[s->getp++]) << 8; q |= ((uint64_t) s->data[s->getp++]); - + return q; } @@ -437,19 +459,19 @@ stream_get_ipv4 (struct stream *s) u_int32_t l; STREAM_VERIFY_SANE(s); - + if (STREAM_READABLE (s) < sizeof(u_int32_t)) { STREAM_BOUND_WARN (s, "get ipv4"); return 0; } - + memcpy (&l, s->data + s->getp, sizeof(u_int32_t)); s->getp += sizeof(u_int32_t); return l; } - + /* Copy to source to stream. * * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap @@ -463,15 +485,15 @@ stream_put (struct stream *s, const void *src, size_t size) /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */ CHECK_SIZE(s, size); - + STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return; } - + if (src) memcpy (s->data + s->endp, src, size); else @@ -485,13 +507,13 @@ int stream_putc (struct stream *s, u_char c) { STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < sizeof(u_char)) { STREAM_BOUND_WARN (s, "put"); return 0; } - + s->data[s->endp++] = c; return sizeof (u_char); } @@ -507,7 +529,7 @@ stream_putw (struct stream *s, u_int16_t w) STREAM_BOUND_WARN (s, "put"); return 0; } - + s->data[s->endp++] = (u_char)(w >> 8); s->data[s->endp++] = (u_char) w; @@ -525,7 +547,7 @@ stream_putl (struct stream *s, u_int32_t l) STREAM_BOUND_WARN (s, "put"); return 0; } - + s->data[s->endp++] = (u_char)(l >> 24); s->data[s->endp++] = (u_char)(l >> 16); s->data[s->endp++] = (u_char)(l >> 8); @@ -545,7 +567,7 @@ stream_putq (struct stream *s, uint64_t q) STREAM_BOUND_WARN (s, "put quad"); return 0; } - + s->data[s->endp++] = (u_char)(q >> 56); s->data[s->endp++] = (u_char)(q >> 48); s->data[s->endp++] = (u_char)(q >> 40); @@ -562,15 +584,15 @@ int stream_putc_at (struct stream *s, size_t putp, u_char c) { STREAM_VERIFY_SANE(s); - + if (!PUT_AT_VALID (s, putp + sizeof (u_char))) { STREAM_BOUND_WARN (s, "put"); return 0; } - + s->data[putp] = c; - + return 1; } @@ -578,16 +600,16 @@ int stream_putw_at (struct stream *s, size_t putp, u_int16_t w) { STREAM_VERIFY_SANE(s); - + if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t))) { STREAM_BOUND_WARN (s, "put"); return 0; } - + s->data[putp] = (u_char)(w >> 8); s->data[putp + 1] = (u_char) w; - + return 2; } @@ -595,7 +617,7 @@ int stream_putl_at (struct stream *s, size_t putp, u_int32_t l) { STREAM_VERIFY_SANE(s); - + if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t))) { STREAM_BOUND_WARN (s, "put"); @@ -605,7 +627,7 @@ stream_putl_at (struct stream *s, size_t putp, u_int32_t l) s->data[putp + 1] = (u_char)(l >> 16); s->data[putp + 2] = (u_char)(l >> 8); s->data[putp + 3] = (u_char)l; - + return 4; } @@ -613,7 +635,7 @@ int stream_putq_at (struct stream *s, size_t putp, uint64_t q) { STREAM_VERIFY_SANE(s); - + if (!PUT_AT_VALID (s, putp + sizeof (uint64_t))) { STREAM_BOUND_WARN (s, "put"); @@ -627,7 +649,7 @@ stream_putq_at (struct stream *s, size_t putp, uint64_t q) s->data[putp + 5] = (u_char)(q >> 16); s->data[putp + 6] = (u_char)(q >> 8); s->data[putp + 7] = (u_char)q; - + return 8; } @@ -636,7 +658,7 @@ int stream_put_ipv4 (struct stream *s, u_int32_t l) { STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "put"); @@ -653,7 +675,7 @@ int stream_put_in_addr (struct stream *s, struct in_addr *addr) { STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "put"); @@ -671,24 +693,24 @@ int stream_put_prefix (struct stream *s, struct prefix *p) { size_t psize; - + STREAM_VERIFY_SANE(s); - + psize = PSIZE (p->prefixlen); - + if (STREAM_WRITEABLE (s) < psize) { STREAM_BOUND_WARN (s, "put"); return 0; } - + stream_putc (s, p->prefixlen); memcpy (s->data + s->endp, &p->u.prefix, psize); s->endp += psize; - + return psize; } - + /* Read size from fd. */ int stream_read (struct stream *s, int fd, size_t size) @@ -696,18 +718,18 @@ stream_read (struct stream *s, int fd, size_t size) int nbytes; STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } - + nbytes = readn (fd, s->data + s->endp, size); if (nbytes > 0) s->endp += nbytes; - + return nbytes; } @@ -717,15 +739,15 @@ stream_read_unblock (struct stream *s, int fd, size_t size) { int nbytes; int val; - + STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } - + val = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, val|O_NONBLOCK); nbytes = read (fd, s->data + s->endp, size); @@ -733,17 +755,67 @@ stream_read_unblock (struct stream *s, int fd, size_t size) if (nbytes > 0) s->endp += nbytes; - + return nbytes; } +/*------------------------------------------------------------------------------ + * Read up to size bytes into stream -- assuming non-blocking socket. + * + * Loops internally if gets EINTR -- so if does not read everything asked for, + * that must be because the read would otherwise block. + * + * Returns: 0..size -- number of bytes read + * -1 => failed -- see errno + * -2 => EOF met + * + * NB: if asks for zero bytes, will return 0 or error (if any). + */ +int +stream_read_nonblock(struct stream *s, int fd, size_t size) +{ + int ret ; + int want = size ; + + STREAM_VERIFY_SANE(s); + + if (STREAM_WRITEABLE (s) < size) + { + STREAM_BOUND_WARN (s, "put"); + return 0; + } + + do + { + ret = read(fd, s->data + s->endp, want); + + if (ret > 0) + { + s->endp += ret ; + want -= ret ; + } + else if (ret == 0) + return (want == 0) ? 0 : -2 ; + else + { + int err = errno ; + if ((err == EAGAIN) || (err == EWOULDBLOCK)) + break ; + if (err != EINTR) + return -1 ; + } ; + } while (want > 0) ; + + return size - want ; +} + ssize_t stream_read_try(struct stream *s, int fd, size_t size) { ssize_t nbytes; STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE(s) < size) { STREAM_BOUND_WARN (s, "put"); @@ -767,14 +839,14 @@ stream_read_try(struct stream *s, int fd, size_t size) /* Read up to size bytes into the stream from the fd, using recvmsgfrom * whose arguments match the remaining arguments to this function */ -ssize_t +ssize_t stream_recvfrom (struct stream *s, int fd, size_t size, int flags, - struct sockaddr *from, socklen_t *fromlen) + struct sockaddr *from, socklen_t *fromlen) { ssize_t nbytes; STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE(s) < size) { STREAM_BOUND_WARN (s, "put"); @@ -783,7 +855,7 @@ stream_recvfrom (struct stream *s, int fd, size_t size, int flags, return -1; } - if ((nbytes = recvfrom (fd, s->data + s->endp, size, + if ((nbytes = recvfrom (fd, s->data + s->endp, size, flags, from, fromlen)) >= 0) { s->endp += nbytes; @@ -802,15 +874,15 @@ stream_recvfrom (struct stream *s, int fd, size_t size, int flags, * Stream need not be empty. */ ssize_t -stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, +stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, size_t size) { int nbytes; struct iovec *iov; - + STREAM_VERIFY_SANE(s); - assert (msgh->msg_iovlen > 0); - + assert (msgh->msg_iovlen > 0); + if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); @@ -818,19 +890,19 @@ stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, to hold the desired data! */ return -1; } - + iov = &(msgh->msg_iov[0]); iov->iov_base = (s->data + s->endp); iov->iov_len = size; - + nbytes = recvmsg (fd, msgh, flags); - + if (nbytes > 0) s->endp += nbytes; - + return nbytes; } - + /* Write data to buffer. */ size_t stream_write (struct stream *s, const void *ptr, size_t size) @@ -839,20 +911,20 @@ stream_write (struct stream *s, const void *ptr, size_t size) CHECK_SIZE(s, size); STREAM_VERIFY_SANE(s); - + if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } - + memcpy (s->data + s->endp, ptr, size); s->endp += size; return size; } -/* Return current read pointer. +/* Return current read pointer. * DEPRECATED! * Use stream_get_pnt_to if you must, but decoding streams properly * is preferred @@ -882,26 +954,97 @@ stream_reset (struct stream *s) s->getp = s->endp = 0; } +/* Number of bytes pending to be written */ +int +stream_pending(struct stream* s) +{ + STREAM_VERIFY_SANE(s); + + return s->endp - s->getp ; +} + /* Write stream contens to the file discriptor. */ int -stream_flush (struct stream *s, int fd) +stream_flush (struct stream* s, int fd) { int nbytes; - + STREAM_VERIFY_SANE(s); - + nbytes = write (fd, s->data + s->getp, s->endp - s->getp); - + return nbytes; } - + +/*------------------------------------------------------------------------------ + * Try to write stream contents to the file descriptor -- assuming non-blocking. + * + * Loops if gets EINTR. + * + * If writes everything, resets the stream. + * + * If does not write everything, then would block. + * + * Returns: >= 0 number of bytes left to write + * -1 => some error (not including EINTR, EAGAIN or EWOULDBLOCK) + */ +int +stream_flush_try(struct stream* s, int fd) +{ + int have ; + int ret ; + + STREAM_VERIFY_SANE(s); + + while ((have = (s->endp - s->getp)) != 0) + { + ret = write(fd, s->data + s->getp, have) ; + if (ret > 0) + s->getp += ret ; + else if (ret < 0) + { + ret = errno ; + if ((ret == EAGAIN) || (ret == EWOULDBLOCK)) + return have ; + if (ret != EINTR) + return -1 ; + } ; + } ; + + s->getp = s->endp = 0; + + return 0 ; +} + +/*------------------------------------------------------------------------------ + * Transfer contents of stream to given buffer and reset stream. + * + * Transfers *entire* stream buffer. + * + * Returns pointer to next byte in given buffer + */ +void* +stream_transfer(void* p, struct stream* s, void* limit) +{ + size_t have = s->endp ; + + STREAM_VERIFY_SANE(s); + assert((p + have) <= limit) ; + + memcpy(p, s->data, have) ; + + s->getp = s->endp = 0; + + return p + have ; +} ; + /* Stream first in first out queue. */ struct stream_fifo * stream_fifo_new (void) { struct stream_fifo *new; - + new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo)); return new; } @@ -914,7 +1057,7 @@ stream_fifo_push (struct stream_fifo *fifo, struct stream *s) fifo->tail->next = s; else fifo->head = s; - + fifo->tail = s; fifo->count++; @@ -925,20 +1068,20 @@ struct stream * stream_fifo_pop (struct stream_fifo *fifo) { struct stream *s; - - s = fifo->head; + + s = fifo->head; if (s) - { + { fifo->head = s->next; if (fifo->head == NULL) fifo->tail = NULL; - } - fifo->count--; + fifo->count--; + } - return s; + return s; } /* Return first fifo entry. */ diff --git a/lib/stream.h b/lib/stream.h index 3e4ba7b4..4c8a4fa9 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #ifndef _ZEBRA_STREAM_H @@ -78,7 +78,7 @@ * The stream is empty from endp to size. Without adjusting getp, there are * still endp-getp bytes of valid data to be read from the stream. * - * Methods are provided to get and put to/from the stream, as well as + * Methods are provided to get and put to/from the stream, as well as * retrieve the values of the 3 markers and manipulate the getp marker. * * Note: @@ -98,7 +98,7 @@ struct stream /* Remainder is ***private*** to stream * direct access is frowned upon! - * Use the appropriate functions/macros + * Use the appropriate functions/macros */ size_t getp; /* next get position */ size_t endp; /* last valid data position */ @@ -127,7 +127,7 @@ struct stream_fifo #define STREAM_DATA(S) ((S)->data) #define STREAM_REMAIN(S) STREAM_WRITEABLE((S)) -/* Stream prototypes. +/* Stream prototypes. * For stream_{put,get}S, the S suffix mean: * * c: character (unsigned byte) @@ -139,6 +139,7 @@ extern struct stream *stream_new (size_t); extern void stream_free (struct stream *); extern struct stream * stream_copy (struct stream *, struct stream *src); extern struct stream *stream_dup (struct stream *); +extern struct stream* stream_dup_pending(struct stream*) ; extern size_t stream_resize (struct stream *, size_t); extern size_t stream_get_getp (struct stream *); extern size_t stream_get_endp (struct stream *); @@ -177,7 +178,7 @@ extern u_int32_t stream_get_ipv4 (struct stream *); #undef stream_read #undef stream_write -/* Deprecated: assumes blocking I/O. Will be removed. +/* Deprecated: assumes blocking I/O. Will be removed. Use stream_read_try instead. */ extern int stream_read (struct stream *, int, size_t); @@ -185,6 +186,8 @@ extern int stream_read (struct stream *, int, size_t); Will be removed. Use stream_read_try instead. */ extern int stream_read_unblock (struct stream *, int, size_t); +extern int stream_read_nonblock (struct stream *s, int fd, size_t size) ; + /* Read up to size bytes into the stream. Return code: >0: number of bytes read @@ -197,8 +200,8 @@ extern ssize_t stream_read_try(struct stream *s, int fd, size_t size); extern ssize_t stream_recvmsg (struct stream *s, int fd, struct msghdr *, int flags, size_t size); -extern ssize_t stream_recvfrom (struct stream *s, int fd, size_t len, - int flags, struct sockaddr *from, +extern ssize_t stream_recvfrom (struct stream *s, int fd, size_t len, + int flags, struct sockaddr *from, socklen_t *fromlen); extern size_t stream_write (struct stream *, const void *, size_t); @@ -207,6 +210,10 @@ extern void stream_reset (struct stream *); extern int stream_flush (struct stream *, int); extern int stream_empty (struct stream *); /* is the stream empty? */ +extern int stream_pending(struct stream* s) ; +extern int stream_flush_try(struct stream* s, int fd) ; +extern void* stream_transfer(void* p, struct stream* s, void* limit) ; + /* deprecated */ extern u_char *stream_pnt (struct stream *); diff --git a/lib/symtab.h b/lib/symtab.h index 7b4e002c..a8a6e622 100644 --- a/lib/symtab.h +++ b/lib/symtab.h @@ -23,6 +23,8 @@ #define _ZEBRA_SYMTAB_H #include "vector.h" +#include <stddef.h> +#include <stdint.h> /* Macro in case there are particular compiler issues. */ #ifndef Inline @@ -94,9 +96,9 @@ struct symbol symbol_ref ref_list ; /* list of symbol_ref references */ unsigned ref_count ; /* count of simple references */ - u_int32_t hash ; /* used in lookup and when extending bases. */ + uint32_t hash ; /* used in lookup and when extending bases. */ - u_int16_t name_len ; /* see: symbol_get_name_len(sym) */ + uint16_t name_len ; /* see: symbol_get_name_len(sym) */ char name[] ; /* see: symbol_get_name(sym) */ } ; @@ -127,10 +129,10 @@ struct symbol_ref /* Result of a hash function for a symbol name. */ struct symbol_hash { - u_int32_t hash ; /* the hash value ! */ - const void* name ; /* symbol name as byte vector */ - u_int16_t name_len ; /* length in chars for comparison purposes */ - u_int16_t name_copy_len ; /* number of chars to copy to store name. */ + uint32_t hash ; /* the hash value ! */ + const void* name ; /* symbol name as byte vector */ + uint16_t name_len ; /* length in chars for comparison purposes */ + uint16_t name_copy_len ; /* number of chars to copy to store name. */ } ; /* Symbol Walk Iterator */ @@ -265,7 +267,7 @@ sym_ref_name(symbol_ref ref) { return symbol_get_name(sym_ref_symbol(ref)) ; } -Inline u_int16_t +Inline uint16_t sym_ref_name_len(symbol_ref ref) { return symbol_get_name_len(sym_ref_symbol(ref)) ; diff --git a/lib/zebra.h b/lib/zebra.h index 2dc84514..65aad161 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -115,7 +115,7 @@ typedef int socklen_t; #ifdef __va_copy #define va_copy(DST,SRC) __va_copy(DST,SRC) #else -/* Now we are desperate; this should work on many typical platforms. +/* Now we are desperate; this should work on many typical platforms. But this is slightly dangerous, because the standard does not require va_copy to be a macro. */ #define va_copy(DST,SRC) memcpy(&(DST), &(SRC), sizeof(va_list)) @@ -260,7 +260,7 @@ typedef int socklen_t; #endif /* BSDI_NRL */ /* Local includes: */ -#if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL)) +#if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL)) #define __attribute__(x) #endif /* !__GNUC__ || VTYSH_EXTRACT_PL */ @@ -285,7 +285,7 @@ typedef int socklen_t; -/* +/* * RFC 3542 defines several macros for using struct cmsghdr. * Here, we define those that are not present */ @@ -330,7 +330,7 @@ struct in_pktinfo }; #endif -/* +/* * OSPF Fragmentation / fragmented writes * * ospfd can support writing fragmented packets, for cases where @@ -350,13 +350,13 @@ struct in_pktinfo #define WANT_OSPF_WRITE_FRAGMENT #endif -/* +/* * IP_HDRINCL / struct ip byte order * * Linux: network byte order * *BSD: network, except for length and offset. (cf Stevens) * SunOS: nominally as per BSD. but bug: network order on LE. - * OpenBSD: network byte order, apart from older versions which are as per + * OpenBSD: network byte order, apart from older versions which are as per * *BSD */ #if defined(__NetBSD__) || defined(__FreeBSD__) \ @@ -385,7 +385,7 @@ struct in_pktinfo /* MAX / MIN are not commonly defined, but useful */ #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif +#endif #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -451,7 +451,7 @@ struct in_pktinfo extern const char *zebra_route_string(unsigned int route_type); /* Map a route type to a char. For example, ZEBRA_ROUTE_RIPNG -> 'R'. */ extern char zebra_route_char(unsigned int route_type); -/* Map a zserv command type to the same string, +/* Map a zserv command type to the same string, * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ /* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ extern int proto_name2num(const char *s); @@ -496,17 +496,8 @@ extern const char *zserv_command_string (unsigned int command); #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif -/* Address family numbers from RFC1700. */ -#define AFI_IP 1 -#define AFI_IP6 2 -#define AFI_MAX 3 - -/* Subsequent Address Family Identifier. */ -#define SAFI_UNICAST 1 -#define SAFI_MULTICAST 2 -#define SAFI_UNICAST_MULTICAST 3 -#define SAFI_MPLS_VPN 4 -#define SAFI_MAX 5 +/* AFI/SAFI types and numbers. */ +#include "qafi_safi.h" /* Filter direction. */ #define FILTER_IN 0 @@ -530,10 +521,6 @@ extern const char *zserv_command_string (unsigned int command); #define SET_FLAG(V,F) (V) |= (F) #define UNSET_FLAG(V,F) (V) &= ~(F) -/* AFI and SAFI type. */ -typedef u_int16_t afi_t; -typedef u_int8_t safi_t; - /* Zebra types. Used in Zserv message header. */ typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; |