summaryrefslogtreecommitdiffstats
path: root/lib/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/network.c')
-rw-r--r--lib/network.c163
1 files changed, 145 insertions, 18 deletions
diff --git a/lib/network.c b/lib/network.c
index 3373983b..61d98717 100644
--- a/lib/network.c
+++ b/lib/network.c
@@ -17,14 +17,23 @@
* 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>
#include "log.h"
#include "network.h"
-/* Read nbytes from fd and store into ptr. */
+/*------------------------------------------------------------------------------
+ * Read nbytes from fd and store into ptr -- BLOCKING
+ *
+ * Loops internally if gets EINTR.
+ *
+ * Returns: >= 0 -- number of bytes read
+ * < 0 => error
+ *
+ * NB: if applied to a NON-BLOCKING fd, may return EAGAIN or EWOULDBLOCK
+ */
int
readn (int fd, u_char *ptr, int nbytes)
{
@@ -33,24 +42,86 @@ readn (int fd, u_char *ptr, int nbytes)
nleft = nbytes;
- while (nleft > 0)
+ while (nleft > 0)
{
nread = read (fd, ptr, nleft);
- if (nread < 0)
- return (nread);
+ if (nread > 0)
+ {
+ nleft -= nread;
+ ptr += nread;
+ }
+ else if (nread == 0)
+ break;
else
- if (nread == 0)
- break;
-
- nleft -= nread;
- ptr += nread;
+ {
+ if (errno != EINTR)
+ return (nread);
+ }
}
return nbytes - nleft;
-}
+}
+
+/*------------------------------------------------------------------------------
+ * Read up to nbyte bytes into buf -- assuming NON-BLOCKING.
+ *
+ * Loops internally if gets EINTR -- so if does not read everything asked for,
+ * that must be because the read would otherwise block.
+ *
+ * Returns: 0..n -- number of bytes read
+ * -1 => failed -- see errno
+ * -2 => EOF met immediately
+ *
+ * NB: if asked to write zero bytes, does nothing and will return 0.
+ *
+ * Reading zero bytes is defined for all types of files, and may be used
+ * to probe for error state.
+ */
+int
+read_nb(int fd, void* buf, size_t nbyte)
+{
+ size_t nleft = nbyte ;
+
+ do
+ {
+ int ret = read(fd, buf, nleft);
+
+ if (ret > 0)
+ {
+ buf = (char*)buf + ret ;
+ nleft -= ret ;
+ }
+ else if (ret == 0)
+ {
+ if (nleft < nbyte)
+ break ; /* if read something before EOF */
+
+ return -2 ; /* hit EOF immediately */
+ }
+ else
+ {
+ int err = errno ;
+ if ((err == EAGAIN) || (err == EWOULDBLOCK))
+ break ;
+ if (err != EINTR)
+ return -1 ; /* failed */
+ } ;
+ } while (nleft > 0) ;
+
+ return (nbyte - nleft) ;
+} ;
-/* Write nbytes from ptr to fd. */
+/*------------------------------------------------------------------------------
+ * Write nbytes to fd from ptr -- BLOCKING
+ *
+ * Loops internally if gets EINTR.
+ *
+ * Returns: >= 0 -- number of bytes written
+ * < 0 => error
+ *
+ * NB: if applied to a NON-BLOCKING fd, may return EAGAIN or EWOULDBLOCK
+ */
int
writen(int fd, const u_char *ptr, int nbytes)
{
@@ -59,19 +130,75 @@ writen(int fd, const u_char *ptr, int nbytes)
nleft = nbytes;
- while (nleft > 0)
+ while (nleft > 0)
{
nwritten = write(fd, ptr, nleft);
-
- if (nwritten <= 0)
- return (nwritten);
- nleft -= nwritten;
- ptr += nwritten;
+ if (nwritten > 0)
+ {
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ else if (nwritten == 0)
+ break ;
+ else
+ {
+ if (errno != EINTR)
+ return (nwritten);
+ }
}
return nbytes - nleft;
}
+/*------------------------------------------------------------------------------
+ * Write up to nbyte bytes from buf -- assuming NON-BLOCKING.
+ *
+ * Loops internally if gets EINTR.
+ *
+ * Returns: 0..n -- number of bytes written
+ * -1 => failed -- see errno
+ *
+ * NB: if asked to write zero bytes, does nothing and will return 0.
+ *
+ * Writing zero bytes is defined for "regular files", but not for anything
+ * else.
+ */
+int
+write_nb(int fd, void* buf, size_t nbyte)
+{
+ size_t nleft = nbyte ;
+
+ while (nleft > 0)
+ {
+ int ret = write(fd, buf, nleft);
+
+ if (ret > 0)
+ {
+ buf = (char*)buf + ret ;
+ nleft -= ret ;
+ }
+ else if (ret == 0)
+ break ; /* not sure can happen... but
+ cannot assume will go away */
+ else
+ {
+ int err = errno ;
+ if ((err == EAGAIN) || (err == EWOULDBLOCK))
+ break ;
+ if (err != EINTR)
+ return -1 ; /* failed */
+ } ;
+ } ;
+
+ return (nbyte - nleft) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set fd to non-blocking
+ *
+ * Returns: 0 => OK
+ * -1 => failed
+ */
int
set_nonblocking(int fd)
{