summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/memtypes.c3
-rw-r--r--lib/mqueue.c103
-rw-r--r--lib/mqueue.h55
-rw-r--r--lib/qafi_safi.h151
-rw-r--r--lib/qpselect.c2
-rw-r--r--lib/qpselect.h30
-rw-r--r--lib/qpthreads.c50
-rw-r--r--lib/qpthreads.h4
-rw-r--r--lib/sockopt.c181
-rw-r--r--lib/sockunion.c378
-rw-r--r--lib/sockunion.h23
-rw-r--r--lib/stream.c373
-rw-r--r--lib/stream.h21
-rw-r--r--lib/symtab.h16
-rw-r--r--lib/zebra.h33
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;