diff -r -N -U 3 socat-1.6.0.0/procan.c socat-1.6.0.0+maxfds/procan.c
--- procan.c.orig	2006-12-28 08:25:01.000000000 +0100
+++ procan.c	2007-04-05 12:41:26.000000000 +0200
@@ -161,6 +161,10 @@
 #endif
    }
 
+   /* C defines */
+   fprintf(outfile, "#define FD_SETSIZE %u\n", FD_SETSIZE);
+   fprintf(outfile, "#define FOPEN_MAX %u\n", FOPEN_MAX);
+
    /* file descriptors */
 
    /* what was this for?? */
diff -r -N -U 3 socat-1.6.0.0/socat.c socat-1.6.0.0+maxfds/socat.c
--- socat.c.orig	2007-03-06 22:03:28.000000000 +0100
+++ socat.c	2007-03-31 22:24:37.000000000 +0200
@@ -642,8 +642,8 @@
    returns >0 if child died and left data
 */
 int childleftdata(xiofile_t *xfd) {
-   fd_set in, out, expt;
-   int retval;
+   fd_set *in = NULL, *out = NULL, *expt = NULL;
+   int max, retval;
    /* have to check if a child process died before, but left read data */
    if (XIO_READABLE(xfd) &&
        (XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
@@ -652,25 +652,59 @@
        XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
       struct timeval time0 = { 0,0 };
 
-      FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
+#ifndef howmany
+#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+#endif
+
+#ifndef NFDBITS
+#     ifndef HAVE_FDS_BITS
+#           define NFDBITS (sizeof(__fd_mask) * 8)
+#     else
+#           define NFDBITS (sizeof(fd_mask) * 8)
+#     endif
+#endif
+
+#ifndef HAVE_FDS_BITS
+#     define FD_MASK_SIZE (sizeof(__fd_mask))
+#else
+#     define FD_MASK_SIZE (sizeof(fd_mask))
+#endif
+
+      max = XIO_GETRDFD(xfd);
+      in = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+      out = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+      expt = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+      if (in == NULL || out == NULL || expt == NULL) {
+         Error2("select(%d): %s", max+1, strerror(errno));
+         if (in != NULL)
+               free(in);
+         if (out != NULL)
+               free(out);
+         if (expt != NULL)
+               free(expt);
+         return -1;
+      }
       if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
-	 FD_SET(XIO_GETRDFD(xfd), &in);
+	 FD_SET(XIO_GETRDFD(xfd), in);
 	 /*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/
       }
       do {
-	 retval = Select(FOPEN_MAX, &in, &out, &expt, &time0);
+	 retval = Select(max+1, in, out, expt, &time0);
       } while (retval < 0 && errno == EINTR);
 
       if (retval < 0) {
 #if HAVE_FDS_BITS
 	 Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
-		FOPEN_MAX, in.fds_bits[0], out.fds_bits[0],
-		expt.fds_bits[0], strerror(errno));
+		max+1, in->fds_bits[0], out->fds_bits[0],
+		expt->fds_bits[0], strerror(errno));
 #else
 	 Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s",
-		FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0],
-		expt.__fds_bits[0], strerror(errno));
+		max+1, in->__fds_bits[0], out->__fds_bits[0],
+		expt->__fds_bits[0], strerror(errno));
 #endif
+         free(in);
+         free(out);
+         free(expt);
 	 return -1;
       } else if (retval == 0) {
 	 Info("terminated child did not leave data for us");
@@ -679,6 +713,9 @@
 	 closing = MAX(closing, 1);
       }
    }
+   free(in);
+   free(out);
+   free(expt);
    return 0;
 }
 
@@ -694,14 +731,34 @@
    and their options are set/applied
    returns -1 on error or 0 on success */
 int _socat(void) {
-   fd_set in, out, expt;
-   int retval;
+   fd_set *in, *out, *expt;
+   int max, retval;
    unsigned char *buff;
    ssize_t bytes1, bytes2;
    int polling = 0;	/* handling ignoreeof */
    int wasaction = 1;	/* last select was active, do NOT sleep before next */
    struct timeval total_timeout;	/* the actual total timeout timer */
 
+#ifndef MAX
+#     define MAX(x, y) (((y) > (x)) ? (y) : (x))
+#endif
+
+   max = MAX(
+      MAX(XIO_GETRDFD(sock1), XIO_GETWRFD(sock1)),
+      MAX(XIO_GETRDFD(sock2), XIO_GETWRFD(sock2)));
+   in = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+   out = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+   expt = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE);
+   if (in == NULL || out == NULL || expt == NULL) {
+       Error2("select(%d): %s", max+1, strerror(errno));
+       if (in != NULL)
+           free(in);
+       if (out != NULL)
+           free(out);
+       if (expt != NULL)
+           free(expt);
+       return -1;
+   }
 #if WITH_FILAN
    if (socat_opts.debug) {
       int fdi, fdo;
@@ -733,7 +790,7 @@
 
    /* when converting nl to crnl, size might double */
    buff = Malloc(2*socat_opts.bufsiz+1);
-   if (buff == NULL)  return -1;
+   if (buff == NULL)  { free(in); free(out); free(expt); return -1; }
 
    if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
       Info("switching to syslog");
@@ -772,6 +829,9 @@
 	       if (total_timeout.tv_sec < 0 ||
 		   total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
 		  Notice("inactivity timeout triggered");
+                  free(in);
+                  free(out);
+                  free(expt);
 		  return 0;
 	       }
 	    }
@@ -803,7 +863,9 @@
 
       do {
 	 int _errno;
-	 FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt);
+         memset(in, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE);
+         memset(out, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE);
+         memset(expt, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE);
 
 	 childleftdata(sock1);
 	 childleftdata(sock2);
@@ -819,23 +881,23 @@
 	     !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
 	     !socat_opts.righttoleft) {
 	    if (!mayrd1) {
-	       FD_SET(XIO_GETRDFD(sock1), &in);
+	       FD_SET(XIO_GETRDFD(sock1), in);
 	    }
 	    if (!maywr2) {
-	       FD_SET(XIO_GETWRFD(sock2), &out);
+	       FD_SET(XIO_GETWRFD(sock2), out);
 	    }
 	 }
 	 if (XIO_READABLE(sock2) &&
 	     !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
 	     !socat_opts.lefttoright) {
 	    if (!mayrd2) {
-	       FD_SET(XIO_GETRDFD(sock2), &in);
+	       FD_SET(XIO_GETRDFD(sock2), in);
 	    }
 	    if (!maywr1) {
-	       FD_SET(XIO_GETWRFD(sock1), &out);
+	       FD_SET(XIO_GETWRFD(sock1), out);
 	    }
 	 }
-	 retval = Select(FOPEN_MAX, &in, &out, &expt, to);
+	 retval = Select(max+1, in, out, expt, to);
 	 _errno = errno;
 	 if (retval < 0 && errno == EINTR) {
 	    Info1("select(): %s", strerror(errno));
@@ -851,15 +913,18 @@
       if (retval < 0) {
 #if HAVE_FDS_BITS
 	    Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
-		   FOPEN_MAX, in.fds_bits[0], out.fds_bits[0],
-		   expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
+		   max+1, in->fds_bits[0], out->fds_bits[0],
+		   expt->fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
 		   strerror(errno));
 #else
 	    Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s",
-		   FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0],
-		   expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
+		   max+1, in->__fds_bits[0], out->__fds_bits[0],
+		   expt->__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0,
 		   strerror(errno));
 #endif
+            free(in);
+            free(out);
+            free(expt);
 	    return -1;
       } else if (retval == 0) {
 	 Info2("select timed out (no data within %ld.%06ld seconds)",
@@ -872,6 +937,9 @@
 		    socat_opts.total_timeout.tv_usec != 0) {
 	    /* there was a total inactivity timeout */
 	    Notice("inactivity timeout triggered");
+            free(in);
+            free(out);
+            free(expt);
 	    return 0;
 	 }
 
@@ -884,17 +952,17 @@
       }
 
       if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
-	  FD_ISSET(XIO_GETRDFD(sock1), &in)) {
+	  FD_ISSET(XIO_GETRDFD(sock1), in)) {
 	 mayrd1 = true;
       }
       if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
-	  FD_ISSET(XIO_GETRDFD(sock2), &in)) {
+	  FD_ISSET(XIO_GETRDFD(sock2), in)) {
 	 mayrd2 = true;
       }
-      if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), &out)) {
+      if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), out)) {
 	 maywr1 = true;
       }
-      if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), &out)) {
+      if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), out)) {
 	 maywr2 = true;
       }
 
@@ -989,6 +1057,10 @@
    xioclose(sock1);
    xioclose(sock2);
 
+   free(in);
+   free(out);
+   free(expt);
+
    return 0;
 }
 
diff -r -N -U 3 socat-1.6.0.0/test.sh socat-1.6.0.0+maxfds/test.sh
--- test.sh.orig	2007-03-06 22:06:20.000000000 +0100
+++ test.sh	2007-04-06 10:16:30.000000000 +0200
@@ -1425,7 +1425,8 @@
     local arg1="$3";	[ -z "$arg1" ] && arg1="-"
     local arg2="$4";	[ -z "$arg2" ] && arg2="echo"
     local opts="$5"
-    local T="$6";	[ -z "$T" ] && T=0
+    local redir="$6"
+    local T="$7";	[ -z "$T" ] && T=0
     local tf="$td/test$N.stdout"
     local te="$td/test$N.stderr"
     local tdiff="$td/test$N.diff"
@@ -1435,14 +1436,16 @@
     $PRINTF "test $F_n %s... " $num "$title"
     #echo "$da" |$cmd >"$tf" 2>"$te"
 #set -vx
-    (echo "$da"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" &
+#    (echo "$da"; sleep $T) |($SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"; echo $? >"$td/test$N.rc") &
+#    echo eval $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" $redir
+    (echo "$da"; sleep $T) |(eval $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" $redir; echo $? >"$td/test$N.rc") &
     export rc1=$!
     #sleep 5 && kill $rc1 2>/dev/null &
 #    rc2=$!
     wait $rc1
 #    kill $rc2 2>/dev/null
-#set +vx
-    if [ "$?" != 0 ]; then
+set +vx
+    if [ "$(cat "$td/test$N.rc")" != 0 ]; then
 	$PRINTF "$FAILED: $SOCAT:\n"
 	echo "$SOCAT $opts $arg1 $arg2"
 	cat "$te"
@@ -4129,7 +4132,7 @@
 case "$TESTS" in
 *%functions%*|*%$NAME%*)
 TEST="$NAME: inheritance of stdout to single exec with socketpair"
-testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1
+testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" "" 1
 esac
 N=$((N+1))
 
@@ -4137,7 +4140,7 @@
 case "$TESTS" in
 *%functions%*|*%$NAME%*)
 TEST="$NAME: inheritance of stdout to single exec with pipe"
-testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1
+testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" "" 1
 esac
 N=$((N+1))
 
@@ -4149,7 +4152,7 @@
     $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
     numCANT=$((numCANT+1))
 else
-testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1
+testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" "" 1
 fi
 esac
 N=$((N+1))
@@ -4178,7 +4181,7 @@
     $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N
     numCANT=$((numCANT+1))
 else
-testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY
+testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" "" $MISCDELAY
 fi
 esac
 N=$((N+1))
@@ -5662,7 +5665,7 @@
 case "$TESTS" in
 *%parse%*|*%functions%*|*%$NAME%*)
 TEST="$NAME: does lexical analysis work sensibly (exec)"
-testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" 1
+testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" "" 1
 esac
 N=$((N+1))
 
@@ -5670,7 +5673,7 @@
 case "$TESTS" in
 *%parse%*|*%functions%*|*%$NAME%*)
 TEST="$NAME: does lexical analysis work sensibly (system)"
-testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" 1
+testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" "" 1
 esac
 N=$((N+1))
 
@@ -7737,6 +7740,81 @@
 esac
 N=$((N+1))
 
+
+# test: up to socat 1.6.0.0, the highest file descriptor supported in socats
+# transfer engine was FOPEN_MAX-1; this usually worked fine but would fail when
+# socat was invoked with many file descriptors already opened. socat would 
+# just hang in the select() call. Daniel Lucq found this problem and provided a
+# patch that replaced the FOPEN_MAX limit: this patch not only allows FDs to be
+# up to NFDBITS-1, but should work even when the processes maximum number of
+# open files is increased with ulimit -n.
+# FOPEN_MAX on different OS's:
+#   OS			FOPEN_	ulimit	ulimit	FD_
+#			MAX	-H -n	-S -n	SETSIZE
+#   Linux 2.6:		16	1024	1024	1024
+#   HP-UX 11.11:	60	2048	2048	2048
+#   FreeBSD:		20	11095	11095	1024
+#   Cygwin:		20	unlimit	256	64
+#   AIX:		32767	65534		65534
+NAME=EXCEED_FOPEN_MAX
+case "$TESTS" in
+*%functions%*|*%maxfds%*|*%$NAME%*)
+TEST="$NAME: more than FOPEN_MAX FDs in use"
+# this test opens a number of FDs before socat is invoked. socat will have to
+# allocate higher FD numbers and thus hang if it cannot handle them.
+REDIR=
+FOPEN_MAX=$($PROCAN |grep '^#define FOPEN_MAX' |awk '{print($3);}')
+OPEN_FILES=$FOPEN_MAX	# more than the highest FOPEN_MAX
+i=3; while [ "$i" -lt "$OPEN_FILES" ]; do
+    REDIR="$REDIR $i>&2"
+    i=$((i+1))
+done
+#echo $REDIR
+#testecho "$N" "$TEST" "" "pipe" "$opts -T 3" "" 1 
+#set -vx
+testecho "$N" "$TEST" "" "pipe" "$opts -T 1" "$REDIR" 1
+#set +vx
+esac
+N=$((N+1))
+
+OPEN_FILES="$(ulimit -n)"
+NAME=EXCEED_FD_SETSIZE
+case "$TESTS" in
+*%functions%*|*%maxfds%*|*%root%*|*%$NAME%*)
+TEST="$NAME: more than FD_SETSIZE FDs in use"
+# this test opens a number of FDs before socat is invoked. This number exceeds
+# the size of the fd_set type proposed for use with select(). socat will have
+# to allocate space for a larger record and will hang or crash if it cannot
+# handle this.
+# ulimit -n must be above FD_SETSIZE which might require root
+REDIR=
+FD_SETSIZE=$($PROCAN |grep '^#define FD_SETSIZE' |awk '{print($3);}')
+OPEN_FILES=$(($FD_SETSIZE+2))	# more than the highest FD_SETSIZE
+while true; do	# just go once; so we can break inside
+ if [ $(ulimit -S -n) -lt $OPEN_FILES ]; then
+ # if it increases, -H must be first
+    if [ $(ulimit -H -n) -lt $OPEN_FILES ]; then
+	if ! ulimit -H -n $((OPEN_FILES)); then
+	    $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N
+	    numCANT=$((numCANT+1))
+	    break;
+	fi
+    fi
+    ulimit -S -n $((OPEN_FILES))
+ fi
+ i=3; while [ "$i" -lt "$FD_SETSIZE" ]; do
+    REDIR="$REDIR $i>&2"
+    i=$((i+1))
+ done
+ testecho "$N" "$TEST" "" "pipe" "$opts -T 1" "$REDIR" 1
+ set +vx
+break
+done
+;;
+esac
+N=$((N+1))
+
+
 echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
 
 if [ "$numFAIL" -gt 0 ]; then
diff -r -N -U 3 socat-1.6.0.0/VERSION socat-1.6.0.0+maxfds/VERSION
--- VERSION.orig	2007-03-06 21:58:44.000000000 +0100
+++ VERSION	2007-04-06 23:20:11.000000000 +0200
@@ -1 +1 @@
-"1.6.0.0"
+"1.6.0.0_1"
