From c2011088f312028d2c6f242a437e14c12127a8ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Wed, 25 Mar 1998 23:39:40 +0100
Subject: [PATCH] Added support for out-of-band data.

Rev: src/acconfig.h:1.18
Rev: src/backend.c:1.24
Rev: src/backend.h:1.5
Rev: src/configure.in:1.169
Rev: src/fdlib.c:1.15
Rev: src/fdlib.h:1.12
Rev: src/modules/files/file.c:1.81
Rev: src/modules/files/file.h:1.8
---
 src/acconfig.h           |   3 +
 src/backend.c            | 191 +++++++++++++++-
 src/backend.h            |  12 +
 src/configure.in         |   3 +-
 src/fdlib.c              |   1 +
 src/fdlib.h              |   2 +
 src/modules/files/file.c | 462 ++++++++++++++++++++++++++++++++++++++-
 src/modules/files/file.h |   4 +
 8 files changed, 665 insertions(+), 13 deletions(-)

diff --git a/src/acconfig.h b/src/acconfig.h
index 7c45fb2226..26eb98f333 100644
--- a/src/acconfig.h
+++ b/src/acconfig.h
@@ -183,6 +183,9 @@
 /* Use poll() instead of select() ? */
 #undef HAVE_AND_USE_POLL
 
+/* Enable code to handle Out-Of-Band data */
+#undef WITH_OOB
+
 @BOTTOM@
 
 /* NT stuff */
diff --git a/src/backend.c b/src/backend.c
index 8f7e7fc96d..ac85d38c71 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: backend.c,v 1.23 1998/03/10 03:16:34 per Exp $");
+RCSID("$Id: backend.c,v 1.24 1998/03/25 22:39:38 grubba Exp $");
 #include "fdlib.h"
 #include "backend.h"
 #include <errno.h>
@@ -37,6 +37,12 @@ file_callback read_callback[MAX_OPEN_FILEDESCRIPTORS];
 void *read_callback_data[MAX_OPEN_FILEDESCRIPTORS];
 file_callback write_callback[MAX_OPEN_FILEDESCRIPTORS];
 void *write_callback_data[MAX_OPEN_FILEDESCRIPTORS];
+#ifdef WITH_OOB
+file_callback read_oob_callback[MAX_OPEN_FILEDESCRIPTORS];
+void *read_oob_callback_data[MAX_OPEN_FILEDESCRIPTORS];
+file_callback write_oob_callback[MAX_OPEN_FILEDESCRIPTORS];
+void *write_oob_callback_data[MAX_OPEN_FILEDESCRIPTORS];
+#endif /* WITH_OOB */
 
 #ifndef HAVE_AND_USE_POLL
 #undef HAVE_POLL
@@ -55,7 +61,11 @@ static struct selectors selectors;
 #include <poll.h>
 struct pollfd *poll_fds, *active_poll_fds;
 int num_in_poll=0;
+int active_num_in_poll=0;
 
+/*
+ * This code probably uses realloc a bit too much...
+ */
 void POLL_FD_SET(int fd, short add)
 {
   int i;
@@ -81,17 +91,30 @@ void POLL_FD_CLR(int fd, short sub)
       poll_fds[i].events &= ~sub;
       if(!poll_fds[i].events)
       {
-	if(i!=num_in_poll-1)
-	  MEMCPY(poll_fds+i, poll_fds+i+1,
-		 (num_in_poll-1-i)*sizeof(struct pollfd));
+	/* Note that num_in_poll is decreased here.
+	 * This is to avoid a lot of -1's below.
+	 * /grubba
+	 */
 	num_in_poll--;
+	if(i != num_in_poll) {
+#if 0
+	  /* Not very efficient...
+	   * /grubba
+	   */
+	  MEMCPY(poll_fds+i, poll_fds+i+1,
+		 (num_in_poll-i)*sizeof(struct pollfd));
+#else /* !0 */
+	  /* This should speed things up a bit...
+	   */
+	  *(poll_fds+i) = *(poll_fds+num_in_poll);
+#endif /* 0 */
+	}
       }
       break;
     }
   return;
 }
 
-int active_num_in_poll;
 void switch_poll_set()
 {
   struct pollfd *tmp = active_poll_fds;
@@ -242,6 +265,94 @@ void set_write_callback(int fd,file_callback cb,void *data)
   }
 }
 
+#ifdef WITH_OOB
+void set_read_oob_callback(int fd,file_callback cb,void *data)
+{
+#ifdef HAVE_POLL
+  int was_set = (read_oob_callback[fd]!=0);
+#endif
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+  read_oob_callback[fd]=cb;
+  read_oob_callback_data[fd]=data;
+
+  if(cb)
+  {
+#ifdef HAVE_POLL
+    POLL_FD_SET(fd,POLLRDBAND);
+#else
+    my_FD_SET(fd, &selectors.read);	/* FIXME:? */
+#endif
+    if(max_fd < fd) max_fd = fd;
+    wake_up_backend();
+  }else{
+#ifndef HAVE_POLL
+    /* FIXME:? */
+    if(fd <= max_fd)
+    {
+      my_FD_CLR(fd, &selectors.read);
+
+      if(fd == max_fd)
+      {
+	while(max_fd >=0 &&
+	      !my_FD_ISSET(max_fd, &selectors.read) &&
+	      !my_FD_ISSET(max_fd, &selectors.write))
+	  max_fd--;
+      }
+    }
+#else
+    if(was_set)
+      POLL_FD_CLR(fd,POLLRDBAND);
+#endif
+  }
+}
+
+void set_write_oob_callback(int fd,file_callback cb,void *data)
+{
+#ifdef HAVE_POLL
+  int was_set = (write_oob_callback[fd]!=0);
+#endif
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+
+  write_oob_callback[fd]=cb;
+  write_oob_callback_data[fd]=data;
+
+  if(cb)
+  {
+#ifdef HAVE_POLL
+    POLL_FD_SET(fd,POLLWRBAND);
+#else
+    my_FD_SET(fd, &selectors.write);	/* FIXME:? */
+#endif
+    if(max_fd < fd) max_fd = fd;
+    wake_up_backend();
+  }else{
+#ifndef HAVE_POLL
+    /* FIXME:? */
+    if(fd <= max_fd)
+    {
+      my_FD_CLR(fd, &selectors.write);
+      if(fd == max_fd)
+      {
+	while(max_fd >=0 &&
+	      !my_FD_ISSET(max_fd, &selectors.read) &&
+	      !my_FD_ISSET(max_fd, &selectors.write))
+	  max_fd--;
+      }
+    }
+#else
+    if(was_set)
+      POLL_FD_CLR(fd,POLLWRBAND);
+#endif
+  }
+}
+#endif /* WITH_OOB */
+
 file_callback query_read_callback(int fd)
 {
 #ifdef DEBUG
@@ -262,6 +373,28 @@ file_callback query_write_callback(int fd)
   return write_callback[fd];
 }
 
+#ifdef WITH_OOB
+file_callback query_read_oob_callback(int fd)
+{
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+
+  return read_oob_callback[fd];
+}
+
+file_callback query_write_oob_callback(int fd)
+{
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+
+  return write_oob_callback[fd];
+}
+#endif /* WITH_OOB */
+
 void *query_read_callback_data(int fd)
 {
 #ifdef DEBUG
@@ -282,6 +415,28 @@ void *query_write_callback_data(int fd)
   return write_callback_data[fd];
 }
 
+#ifdef WITH_OOB
+void *query_read_oob_callback_data(int fd)
+{
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+
+  return read_oob_callback_data[fd];
+}
+
+void *query_write_oob_callback_data(int fd)
+{
+#ifdef DEBUG
+  if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS)
+    fatal("File descriptor out of range.\n %d",fd);
+#endif
+
+  return write_oob_callback_data[fd];
+}
+#endif /* WITH_OOB */
+
 #ifdef DEBUG
 
 struct callback_list do_debug_callbacks;
@@ -306,6 +461,7 @@ void do_debug(void)
 
   call_callback(& do_debug_callbacks, 0);
 
+  /* FIXME: OOB? */
 #ifndef HAVE_POLL
   for(e=0;e<=max_fd;e++)
   {
@@ -384,6 +540,7 @@ void backend(void)
     check_threads_etc();
 
 #ifndef HAVE_POLL
+    /* FIXME: OOB? */
     fd_copy_my_fd_set_to_fd_set(&rset, &selectors.read, max_fd+1);
     fd_copy_my_fd_set_to_fd_set(&wset, &selectors.write, max_fd+1);
 #endif
@@ -412,6 +569,7 @@ void backend(void)
       i=poll(active_poll_fds, active_num_in_poll, msec);
     }
 #else
+    /* FIXME: OOB? */
     i=fd_select(max_fd+1, &rset, &wset, 0, &next_timeout);
 #endif
     GETTIMEOFDAY(&current_time);
@@ -421,6 +579,7 @@ void backend(void)
     if(i>=0)
     {
 #ifndef HAVE_POLL
+      /* FIXME: OOB? */
       for(i=0; i<max_fd+1; i++)
       {
 	if(fd_FD_ISSET(i, &rset) && read_callback[i])
@@ -440,15 +599,32 @@ void backend(void)
 	    if(poll_fds[j].fd == fd) /* It's still there... */
 	      fatal("Bad filedescriptor %d to select().\n", fd);
 	}
+
+#ifdef WITH_OOB
+	if ((active_poll_fds[i].revents & POLLRDBAND) &&
+	    read_oob_callback[fd]) {
+	  (*(read_oob_callback[fd]))(fd, read_oob_callback_data[fd]);
+	}
+#endif /* WITH_OOB */
+
 	if((active_poll_fds[i].revents & POLLHUP) ||
 	   (active_poll_fds[i].revents & POLLERR))
 	  active_poll_fds[i].revents |= POLLRDNORM;
 
-	if((active_poll_fds[i].revents & POLLRDNORM)&& read_callback[fd])
+	if((active_poll_fds[i].revents & POLLRDNORM)&& read_callback[fd]) {
 	  (*(read_callback[fd]))(fd,read_callback_data[fd]);
+	}
 
-	if((active_poll_fds[i].revents & POLLOUT)&& write_callback[fd])
+#ifdef WITH_OOB
+	if ((active_poll_fds[i].revents & POLLWRBAND) &&
+	    write_oob_callback[fd]) {
+	  (*(write_oob_callback[fd]))(fd, write_oob_callback_data[fd]);
+	}
+#endif /* WITH_OOB */
+
+	if((active_poll_fds[i].revents & POLLOUT)&& write_callback[fd]) {
 	  (*(write_callback[fd]))(fd,write_callback_data[fd]);
+	}
       }
 #endif
     }else{
@@ -479,6 +655,7 @@ void backend(void)
       case EBADF:
 	/* TODO: Fix poll version! */
 #ifndef HAVE_POLL
+	/* FIXME: OOB? */
 	fd_copy_my_fd_set_to_fd_set(&rset, &selectors.read, max_fd+1);
 	fd_copy_my_fd_set_to_fd_set(&wset, &selectors.write, max_fd+1);
 	next_timeout.tv_usec=0;
diff --git a/src/backend.h b/src/backend.h
index e58a610727..002d5cfc09 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -24,10 +24,22 @@ void wake_up_backend(void);
 void init_backend(void);
 void set_read_callback(int fd,file_callback cb,void *data);
 void set_write_callback(int fd,file_callback cb,void *data);
+#ifdef WITH_OOB
+void set_read_oob_callback(int fd,file_callback cb,void *data);
+void set_write_oob_callback(int fd,file_callback cb,void *data);
+#endif /* WITH_OOB */
 file_callback query_read_callback(int fd);
 file_callback query_write_callback(int fd);
+#ifdef WITH_OOB
+file_callback query_read_oob_callback(int fd);
+file_callback query_write_oob_callback(int fd);
+#endif /* WITH_OOB */
 void *query_read_callback_data(int fd);
 void *query_write_callback_data(int fd);
+#ifdef WITH_OOB
+void *query_read_oob_callback_data(int fd);
+void *query_write_oob_callback_data(int fd);
+#endif /* WITH_OOB */
 void do_debug(void);
 void backend(void);
 int write_to_stderr(char *a, INT32 len);
diff --git a/src/configure.in b/src/configure.in
index 18d80a481c..29fb29d40e 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.168 1998/03/22 03:20:31 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.169 1998/03/25 22:39:39 grubba Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -103,6 +103,7 @@ AC_ARG_WITH(dmalloc,     [  --with-dmalloc         enable memory-leak tests],[AC
 AC_ARG_WITH(profiling,   [  --with-profiling       add code used to profile pike code ],[AC_DEFINE(PROFILING)],[])
 AC_ARG_WITH(poll,        [  --with-poll            use poll instead of select],[AC_DEFINE(HAVE_AND_USE_POLL)],[])
 AC_ARG_WITH(max-fd,      [  --with-max-fd=X        set how many filedescriptors can be used at once],[pike_cv_max_open_fd=$withval],[])
+AC_ARG_WITH(oob,	 [  --with-oob             enable out-of-band data handling],[AC_DEFINE(WITH_OOB)],[])
 
 #
 # Allow --with(out)-debug to toggle both cdebug and rtldebug, but
diff --git a/src/fdlib.c b/src/fdlib.c
index ae68f31eed..e6d0c60e70 100644
--- a/src/fdlib.c
+++ b/src/fdlib.c
@@ -335,6 +335,7 @@ SOCKFUN2(getsockname,struct sockaddr *,int *)
 SOCKFUN2(getpeername,struct sockaddr *,int *)
 SOCKFUN3(recv,void *,int,int)
 SOCKFUN5(recvfrom,void *,int,int,struct sockaddr *,int*)
+SOCKFUN3(send,void *,int,int)
 SOCKFUN5(sendto,void *,int,int,struct sockaddr *,int*)
 SOCKFUN1(shutdown, int)
 SOCKFUN1(listen, int)
diff --git a/src/fdlib.h b/src/fdlib.h
index 5c6c40405e..adac723483 100644
--- a/src/fdlib.h
+++ b/src/fdlib.h
@@ -73,6 +73,7 @@ SOCKFUN2(getsockname,struct sockaddr *,int *)
 SOCKFUN2(getpeername,struct sockaddr *,int *)
 SOCKFUN3(recv,void *,int,int)
 SOCKFUN5(recvfrom,void *,int,int,struct sockaddr *,int*)
+SOCKFUN3(send,void *,int,int)
 SOCKFUN5(sendto,void *,int,int,struct sockaddr *,int*)
 SOCKFUN1(shutdown, int)
 SOCKFUN1(listen, int)
@@ -235,6 +236,7 @@ typedef int FD;
 #define fd_getsockname getsockname
 #define fd_getpeername getpeername
 #define fd_recv recv
+#define fd_send send
 #define fd_sendto sendto
 #define fd_recvfrom recvfrom
 #define fd_shutdown shutdown
diff --git a/src/modules/files/file.c b/src/modules/files/file.c
index 038fc948c2..92470bebf2 100644
--- a/src/modules/files/file.c
+++ b/src/modules/files/file.c
@@ -8,7 +8,7 @@
 #define READ_BUFFER 8192
 
 #include "global.h"
-RCSID("$Id: file.c,v 1.80 1998/03/22 04:37:19 per Exp $");
+RCSID("$Id: file.c,v 1.81 1998/03/25 22:39:40 grubba Exp $");
 #include "fdlib.h"
 #include "interpret.h"
 #include "svalue.h"
@@ -119,6 +119,12 @@ static void init_fd(int fd, int open_mode)
   files[fd].read_callback.u.integer=0;
   files[fd].write_callback.type=T_INT;
   files[fd].write_callback.u.integer=0;
+#ifdef WITH_OOB
+  files[fd].read_oob_callback.type=T_INT;
+  files[fd].read_oob_callback.u.integer=0;
+  files[fd].write_oob_callback.type=T_INT;
+  files[fd].write_oob_callback.u.integer=0;
+#endif /* WITH_OOB */
   files[fd].close_callback.type=T_INT;
   files[fd].close_callback.u.integer=0;
 }
@@ -138,14 +144,26 @@ static int close_fd(int fd)
   {
     set_read_callback(fd,0,0);
     set_write_callback(fd,0,0);
+#ifdef WITH_OOB
+    set_read_oob_callback(fd,0,0);
+    set_write_oob_callback(fd,0,0);
+#endif /* WITH_OOB */
 
     free_svalue(& files[fd].id);
     free_svalue(& files[fd].read_callback);
     free_svalue(& files[fd].write_callback);
+#ifdef WITH_OOB
+    free_svalue(& files[fd].read_oob_callback);
+    free_svalue(& files[fd].write_oob_callback);
+#endif /* WITH_OOB */
     free_svalue(& files[fd].close_callback);
     files[fd].id.type=T_INT;
     files[fd].read_callback.type=T_INT;
     files[fd].write_callback.type=T_INT;
+#ifdef WITH_OOB
+    files[fd].read_oob_callback.type=T_INT;
+    files[fd].write_oob_callback.type=T_INT;
+#endif /* WITH_OOB */
     files[fd].close_callback.type=T_INT;
     files[fd].open_mode = 0;
 
@@ -261,7 +279,6 @@ static int parse(char *a)
     case 'X':
       ret|=FILE_EXCLUSIVE;
       break;
-
    }
   }
 }
@@ -408,6 +425,129 @@ static struct pike_string *do_read(int fd,
   }
 }
 
+#ifdef WITH_OOB
+static struct pike_string *do_read_oob(int fd,
+				       INT32 r,
+				       int all,
+				       short *err)
+{
+  ONERROR ebuf;
+  INT32 bytes_read,i;
+  bytes_read=0;
+  *err=0;
+
+  if(r <= 65536)
+  {
+    struct pike_string *str;
+
+    str=begin_shared_string(r);
+
+    SET_ONERROR(ebuf, call_free, str);
+
+    do{
+      int fd=FD;
+      THREADS_ALLOW();
+      i=fd_recv(fd, str->str+bytes_read, r, MSG_OOB);
+      THREADS_DISALLOW();
+
+      check_signals(0,0,0);
+
+      if(i>0)
+      {
+	r-=i;
+	bytes_read+=i;
+	if(!all) break;
+      }
+      else if(i==0)
+      {
+	break;
+      }
+      else if(errno != EINTR)
+      {
+	*err=errno;
+	if(!bytes_read)
+	{
+	  free((char *)str);
+	  UNSET_ONERROR(ebuf);
+	  return 0;
+	}
+	break;
+      }
+    }while(r);
+
+    UNSET_ONERROR(ebuf);
+    
+    if(bytes_read == str->len)
+    {
+      return end_shared_string(str);
+    }else{
+      struct pike_string *foo; /* Per */
+      foo = make_shared_binary_string(str->str,bytes_read);
+      free((char *)str);
+      return foo;
+    }
+    
+  }else{
+#define CHUNK 65536
+    INT32 try_read;
+    dynamic_buffer b;
+
+    b.s.str=0;
+    initialize_buf(&b);
+    SET_ONERROR(ebuf, free_dynamic_buffer, &b);
+    do{
+      char *buf;
+      try_read=MINIMUM(CHUNK,r);
+      
+      buf = low_make_buf_space(try_read, &b);
+
+      THREADS_ALLOW();
+      i=fd_recv(fd, buf, try_read, MSG_OOB);
+      THREADS_DISALLOW();
+
+      check_signals(0,0,0);
+      
+      if(i==try_read)
+      {
+	r-=i;
+	bytes_read+=i;
+	if(!all) break;
+      }
+      else if(i>0)
+      {
+	bytes_read+=i;
+	r-=i;
+	low_make_buf_space(i - try_read, &b);
+	if(!all) break;
+      }
+      else if(i==0)
+      {
+	low_make_buf_space(-try_read, &b);
+	break;
+      }
+      else
+      {
+	low_make_buf_space(-try_read, &b);
+	if(errno != EINTR)
+	{
+	  *err=errno;
+	  if(!bytes_read)
+	  {
+	    free(b.s.str);
+	    UNSET_ONERROR(ebuf);
+	    return 0;
+	  }
+	  break;
+	}
+      }
+    }while(r);
+
+    UNSET_ONERROR(ebuf);
+    return low_free_buf(&b);
+  }
+}
+#endif /* WITH_OOB */
+
 static void file_read(INT32 args)
 {
   struct pike_string *tmp;
@@ -426,7 +566,7 @@ static void file_read(INT32 args)
       error("Bad argument 1 to file->read().\n");
     len=sp[-args].u.integer;
     if(len<0)
-      error("Cannot read negative number of args.\n");
+      error("Cannot read negative number of characters.\n");
   }
 
   if(args > 1 && !IS_ZERO(sp+1-args))
@@ -444,6 +584,44 @@ static void file_read(INT32 args)
     push_int(0);
 }
 
+#ifdef WITH_OOB
+static void file_read_oob(INT32 args)
+{
+  struct pike_string *tmp;
+  INT32 all, len;
+
+  if(FD < 0)
+    error("File not open.\n");
+
+  if(!args)
+  {
+    len=0x7fffffff;
+  }
+  else
+  {
+    if(sp[-args].type != T_INT)
+      error("Bad argument 1 to file->read_oob().\n");
+    len=sp[-args].u.integer;
+    if(len<0)
+      error("Cannot read negative number of characters.\n");
+  }
+
+  if(args > 1 && !IS_ZERO(sp+1-args))
+  {
+    all=0;
+  }else{
+    all=1;
+  }
+
+  pop_n_elems(args);
+
+  if((tmp=do_read_oob(FD, len, all, & ERRNO)))
+    push_string(tmp);
+  else
+    push_int(0);
+}
+#endif /* WITH_OOB */
+
 static void file_write_callback(int fd, void *data)
 {
   set_write_callback(fd, 0, 0);
@@ -453,6 +631,17 @@ static void file_write_callback(int fd, void *data)
   pop_stack();
 }
 
+#ifdef WITH_OOB
+static void file_write_oob_callback(int fd, void *data)
+{
+  set_write_oob_callback(fd, 0, 0);
+
+  assign_svalue_no_free(sp++, & files[fd].id);
+  apply_svalue(& files[fd].write_oob_callback, 1);
+  pop_stack();
+}
+#endif /* WITH_OOB */
+
 static void file_write(INT32 args)
 {
   INT32 written,i;
@@ -516,6 +705,71 @@ static void file_write(INT32 args)
   push_int(written);
 }
 
+#ifdef WITH_OOB
+static void file_write_oob(INT32 args)
+{
+  INT32 written,i;
+  struct pike_string *str;
+
+  if(args<1 || sp[-args].type != T_STRING)
+    error("Bad argument 1 to file->write().\n");
+
+  if(args > 1)
+  {
+    extern void f_sprintf(INT32);
+    f_sprintf(args);
+    args=1;
+  }
+
+  if(FD < 0)
+    error("File not open for write_oob.\n");
+  
+  written=0;
+  str=sp[-args].u.string;
+
+  while(written < str->len)
+  {
+    int fd=FD;
+    THREADS_ALLOW();
+    i=fd_send(fd, str->str + written, str->len - written, MSG_OOB);
+    THREADS_DISALLOW();
+
+#ifdef _REENTRANT
+    if(FD<0) error("File destructed while in file->write_oob.\n");
+#endif
+
+    if(i<0)
+    {
+      switch(errno)
+      {
+      default:
+	ERRNO=errno;
+	pop_n_elems(args);
+	push_int(-1);
+	return;
+
+      case EINTR: continue;
+      case EWOULDBLOCK: break;
+      }
+      break;
+    }else{
+      written+=i;
+
+      /* Avoid extra write() */
+      if(THIS->open_mode & FILE_NONBLOCKING)
+	break;
+    }
+  }
+
+  if(!IS_ZERO(& THIS->write_oob_callback))
+    set_write_oob_callback(FD, file_write_oob_callback, 0);
+  ERRNO=0;
+
+  pop_n_elems(args);
+  push_int(written);
+}
+#endif /* WITH_OOB */
+
 static int do_close(int fd, int flags)
 {
   if(fd == -1) return 1; /* already closed */
@@ -536,6 +790,9 @@ static int do_close(int fd, int flags)
     if(files[fd].open_mode & FILE_WRITE)
     {
       set_read_callback(fd,0,0);
+#ifdef WITH_OOB
+      set_read_oob_callback(fd,0,0);
+#endif /* WITH_OOB */
       fd_shutdown(fd, 0);
       files[fd].open_mode &=~ FILE_READ;
       return 0;
@@ -548,6 +805,9 @@ static int do_close(int fd, int flags)
     if(files[fd].open_mode & FILE_READ)
     {
       set_write_callback(fd,0,0);
+#ifdef WITH_OOB
+      set_write_oob_callback(fd,0,0);
+#endif /* WITH_OOB */
       fd_shutdown(fd, 1);
       files[fd].open_mode &=~ FILE_WRITE;
       return 0;
@@ -645,7 +905,6 @@ static void file_open(INT32 args)
   }
   else
   {
-    
     init_fd(fd,flags | fd_query_properties(fd, FILE_CAPABILITIES));
     FD=fd;
     ERRNO = 0;
@@ -763,6 +1022,17 @@ static struct pike_string *simple_do_read(INT32 *amount,int fd)
   return 0;
 }
 
+#ifdef WITH_OOB
+static struct pike_string *simple_do_read_oob(INT32 *amount,int fd)
+{
+  char buffer[READ_BUFFER];
+  *amount = fd_recv(fd, buffer, READ_BUFFER, MSG_OOB);
+  /* Note: OOB packets may have zero size */
+  if(*amount>=0) return make_shared_binary_string(buffer,*amount);
+  return 0;
+}
+#endif /* WITH_OOB */
+
 static void file_read_callback(int fd, void *data)
 {
   struct pike_string *s;
@@ -805,6 +1075,44 @@ static void file_read_callback(int fd, void *data)
   apply_svalue(& files[fd].close_callback, 1);
 }
 
+#ifdef WITH_OOB
+static void file_read_oob_callback(int fd, void *data)
+{
+  struct pike_string *s;
+  INT32 i;
+
+#ifdef DEBUG
+  if(fd == -1 || fd >= MAX_OPEN_FILEDESCRIPTORS)
+    fatal("Error in file::read_oob_callback()\n");
+#endif
+
+  /* files[fd].errno=0; */
+
+  s=simple_do_read_oob(&i, fd);
+
+  /* Note: OOB ackets may have zero size */
+  if(i>=0)
+  {
+    assign_svalue_no_free(sp++, &files[fd].id);
+    push_string(s);
+    apply_svalue(& files[fd].read_oob_callback, 2);
+    pop_stack();
+    return;
+  }
+  
+  if(i < 0)
+  {
+    /* files[fd].errno=errno; */
+    switch(errno)
+    {
+    case EINTR:
+    case EWOULDBLOCK:
+      return;
+    }
+  }
+}
+#endif /* WITH_OOB */
+
 static void file_set_read_callback(INT32 args)
 {
   if(FD < 0)
@@ -843,6 +1151,46 @@ static void file_set_write_callback(INT32 args)
   pop_n_elems(args);
 }
 
+#ifdef WITH_OOB
+static void file_set_read_oob_callback(INT32 args)
+{
+  if(FD < 0)
+    error("File is not open.\n");
+
+  if(args < 1)
+    error("Too few arguments to file->set_read_oob_callback().\n");
+
+  assign_svalue(& THIS->read_oob_callback, sp-args);
+
+  if(IS_ZERO(& THIS->read_oob_callback))
+  {
+    set_read_oob_callback(FD, 0, 0);
+  }else{
+    set_read_oob_callback(FD, file_read_oob_callback, 0);
+  }
+  pop_n_elems(args);
+}
+
+static void file_set_write_oob_callback(INT32 args)
+{
+  if(FD < 0)
+    error("File is not open.\n");
+
+  if(args < 1)
+    error("Too few arguments to file->set_write_oob_callback().\n");
+
+  assign_svalue(& THIS->write_oob_callback, sp-args);
+
+  if(IS_ZERO(& THIS->write_oob_callback))
+  {
+    set_write_oob_callback(FD, 0, 0);
+  }else{
+    set_write_oob_callback(FD, file_write_oob_callback, 0);
+  }
+  pop_n_elems(args);
+}
+#endif /* WITH_OOB */
+
 static void file_set_close_callback(INT32 args)
 {
   if(FD < 0)
@@ -870,7 +1218,13 @@ static void file_set_nonblocking(INT32 args)
 
   switch(args)
   {
+#ifdef WITH_OOB
+  default: pop_n_elems(args-5);
+  case 5: file_set_write_oob_callback(1);
+  case 4: file_set_read_oob_callback(1);
+#else /* !WITH_OOB */
   default: pop_n_elems(args-3);
+#endif /* WITH_OOB */
   case 3: file_set_close_callback(1);
   case 2: file_set_write_callback(1);
   case 1: file_set_read_callback(1);
@@ -888,6 +1242,16 @@ static void file_set_blocking(INT32 args)
   free_svalue(& THIS->write_callback);
   THIS->write_callback.type=T_INT;
   THIS->write_callback.u.integer=0;
+
+#ifdef WITH_OOB
+  free_svalue(& THIS->read_oob_callback);
+  THIS->read_oob_callback.type=T_INT;
+  THIS->read_oob_callback.u.integer=0;
+  free_svalue(& THIS->write_oob_callback);
+  THIS->write_oob_callback.type=T_INT;
+  THIS->write_oob_callback.u.integer=0;
+#endif /* WITH_OOB */
+
   free_svalue(& THIS->close_callback);
   THIS->close_callback.type=T_INT;
   THIS->close_callback.u.integer=0;
@@ -896,6 +1260,10 @@ static void file_set_blocking(INT32 args)
   {
     set_read_callback(FD, 0, 0);
     set_write_callback(FD, 0, 0);
+#ifdef WITH_OOB
+    set_read_oob_callback(FD, 0, 0);
+    set_write_oob_callback(FD, 0, 0);
+#endif /* WITH_OOB */
     set_nonblocking(FD,0);
     THIS->open_mode &=~ FILE_NONBLOCKING;
   }
@@ -966,6 +1334,26 @@ static void file_query_write_callback(INT32 args)
   assign_svalue_no_free(sp++,& THIS->write_callback);
 }
 
+#ifdef WITH_OOB
+static void file_query_read_oob_callback(INT32 args)
+{
+  if(FD < 0)
+    error("File not open.\n");
+
+  pop_n_elems(args);
+  assign_svalue_no_free(sp++,& THIS->read_oob_callback);
+}
+
+static void file_query_write_oob_callback(INT32 args)
+{
+  if(FD < 0)
+    error("File not open.\n");
+
+  pop_n_elems(args);
+  assign_svalue_no_free(sp++,& THIS->write_oob_callback);
+}
+#endif /* WITH_OOB */
+
 static void file_query_close_callback(INT32 args)
 {
   if(FD < 0)
@@ -1250,7 +1638,7 @@ static void file_pipe(INT32 args)
       break;
     }
     
-    error("Cannot create a pipe patching those parameters.\n");
+    error("Cannot create a pipe matching those parameters.\n");
   }while(0);
     
   if(i<0)
@@ -1298,6 +1686,10 @@ static void gc_mark_file_struct(struct object *o)
   {
     gc_mark_svalues(& THIS->read_callback,1);
     gc_mark_svalues(& THIS->write_callback,1);
+#ifdef WITH_OOB
+    gc_mark_svalues(& THIS->read_oob_callback,1);
+    gc_mark_svalues(& THIS->write_oob_callback,1);
+#endif /* WITH_OOB */
     gc_mark_svalues(& THIS->close_callback,1);
     gc_mark_svalues(& THIS->id,1);
   }
@@ -1387,6 +1779,12 @@ static void file_dup2(INT32 args)
 
   assign_svalue_no_free(& files[fd].read_callback, & THIS->read_callback);
   assign_svalue_no_free(& files[fd].write_callback, & THIS->write_callback);
+#ifdef WITH_OOB
+  assign_svalue_no_free(& files[fd].read_oob_callback,
+			& THIS->read_oob_callback);
+  assign_svalue_no_free(& files[fd].write_oob_callback,
+			& THIS->write_oob_callback);
+#endif /* WITH_OOB */
   assign_svalue_no_free(& files[fd].close_callback, & THIS->close_callback);
   assign_svalue_no_free(& files[fd].id, & THIS->id);
 
@@ -1403,6 +1801,22 @@ static void file_dup2(INT32 args)
   }else{
     set_write_callback(fd, file_write_callback, 0);
   }
+
+#ifdef WITH_OOB  
+  if(IS_ZERO(& THIS->read_oob_callback))
+  {
+    set_read_oob_callback(fd, 0,0);
+  }else{
+    set_read_oob_callback(fd, file_read_oob_callback, 0);
+  }
+  
+  if(IS_ZERO(& THIS->write_oob_callback))
+  {
+    set_write_oob_callback(fd, 0,0);
+  }else{
+    set_write_oob_callback(fd, file_write_oob_callback, 0);
+  }
+#endif /* WITH_OOB */
   
   pop_n_elems(args);
   push_int(1);
@@ -1909,6 +2323,28 @@ void mark_ids(struct callback *foo, void *bar, void *gazonk)
       tmp=0;
     }
 
+#ifdef WITH_OOB
+    if(query_read_oob_callback(e)!=file_read_oob_callback)
+    {
+      gc_check_svalues( & files[e].read_oob_callback, 1);
+    }else{
+#ifdef DEBUG
+      debug_gc_xmark_svalues( & files[e].read_oob_callback, 1, "File->read_oob_callback");
+#endif
+      tmp=0;
+    }
+
+    if(query_write_oob_callback(e)!=file_write_oob_callback)
+    {
+      gc_check_svalues( & files[e].write_oob_callback, 1);
+    }else{
+#ifdef DEBUG
+      debug_gc_xmark_svalues( & files[e].write_oob_callback, 1, "File->write_callback");
+#endif
+      tmp=0;
+    }
+#endif /* WITH_OOB */
+
     if(tmp)
     {
       gc_check_svalues( & files[e].id, 1);
@@ -1954,6 +2390,10 @@ void pike_module_init(void)
   add_function("close",file_close,"function(string|void:int)",0);
   add_function("read",file_read,"function(int|void,int|void:int|string)",0);
   add_function("write",file_write,"function(string,void|mixed...:int)",0);
+#ifdef WITH_OOB
+  add_function("read_oob",file_read_oob,"function(int|void,int|void:int|string)",0);
+  add_function("write_oob",file_write_oob,"function(string,void|mixed...:int)",0);
+#endif /* WITH_OOB */
 
   add_function("seek",file_seek,"function(int,int|void,int|void:int)",0);
   add_function("tell",file_tell,"function(:int)",0);
@@ -1961,9 +2401,17 @@ void pike_module_init(void)
   add_function("errno",file_errno,"function(:int)",0);
 
   add_function("set_close_on_exec",file_set_close_on_exec,"function(int:void)",0);
+#ifdef WITH_OOB
+  add_function("set_nonblocking",file_set_nonblocking,"function(mixed|void,mixed|void,mixed|void,mixed|void,mixed|void:void)",0);
+#else /* !WITH_OOB */
   add_function("set_nonblocking",file_set_nonblocking,"function(mixed|void,mixed|void,mixed|void:void)",0);
+#endif /* WITH_OOB */
   add_function("set_read_callback",file_set_read_callback,"function(mixed:void)",0);
   add_function("set_write_callback",file_set_write_callback,"function(mixed:void)",0);
+#ifdef WITH_OOB
+  add_function("set_read_oob_callback",file_set_read_oob_callback,"function(mixed:void)",0);
+  add_function("set_write_oob_callback",file_set_write_oob_callback,"function(mixed:void)",0);
+#endif /* WITH_OOB */
   add_function("set_close_callback",file_set_close_callback,"function(mixed:void)",0);
 
   add_function("set_blocking",file_set_blocking,"function(:void)",0);
@@ -1973,6 +2421,10 @@ void pike_module_init(void)
   add_function("query_id",file_query_id,"function(:mixed)",0);
   add_function("query_read_callback",file_query_read_callback,"function(:mixed)",0);
   add_function("query_write_callback",file_query_write_callback,"function(:mixed)",0);
+#ifdef WITH_OOB
+  add_function("query_read_oob_callback",file_query_read_oob_callback,"function(:mixed)",0);
+  add_function("query_write_oob_callback",file_query_write_oob_callback,"function(:mixed)",0);
+#endif /* WITH_OOB */
   add_function("query_close_callback",file_query_close_callback,"function(:mixed)",0);
 
   add_function("dup",file_dup,"function(:object)",0);
diff --git a/src/modules/files/file.h b/src/modules/files/file.h
index 8a59b2b8a9..967cd6c74e 100644
--- a/src/modules/files/file.h
+++ b/src/modules/files/file.h
@@ -30,6 +30,10 @@ struct my_file
   struct svalue id;
   struct svalue read_callback;
   struct svalue write_callback;
+#ifdef WITH_OOB
+  struct svalue read_oob_callback;
+  struct svalue write_oob_callback;
+#endif /* WITH_OOB */
   struct svalue close_callback;
 #ifdef HAVE_FD_FLOCK
   struct object *key;
-- 
GitLab