[Spread-cvs] commit: r878 - in trunk: . buildtools daemon include libspread

jschultz at spread.org jschultz at spread.org
Mon Jan 23 03:45:41 EST 2017


Author: jschultz
Date: 2017-01-23 03:45:40 -0500 (Mon, 23 Jan 2017)
New Revision: 878

Modified:
   trunk/buildtools/fixpaths
   trunk/configure
   trunk/configure.in
   trunk/daemon/config.h.in
   trunk/daemon/config_gram.l
   trunk/daemon/configuration.c
   trunk/daemon/sess_types.h
   trunk/include/sp.h
   trunk/libspread/sp.c
   trunk/release_announcement_5.0.txt
Log:
configure.in: Added checks for poll, poll.h, select, sys/select.h and sin6_len field of sockaddr_in6.  Check for clock_gettime in -lrt.
config_gram.l: Set sin_len and sin6_len in sockaddr's in parse_ip.
configuration.c: Suppress an IPv6 specific print when using IPv4.
sp.h, sess_types.h: Exported a new error type ILLEGAL_TIME.
sp.c: Rewrote SP_connect* to more cleanly and properly handle signals interrupting I/O.  Can now return ILLEGAL_TIME if user passes an invalid delta time.
buildtools/fixpaths: Minor change to get rid of deprecated warnings.



Modified: trunk/buildtools/fixpaths
===================================================================
--- trunk/buildtools/fixpaths	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/buildtools/fixpaths	2017-01-23 08:45:40 UTC (rev 878)
@@ -5,7 +5,7 @@
 
 $usage = "Usage: $0 [-Dstring=replacement] [[infile] ...]\n";
 
-if (!defined(@ARGV)) { die ("$usage"); }
+if (! @ARGV) { die ("$usage"); }
 
 # read in the command line and get some definitions
 while ($_=$ARGV[0], /^-/) {
@@ -23,7 +23,7 @@
   }
 } # while parsing arguments
 
-if (!defined(%def)) {
+if (! %def) {
   die ("$0: nothing to do - no substitutions listed!\n");
 }
 

Modified: trunk/configure
===================================================================
--- trunk/configure	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/configure	2017-01-23 08:45:40 UTC (rev 878)
@@ -4912,7 +4912,52 @@
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
+else
+  ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRT 1
+_ACEOF
+
+  LIBS="-lrt $LIBS"
+
+fi
+
+
 for ac_func in strftime
 do :
   ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
@@ -4970,7 +5015,7 @@
 
 
 # Checks for header files.
-for ac_header in arpa/inet.h assert.h errno.h grp.h limits.h netdb.h netinet/in.h netinet/tcp.h process.h pthread.h pwd.h signal.h stdarg.h stdint.h stdio.h stdlib.h string.h sys/inttypes.h sys/ioctl.h sys/param.h sys/socket.h sys/stat.h sys/time.h sys/timeb.h sys/types.h sys/uio.h sys/un.h sys/filio.h time.h unistd.h windows.h winsock2.h ifaddrs.h
+for ac_header in arpa/inet.h assert.h errno.h grp.h limits.h netdb.h netinet/in.h netinet/tcp.h process.h pthread.h pwd.h signal.h stdarg.h stdint.h stdio.h stdlib.h string.h sys/inttypes.h sys/ioctl.h sys/param.h sys/socket.h sys/stat.h sys/time.h sys/timeb.h sys/types.h sys/uio.h sys/un.h sys/filio.h sys/select.h time.h unistd.h windows.h winsock2.h ifaddrs.h poll.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -4984,7 +5029,7 @@
 done
 
 
-for ac_func in bcopy inet_aton inet_ntoa inet_ntop memmove setsid snprintf strerror lrand48 getifaddrs
+for ac_func in bcopy inet_aton inet_ntoa inet_ntop memmove setsid snprintf strerror lrand48 getifaddrs select poll
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -6224,6 +6269,43 @@
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin6_len field in sockaddr_in6" >&5
+$as_echo_n "checking for sin6_len field in sockaddr_in6... " >&6; }
+if ${ac_cv_have_sin6_len_in_struct_sockaddr_in6+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+ struct sockaddr_in6 s; s.sin6_len = sizeof(s);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+   ac_cv_have_sin6_len_in_struct_sockaddr_in6="yes"
+else
+   ac_cv_have_sin6_len_in_struct_sockaddr_in6="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_sin6_len_in_struct_sockaddr_in6" >&5
+$as_echo "$ac_cv_have_sin6_len_in_struct_sockaddr_in6" >&6; }
+if test x"$ac_cv_have_sin6_len_in_struct_sockaddr_in6" = "xyes"; then
+
+$as_echo "#define HAVE_SIN6_LEN_IN_SOCKADDR_IN6 1 " >>confdefs.h
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ss_family field in struct sockaddr_storage" >&5
 $as_echo_n "checking for ss_family field in struct sockaddr_storage... " >&6; }
 if ${ac_cv_have_ss_family_in_struct_ss+:} false; then :

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/configure.in	2017-01-23 08:45:40 UTC (rev 878)
@@ -102,14 +102,15 @@
 AC_SEARCH_LIBS(shm_open, rt posix4, [], [])
 AC_SEARCH_LIBS(nanosleep, rt posix4, [], [])
 AC_CHECK_LIB(m, sqrt)
+AC_CHECK_LIB(rt, clock_gettime)
 
 AC_FUNC_STRFTIME
 
 # Checks for header files.
-AC_CHECK_HEADERS(arpa/inet.h assert.h errno.h grp.h limits.h netdb.h netinet/in.h netinet/tcp.h process.h pthread.h pwd.h signal.h stdarg.h stdint.h stdio.h stdlib.h string.h sys/inttypes.h sys/ioctl.h sys/param.h sys/socket.h sys/stat.h sys/time.h sys/timeb.h sys/types.h sys/uio.h sys/un.h sys/filio.h time.h unistd.h windows.h winsock2.h ifaddrs.h)
+AC_CHECK_HEADERS(arpa/inet.h assert.h errno.h grp.h limits.h netdb.h netinet/in.h netinet/tcp.h process.h pthread.h pwd.h signal.h stdarg.h stdint.h stdio.h stdlib.h string.h sys/inttypes.h sys/ioctl.h sys/param.h sys/socket.h sys/stat.h sys/time.h sys/timeb.h sys/types.h sys/uio.h sys/un.h sys/filio.h sys/select.h time.h unistd.h windows.h winsock2.h ifaddrs.h poll.h)
 
 dnl    Checks for library functions.
-AC_CHECK_FUNCS(bcopy inet_aton inet_ntoa inet_ntop memmove setsid snprintf strerror lrand48 getifaddrs)
+AC_CHECK_FUNCS(bcopy inet_aton inet_ntoa inet_ntop memmove setsid snprintf strerror lrand48 getifaddrs select poll)
 dnl    Checks for time functions
 AC_CHECK_FUNCS(gettimeofday time)
 
@@ -550,6 +551,23 @@
    	AC_DEFINE(HAVE_SIN_LEN_IN_SOCKADDR_IN, 1 ,[sockaddr_in type has sin_len field])
 fi
 
+AC_CACHE_CHECK([for sin6_len field in sockaddr_in6],
+		ac_cv_have_sin6_len_in_struct_sockaddr_in6, [
+	AC_TRY_COMPILE(
+  		[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+		],
+		[ struct sockaddr_in6 s; s.sin6_len = sizeof(s); ],
+		[ ac_cv_have_sin6_len_in_struct_sockaddr_in6="yes" ],
+		[ ac_cv_have_sin6_len_in_struct_sockaddr_in6="no"],
+	)
+])
+if test x"$ac_cv_have_sin6_len_in_struct_sockaddr_in6" = "xyes"; then
+   	AC_DEFINE(HAVE_SIN6_LEN_IN_SOCKADDR_IN6, 1 ,[sockaddr_in6 type has sin6_len field])
+fi
+
 AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage],
 		ac_cv_have_ss_family_in_struct_ss, [
 	AC_TRY_COMPILE(

Modified: trunk/daemon/config.h.in
===================================================================
--- trunk/daemon/config.h.in	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/daemon/config.h.in	2017-01-23 08:45:40 UTC (rev 878)
@@ -3,7 +3,6 @@
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
-
 /* Building on a Windows OS Platform */
 #undef ARCH_PC_WIN95
 
@@ -109,6 +108,12 @@
 /* pid_t type */
 #undef HAVE_PID_T
 
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
 /* Define to 1 if you have the <process.h> header file. */
 #undef HAVE_PROCESS_H
 
@@ -127,12 +132,18 @@
 /* sockaddr type has sa_len field */
 #undef HAVE_SA_LEN_IN_SOCKADDR
 
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
 /* Define to 1 if you have the `setsid' function. */
 #undef HAVE_SETSID
 
 /* Define to 1 if you have the <signal.h> header file. */
 #undef HAVE_SIGNAL_H
 
+/* sockaddr_in6 type has sin6_len field */
+#undef HAVE_SIN6_LEN_IN_SOCKADDR_IN6
+
 /* sockaddr_in type has sin_len field */
 #undef HAVE_SIN_LEN_IN_SOCKADDR_IN
 
@@ -217,6 +228,9 @@
 /* Define to 1 if you have the <sys/param.h> header file. */
 #undef HAVE_SYS_PARAM_H
 
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
 /* Define to 1 if you have the <sys/socket.h> header file. */
 #undef HAVE_SYS_SOCKET_H
 
@@ -283,6 +297,9 @@
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
 
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 

Modified: trunk/daemon/config_gram.l
===================================================================
--- trunk/daemon/config_gram.l	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/daemon/config_gram.l	2017-01-23 08:45:40 UTC (rev 878)
@@ -132,12 +132,18 @@
     val->addr.ipaddr.ipv4.sin_family = AF_INET;
     val->addr.ipaddr.ipv4.sin_addr   = ipv4addr;
     val->addr.ipaddr.ipv4.sin_port   = htons((int16u) port);
+#ifdef HAVE_SIN_LEN_IN_STRUCT_SOCKADDR_IN
+    val->addr.ipaddr.ipv4.sin_len    = sizeof(val->addr.ipaddr.ipv4);
+#endif    
   }
   else
   {
     val->addr.ipaddr.ipv6.sin6_family = AF_INET6;
     val->addr.ipaddr.ipv6.sin6_addr   = ipv6addr;
     val->addr.ipaddr.ipv6.sin6_port   = htons((int16u) port);
+#ifdef HAVE_SIN6_LEN_IN_STRUCT_SOCKADDR_IN6
+    val->addr.ipaddr.ipv6.sin6_len    = sizeof(val->addr.ipaddr.ipv6);
+#endif    
 
     if (hasif)
     {

Modified: trunk/daemon/configuration.c
===================================================================
--- trunk/daemon/configuration.c	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/daemon/configuration.c	2017-01-23 08:45:40 UTC (rev 878)
@@ -462,11 +462,14 @@
             continue;
           }
 
-          if (spu_addr_family(&My.ifc[i].ifaddr) == AF_INET6 && My.ifc[i].ifaddr.ipv6.sin6_scope_id == 0)
-            if ((My.ifc[i].ifaddr.ipv6.sin6_scope_id = ips[j].ipv6.sin6_scope_id) == 0)
+          if (spu_addr_family(&My.ifc[i].ifaddr) == AF_INET6)
+          {
+            if (My.ifc[i].ifaddr.ipv6.sin6_scope_id == 0 &&
+                (My.ifc[i].ifaddr.ipv6.sin6_scope_id = ips[j].ipv6.sin6_scope_id) == 0)
               My.ifc[i].ifaddr.ipv6.sin6_scope_id = scope_id;
 
-          Alarmp(SPLOG_INFO, CONF_SYS, "Conf_load_conf_file: using sin6_scope_id %u for interface %s\n", (unsigned) My.ifc[i].ifaddr.ipv6.sin6_scope_id, SPU_ADDR_NTOP(&My.ifc[i].ifaddr));
+            Alarmp(SPLOG_INFO, CONF_SYS, "Conf_load_conf_file: using sin6_scope_id %u for interface %s\n", (unsigned) My.ifc[i].ifaddr.ipv6.sin6_scope_id, SPU_ADDR_NTOP(&My.ifc[i].ifaddr));
+          }
         }
         
 	Alarmp(SPLOG_INFO, CONF_SYS, "Conf_load_conf_file: My name: %s, id: %s, addr: %s, port: %u\n",

Modified: trunk/daemon/sess_types.h
===================================================================
--- trunk/daemon/sess_types.h	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/daemon/sess_types.h	2017-01-23 08:45:40 UTC (rev 878)
@@ -142,6 +142,7 @@
 #define         MESSAGE_TOO_LONG        -17
 #define         NET_ERROR_ON_SESSION    -18
 #define         SP_BUG                  -19
+#define         ILLEGAL_TIME            -20
 
 typedef	struct	dummy_message_header {
 	int32u	type;

Modified: trunk/include/sp.h
===================================================================
--- trunk/include/sp.h	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/include/sp.h	2017-01-23 08:45:40 UTC (rev 878)
@@ -67,6 +67,10 @@
 #define         MAX_PRIVATE_NAME        10 /* largest possible size of private_name field of SP_connect() */
 #define         MAX_PROC_NAME           20 /* largest possible size of process name of daemon (includes nul terminator) */
 
+#if MAX_PRIVATE_NAME >= 128
+#  error "MAX_PRIVATE_NAME must fit in one signed byte!"
+#endif    
+    
 #define         UNRELIABLE_MESS         0x00000001
 #define         RELIABLE_MESS           0x00000002
 #define         FIFO_MESS               0x00000004
@@ -132,6 +136,7 @@
 #define         MESSAGE_TOO_LONG        (-17)
 #define         NET_ERROR_ON_SESSION    (-18)
 #define         SP_BUG                  (-19)
+#define         ILLEGAL_TIME            (-20)
 
 #define		MAX_CLIENT_SCATTER_ELEMENTS	100
 

Modified: trunk/libspread/sp.c
===================================================================
--- trunk/libspread/sp.c	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/libspread/sp.c	2017-01-23 08:45:40 UTC (rev 878)
@@ -53,12 +53,20 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
+#  ifdef HAVE_SYS_SELECT_H
+#    include <sys/select.h>
+#  endif
+
+#  ifdef HAVE_POLL
+#    include <poll.h>
+#  endif
+
 #else	/* ARCH_PC_WIN95 */
 
 #include <winsock2.h>
 #define ioctl   ioctlsocket
 
-	WSADATA		WSAData;
+WSADATA	WSAData;
 
 #endif	/* ARCH_PC_WIN95 */
 
@@ -145,16 +153,395 @@
 static	int		Num_sessions = 0;
 static	sp_session	Sessions[MAX_LIB_SESSIONS];
 
-static  sp_time         Zero_timeout = { 0, 0 };
-
 static	void    Flip_mess( message_header *head_ptr );
 static	int	SP_get_session( mailbox mbox );
+
+static  int     SP_connect_timeout_low( const char *spread_name, const char *private_name,
+                                        int priority, int group_membership, mailbox *mbox,
+                                        char *private_group, sp_time *time_out );
+
 static	int	SP_internal_multicast( mailbox mbox, service service_type, 
 				       int num_groups,
 				       const char groups[][MAX_GROUP_NAME],
 				       int16 mess_type,
 				       const scatter *scat_mess );
 
+/* wait_nointr waits for read or write readiness on one socket while
+ * ignoring signal interruptions with an optional absolute timeout.
+ *
+ * Returns 0 on success when the socket is ready in time and non-zero
+ * otherwise.
+ *
+ * Returns 1 on timeout, otherwise returns -1 with the specific error
+ * indicated in sock_errno.
+ */
+
+static int wait_nointr( int sock, int readable, const sp_time *abs_time_out )
+#ifdef HAVE_POLL
+{
+    int ret;
+    int tmp;
+
+    do
+    {
+        struct pollfd fd    = { 0 };
+        int           to_ms = -1;
+        
+        fd.fd     = sock;
+        fd.events = ( readable ? POLLIN : POLLOUT );
+
+        if ( abs_time_out )
+        {
+            sp_time t = E_sub_time( *abs_time_out, E_get_time_monotonic() );
+
+            if ( t.sec < 0 || t.usec < 0 )
+            {
+                ret = 1;
+                break;
+            }
+            else if ( t.sec >= INT_MAX / 1000 )
+                to_ms = INT_MAX;
+
+            else
+                to_ms = ( int ) ( t.sec * 1000 + ( t.usec + 999 ) / 1000 );
+        }
+    
+        tmp = poll( &fd, 1, to_ms );
+
+        switch ( tmp )
+        {
+        case 1:  ret =  0; break;
+        case 0:  ret =  1; break;
+        default: ret = -1; break;
+        }
+    }
+    while ( tmp == -1 && sock_errno == EINTR );
+    
+    return ret;
+}
+#else
+{
+    int ret;
+    int tmp;
+
+    do
+    {
+        struct timeval sel_time_ptr = NULL;
+        struct timeval sel_time;
+        fd_set         sel_set;
+
+        FD_ZERO( &sel_set );
+        FD_SET( sock, &sel_set );
+
+        if ( abs_time_out )
+        {
+            sp_time t = E_sub_time( *abs_time_out, E_get_time_monotonic() );
+
+            if ( t.sec < 0 || t.usec < 0 )
+            {
+                ret = 1;
+                break;
+            }
+
+            sel_time.tv_sec  = t.sec;
+            sel_time.tv_usec = t.usec;
+            sel_time_ptr     = &sel_time;
+        }
+
+        tmp = select( s + 1, ( readable ? &sel_set : NULL ), ( readable ? NULL : &sel_set ), NULL, sel_time_ptr );
+
+        switch ( tmp )
+        {
+        case 1:  ret =  0; break;
+        case 0:  ret =  1; break;
+        default: ret = -1; break;
+        }
+    }
+    while ( tmp == -1 && sock_errno == EINTR );
+    
+    return ret;
+}
+#endif
+
+/* connect_nointr calls connect on a socket while ignoring signal
+ * interruptions with an optional absolute timeout.
+ *
+ * Returns 0 on success when the socket is connected in time and
+ * non-zero otherwise.
+ * 
+ * Returns 1 on timeout, otherwise returns -1 with the specific error
+ * indicated in sock_errno.
+ */
+
+static int connect_nointr( int s, struct sockaddr *addr, socklen_t addr_len, sp_time *abs_time_out )
+{
+    int       ret;
+    int       err;
+    socklen_t err_len;
+
+    if ( ( ret = connect( s, addr, addr_len ) ) != 0 && ( sock_errno == EINPROGRESS || sock_errno == EINTR || sock_errno == EAGAIN || sock_errno == EWOULDBLOCK ) )
+    {
+        ret = wait_nointr( s, 0, abs_time_out );
+
+        switch ( ret )
+        {
+        case 0:   /* writeable */
+            if ( ( ret = getsockopt( s, SOL_SOCKET, SO_ERROR, ( err = 0, &err ), ( err_len = sizeof( err ), &err_len ) ) ) == 0 && err != 0 )
+            {
+                sock_set_errno( err );
+                ret = -1;
+            }            
+            break;
+            
+        case 1:   /* timed out */
+            break;
+            
+        default:  /* error */
+            break;
+        }
+    }
+
+    return ret;
+}
+
+#if 0
+/* recv_n_nointr calls recv repeatedly until either a total of exactly
+ * n bytes have been received or an error occurs, all while ignoring
+ * signal interruptions.
+ * 
+ * recv_n_nointr returns the remaining number of bytes left to recv.
+ * On success, it returns 0.  On failure, the non-zero number of bytes
+ * left to recv is returned and sock_errno indicates the error.
+ *
+ * If n is less than zero, then the call will immediately return n and
+ * sock_errno will be set to EINVAL.  If n is zero, then the call will
+ * immediately succeed and return 0.
+ *
+ * This function is meant to be used with blocking sockets.  If called
+ * on a non-blocking socket, then a short read and a blocking error
+ * can be returned.
+ *
+ * NOTE: We don't use MSG_WAITALL as there are reports of large
+ * receives improperly blocking forever with this option on some
+ * implementations when OS buffers are full.
+ */
+
+static int recv_n_nointr( int s, char *b, int n )
+{
+    int tmp;
+
+    for ( ; n > 0; n -= tmp, b += tmp )
+    {
+        tmp = ( int ) recv( s, b, n, 0 );
+    
+        if ( tmp <= 0 )
+        {
+            if ( tmp == -1 && sock_errno == EINTR )
+                tmp = 0;
+
+            else
+            {
+                if ( tmp == 0 )
+                    sock_set_errno( ECONNRESET );
+                    
+                break;
+            }
+        }
+    }
+  
+    if ( n < 0 )
+        sock_set_errno( EINVAL );  /* handle cases where n was initially negative or tmp > n */
+  
+    return n;
+}
+
+/* send_n_nointr calls send repeatedly until either a total of
+ * exactly n bytes have been sent or an error occurs, all while
+ * ignoring signal interruptions.
+ * 
+ * send_n_nointr returns the remaining number of bytes left to send.
+ * On success, it returns 0.  On failure, the non-zero number of bytes
+ * left to send is returned with sock_errno indicating the error.
+ *
+ * This function is meant to be used with blocking sockets.  If called
+ * on a non-blocking socket, then a short send and a blocking error
+ * can be returned.
+ */
+
+static int send_n_nointr( int s, char *b, int n )
+{
+    int tmp;
+
+    for ( ; n > 0; n -= tmp, b += tmp )
+    {
+        tmp = ( int ) send( s, b, n, 0 );
+      
+        if ( tmp <= 0 )
+        {
+            if ( tmp == -1 && sock_errno == EINTR )
+                tmp = 0;
+
+            else
+            {
+                if ( tmp == 0 )
+                    sock_set_errno( ECONNRESET );
+
+                break;
+            }
+        }
+    }
+    
+    if ( n < 0 )
+        sock_set_errno( EINVAL );  /* handle cases where n was initially negative or tmp > n */
+  
+    return n;
+}
+#endif
+
+/* recv_n_nointr_nb calls recv repeatedly until either a total of
+ * exactly n bytes have been received, an error occurs, or an optional
+ * absolute timeout expires, all while ignoring signal interruptions.
+ *
+ * recv_n_nointr_nb returns the remaining number of bytes left to
+ * recv.  On success, it returns 0.  On failure, the non-zero number
+ * of bytes left to recv is returned and sock_errno indicates the
+ * error.  If the timeout expires before all n bytes could be
+ * received, then the non-zero number of bytes left to recv is
+ * returned and sock_errno will be set to EAGAIN.
+ *
+ * If n is less than zero, then the call will immediately return n and
+ * sock_errno will be set to EINVAL.  If n is zero, then the call will
+ * immediately succeed and return 0.
+ *
+ * abs_time_out can be NULL, in which case the timeout is infinite.
+ *
+ * This function is meant to be used with nonblocking sockets.  If
+ * called on a blocking socket, then any timeout may not be respected
+ * and the function can block for arbitrary periods of time.
+ *
+ * NOTE: We don't use MSG_WAITALL as there are reports of large
+ * receives improperly blocking forever with this option on some
+ * implementations when OS buffers are full.
+ */
+
+static int recv_n_nointr_nb( int s, char *b, int n, const sp_time *abs_time_out )
+{
+    int tmp;
+
+    for ( ; n > 0; n -= tmp, b += tmp )
+    {
+        /* check if optional timeout has expired */
+          
+        if ( abs_time_out && E_compare_time( E_get_time_monotonic(), *abs_time_out ) >= 0 )
+        {
+            sock_set_errno( EAGAIN );
+            break;
+        }
+          
+        /* recv and handle error cases; fatal errors break loop, non-fatal errors set tmp = 0 and continue */
+          
+        tmp = ( int ) recv( s, b, n, 0 );
+
+        if ( tmp <= 0 )
+        {
+            if ( tmp == -1 && ( sock_errno == EAGAIN || sock_errno == EWOULDBLOCK ) )
+            {
+                if ( ( tmp = wait_nointr( s, 1, abs_time_out ) ) != 0 )
+                {
+                    if ( tmp == 1 )
+                        sock_set_errno( EAGAIN );
+                        
+                    break;
+                }
+            }
+            else if ( tmp != -1 || sock_errno != EINTR )
+            {
+                if ( tmp == 0 )
+                    sock_set_errno( ECONNRESET );
+
+                break;
+            }
+
+            tmp = 0;
+        }
+    }
+
+    if ( n < 0 )
+        sock_set_errno( EINVAL );  /* handle cases where n was initially negative or tmp > n */
+
+    return n;
+}  
+
+/* send_n_nointr_nb calls send repeatedly until either a total of
+ * exactly n bytes have been sent, an error occurs, or an optional
+ * absolute timeout expires, all while ignoring signal interruptions.
+ *
+ * send_n_nointr_nb returns the remaining number of bytes left to
+ * send.  On success, it returns 0.  On failure, the non-zero number
+ * of bytes left to send is returned and sock_errno indicates the
+ * error.  If the timeout expires before all n bytes could be sent,
+ * then the non-zero number of bytes left to send is returned and
+ * sock_errno will be set to EAGAIN.  
+ *
+ * If n is less than zero, then the call will immediately return n and
+ * sock_errno will be set to EINVAL.  If n is zero, then the call will
+ * immediately succeed and return 0.
+ *
+ * abs_time_out can be NULL, in which case the timeout is infinite.
+ *
+ * This function is meant to be used with nonblocking sockets.  If
+ * called on a blocking socket, then any timeout may not be respected
+ * and the function can block for arbitrary periods of time.
+ */
+
+static int send_n_nointr_nb( int s, char *b, int n, const sp_time *abs_time_out )
+{
+    int tmp;
+
+    for ( ; n > 0; n -= tmp, b += tmp )
+    {
+        /* check if optional timeout has expired */
+          
+        if ( abs_time_out && E_compare_time( E_get_time_monotonic(), *abs_time_out ) >= 0 )
+        {
+            sock_set_errno( EAGAIN );
+            break;
+        }
+          
+        /* send and handle error cases; fatal errors break loop, non-fatal errors set tmp = 0 and continue */
+          
+        tmp = (int) send( s, b, n, 0 );
+
+        if ( tmp <= 0 )
+        {
+            if ( tmp == -1 && ( sock_errno == EAGAIN || sock_errno == EWOULDBLOCK ) )
+            {
+                if ( ( tmp = wait_nointr( s, 0, abs_time_out ) ) != 0 )
+                {
+                    if ( tmp == 1 )
+                        sock_set_errno( EAGAIN );
+                    
+                    break;
+                }
+            }
+            else if ( tmp != -1 || sock_errno != EINTR )
+            {
+                if ( tmp == 0 )
+                    sock_set_errno( ECONNRESET );
+
+                break;
+            }
+
+            tmp = 0;
+        }
+    }
+
+    if ( n < 0 )
+        sock_set_errno( EINVAL );  /* handle cases where n was initially negative or tmp > n */
+
+    return n;
+}  
+
 /* This is a null authenticate method that does nothing */
 
 static  int     sp_null_authenticate(int fd, void * auth_data)
@@ -271,172 +658,7 @@
 
         return;
 }
-/* This calls recv() with the additional features of ignoring syscall interruptions
- * caused by signals delivered to this application, and of returning in at most *time_out time.
- * When it returns the *time_out variable will be modified to have contain the value:
- * old *time_out - time spent in this function.
- *
- * If *time_out == {0,0} then the call is made blocking and will NOT timeout.
- */
-static  int     recv_nointr_timeout(int s, void *buf, size_t len, int flags, sp_time *time_out)
-{
-        int ret, num_ready;
-        fd_set rset,fixed_rset;
-        sp_time start_time, temp_time, target_time, wait_time;
-        struct timeval  sel_time;
 
-        if ( len == 0 )
-                return(0);
-        if ( E_compare_time(Zero_timeout, *time_out) < 0 )
-        {
-                start_time = E_get_time();
-                target_time = E_add_time(start_time, *time_out);
-                wait_time = *time_out;
-                FD_ZERO(&fixed_rset);
-                FD_SET(s, &fixed_rset);
-                rset = fixed_rset;
-                sel_time.tv_sec = wait_time.sec;
-                sel_time.tv_usec = wait_time.usec;
-                while( ((num_ready = select(s+1, &rset, NULL, NULL, &sel_time)) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK)) )
-                {
-                        temp_time = E_get_time();
-                        if (E_compare_time(temp_time, target_time) < 0 ) {
-                                wait_time = E_sub_time(target_time, temp_time);
-                                sel_time.tv_sec = wait_time.sec;
-                                sel_time.tv_usec = wait_time.usec;
-                        } else {
-                                sock_set_errno( ERR_TIMEDOUT );
-                                return(-1);
-                        }
-                        rset = fixed_rset;
-                }
-                if ( !num_ready ) {
-                        sock_set_errno( ERR_TIMEDOUT );
-                        return(-1);
-                } 
-        }
-        while( ((ret = recv( s, buf, len, flags)) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK)) )
-                ;
-        if ( E_compare_time(Zero_timeout, *time_out) < 0 )
-        {
-                temp_time = E_sub_time(E_get_time(), start_time);
-                *time_out = E_sub_time(*time_out, temp_time);
-        }
-        return(ret);
-}
-
-/* This calls connect() with the additional features of ignoring syscall interruptions
- * caused by signals delivered to this application, and of returning in at most *time_out time.
- * When it returns the *time_out variable will be modified to have contain the value:
- * old *time_out - time spent in this function.
- *
- * If *time_out == {0,0} then the call is made blocking and will NOT timeout.
- */
-static  int     connect_nointr_timeout(int s, struct sockaddr *sname, socklen_t slen, sp_time *time_out)
-{
-    int         ret, num_ready;
-    fd_set      rset,fixed_rset,wset;
-    sp_time     start_time, temp_time, target_time, wait_time;
-    struct timeval sel_time;
-    int         non_blocking = 0;
-    int         err = 0;
-    int         on;
-    int         ret_ioctl;
-    sockopt_len_t   elen;
-
-    /* initialize time values even if blocking so later use is valid */
-    start_time = E_get_time();
-    target_time = E_add_time(start_time, *time_out);
-    wait_time = *time_out;
-    sel_time.tv_sec = wait_time.sec;
-    sel_time.tv_usec = wait_time.usec;
-
-    if ( E_compare_time(Zero_timeout, *time_out) < 0 )
-    {
-        /* set file descriptor to non-blocking */
-        non_blocking = 1;
-        on = 1;
-        ret_ioctl = ioctl( s, FIONBIO, &on);
-    }
-    /* Handle EINTR while connecting by waiting with select until the 
-     * connect completes or fails.  This is a while loop but it is never 
-     * done more then once. The while is so we can use 'break' 
-     */
-    while( ((ret = connect( s, sname, slen ) ) == -1) 
-           && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK) || (sock_errno == EINPROGRESS)) )
-    {
-        FD_ZERO(&fixed_rset);
-        FD_SET(s, &fixed_rset);
-        rset = fixed_rset;
-        wset = rset;
-        Alarmp( SPLOG_DEBUG, SESSION, "connect_nointr_timeout: connect in progress for socket %d, now wait in select\n", s);
-        /* wait for select to timeout (num_ready == 0), give a permanent error (num_ready < 0 && sock_errno != transient). If transient error, retry after checking to make sure timeout has not expired */
-        while( ((num_ready = select(s+1, &rset, &wset, NULL, &sel_time)) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK)) )
-        {
-            temp_time = E_get_time();
-            if (E_compare_time(temp_time, target_time) < 0 ) {
-                wait_time = E_sub_time(target_time, temp_time);
-                sel_time.tv_sec = wait_time.sec;
-                sel_time.tv_usec = wait_time.usec;
-            } else {
-                Alarmp( SPLOG_WARNING, SESSION, "connect_nointr_timeout: connect interrupted and select wait timesout during transient error: %s\n", sock_strerror(sock_errno));
-                close(s);
-                sock_set_errno( ERR_TIMEDOUT );
-                ret = -1;
-                goto done_connect_try;
-            }
-            rset = fixed_rset;
-            wset = rset;
-        }
-        if ( num_ready == 0 ) {
-            /* timeout */
-            close(s);
-            sock_set_errno( ERR_TIMEDOUT );
-            ret = -1;
-            break;
-        } else if ( num_ready < 0 ) 
-        {
-            Alarmp( SPLOG_WARNING, SESSION, "connect_nointr_timeout: connect interrupted and error in select wait: %s\n", sock_strerror(sock_errno));
-            ret = -1;
-            break;
-        } 
-        if (FD_ISSET(s, &rset) || FD_ISSET( s, &wset))
-        {
-            err = 0;
-            elen = sizeof(err);
-            if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&err, &elen) < 0)
-            {
-                ret = -1;
-                break;
-            }
-            if (err)
-            {
-                sock_set_errno( err );
-                ret = -1;
-            } else {
-                ret = 0;
-            }
-            break;
-        } else {
-            Alarmp( SPLOG_FATAL, SESSION, "connect_nointr_timeout: connect interrupted--but select does not indicate either error or connecting socket ready. Impossible condition (i.e. bug).  ret= %d: %s\n", err, sock_strerror(sock_errno));
-            ret = -1;
-            break;
-        }
-    } /* while error case for connect */
-    Alarmp( SPLOG_DEBUG, SESSION, "connect_nointr_timeout: After connect, ret = %d error is:%s\n", ret, sock_strerror(sock_errno));
-
-done_connect_try:
-    if ( non_blocking )
-    {
-        /* set file descriptor to blocking */
-        on = 0;
-        ret_ioctl = ioctl( s, FIONBIO, &on);
-        temp_time = E_sub_time(E_get_time(), start_time);
-        *time_out = E_sub_time(*time_out, temp_time);
-    }
-    return(ret);
-}
-
 /* Increase socket buffer size to 200Kb if possible.
  * Used in SP_connect family when connection is established.
  */
@@ -558,20 +780,37 @@
 		    int priority, int group_membership, mailbox *mbox,
 		    char *private_group )
 {
-        int ret;
-
-        ret = SP_connect_timeout( spread_name, private_name, priority, group_membership, mbox, private_group, Zero_timeout);
-        return(ret);
+    return SP_connect_timeout_low( spread_name, private_name, priority, group_membership, mbox, private_group, NULL );
 }
 
 int	SP_connect_timeout( const char *spread_name, const char *private_name,
 		    int priority, int group_membership, mailbox *mbox,
 		    char *private_group, sp_time time_out )
 {
+    sp_time *t = NULL;
+
+    if ( ( time_out.sec < 0 && time_out.usec > 0 ) ||
+         ( time_out.sec > 0 && time_out.usec < 0 ) ||
+         ( time_out.usec <= -1000000 || time_out.usec >= 1000000 ) )
+        return ILLEGAL_TIME;
+    
+    if ( time_out.sec != 0 || time_out.usec != 0 )  /* NOTE: maintain existing API: timeout of (0, 0) means infinite timeout */
+    {
+        time_out = E_add_time( E_get_time_monotonic(), time_out );
+        t        = &time_out;
+    }
+    
+    return SP_connect_timeout_low( spread_name, private_name, priority, group_membership, mbox, private_group, t );
+}
+
+static int SP_connect_timeout_low( const char *spread_name, const char *private_name,
+                                   int priority, int group_membership, mailbox *mbox,
+                                   char *private_group, sp_time *abs_time_out )
+{
 	int16u			port;
 	char			host_name[SPREAD_MAXCONNECT_NAMELEN + 1];
-	char			conn[MAX_PRIVATE_NAME+5];
-        signed char             auth_list_len;
+	char                    conn[ 5 + MAX_PRIVATE_NAME ];
+        char                    auth_list_len;
         char                    auth_list[MAX_AUTH_NAME * MAX_AUTH_METHODS];
         char                    auth_choice[MAX_AUTH_NAME * MAX_AUTH_METHODS];
         bool                    failed;
@@ -581,10 +820,10 @@
 	int                     ses;
 	int                     base_ses;
 	int			ret, i;
-        unsigned int            len;
+        int                     len;
 	int			sp_v1, sp_v2, sp_v3;
-	char		        cval;
 	int32			on;
+        int                     tmp;
 
         spu_addr                addr      = { 0 };
 	struct sockaddr        *sock_addr;
@@ -637,7 +876,7 @@
 		break;
 
 #else	/* ARCH_PC_WIN95 */
-		/* win32: intentional fall through this case to option <port_num>@<host_name> where <host_name> = localhost */
+		/* NOTE: win32: intentional fall through this case to option <port_num>@<host_name> where <host_name> = localhost */
 		strcpy( host_name, "@localhost" );
 #endif	/* ARCH_PC_WIN95 */
 
@@ -722,15 +961,23 @@
 
 	set_large_socket_buffers(s);
 
-	ret = connect_nointr_timeout( s, sock_addr, sock_len, &time_out);
+        if ( ioctl( s, FIONBIO, ( tmp = 1, &tmp ) ) == -1 )
+        {
+		Alarm( SESSION, "SP_connect: unable to set non-blocking mode on mailbox %d: %s\n", s, sock_strerror( sock_errno ) );
+		close( s );
+		return( COULD_NOT_CONNECT );
+        }
+
+	ret = connect_nointr( s, sock_addr, sock_len, abs_time_out );
+        
 	if( ret < 0 )
 	{
 		Alarm( SESSION, "SP_connect: unable to connect mailbox %d: %s\n", s, sock_strerror(sock_errno));
 		close( s );
 		return( COULD_NOT_CONNECT );
 	}
-	/* 
-	 * connect message looks like:
+        
+        /* client connect message looks like:
 	 *
 	 * byte - version of lib
 	 * byte - subversion of lib
@@ -738,79 +985,78 @@
 	 * byte - lower half byte 1/0 with or without groups, upper half byte: priority (0/1).
 	 * byte - len of name
 	 * len bytes - name
-	 *
 	 */
+
+        len = 0;
+
+        if ( private_name != NULL &&
+             ( len = strlen( private_name ) ) > MAX_PRIVATE_NAME )
+                len = MAX_PRIVATE_NAME;
+        
 	conn[0] = SP_MAJOR_VERSION;
 	conn[1] = SP_MINOR_VERSION;
 	conn[2] = SP_PATCH_VERSION;
+        conn[3] = ( ( ( priority >= 1 ) << 4 ) | ( group_membership != 0 ) );
+	conn[4] = len;
+        memcpy( &conn[5], private_name, len );
 
-	if( group_membership ) conn[3] = 1; 
-	else conn[3] = 0;
-	if(priority < 0) priority = 0;
-	if(priority > 1) priority = 1;
-	conn[3] = conn[3]+16*priority;
+        ret = send_n_nointr_nb( s, conn, 5+len, abs_time_out );
 
-        if (private_name == NULL)
+        if ( ret )
         {
-                len = 0;
-        } else {
-                len = strlen(private_name);
-                if( len > MAX_PRIVATE_NAME ) len = MAX_PRIVATE_NAME;
-                memcpy( &conn[5], private_name, len );
-        }
-	conn[4] = len;
-	while(((ret = send( s, conn, len+5, 0 )) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK)) )
-                ;
-	if( ret != len+5 )
-	{
-		Alarm( SESSION, "SP_connect: unable to send name %d %d: %s\n", ret, len+5, sock_strerror(sock_errno));
+		Alarm( SESSION, "SP_connect: unable to send connect handshake %d %d: %s\n", ret, 5+len, sock_strerror(sock_errno));
 		close( s );
 		return( CONNECTION_CLOSED );
-	}
-        /* Insert Access control and authentication checks here */
-        auth_list_len = 0;
-        ret = recv_nointr_timeout( s, &auth_list_len, 1, 0, &time_out); 
-        if ( ret <= 0 )
+        }
+        
+        /* insert access control and authentication checks here */
+
+        ret = recv_n_nointr_nb( s, &auth_list_len, sizeof( auth_list_len ), abs_time_out );
+        
+        if ( ret )
         {
 		Alarm( SESSION, "SP_connect: unable to read auth_list_len %d: %s\n", ret, sock_strerror(sock_errno));
 		close( s );
 		return( CONNECTION_CLOSED );
         }
-        if ( auth_list_len > (MAX_AUTH_NAME * MAX_AUTH_METHODS) )
+        
+        if ( auth_list_len < 0 ) 
         {
-		Alarm( SESSION, "SP_connect: illegal value in auth_list_len %d: %s\n", auth_list_len, sock_strerror(sock_errno));
+                Alarm( SESSION, "SP_connect: connection invalid with code %d while reading auth_list_len\n", auth_list_len );
+                close( s );
+                return( auth_list_len );
+        }
+        
+        if ( auth_list_len > MAX_AUTH_NAME * MAX_AUTH_METHODS )
+        {
+		Alarm( SESSION, "SP_connect: illegal value in auth_list_len %d: %s\n", auth_list_len, sock_strerror(sock_errno) );
 		close( s );
 		return( CONNECTION_CLOSED );
-        } 
-        if ( auth_list_len < 0 ) 
-        {
-            Alarm( SESSION, "SP_connect: connection invalid with code %d while reading auth_list_len\n", auth_list_len);
-            close( s );
-            return( auth_list_len );
         }
-        if ( auth_list_len != 0 )
+
+        auth_list[0] = 0;
+        
+        ret = recv_n_nointr_nb( s, auth_list, auth_list_len, abs_time_out);
+                
+        if ( ret )
         {
-                ret = recv_nointr_timeout( s, auth_list, auth_list_len, 0, &time_out);
-                if ( ret <= 0 )
-                {
-                        Alarm( SESSION, "SP_connect: unable to read auth_list %d: %s\n", ret, sock_strerror(sock_errno));
-                        close( s );
-                        return( CONNECTION_CLOSED );
-                }
-
-                Alarm( SESSION, "SP_connect: DEBUG: Auth list is: %s\n", auth_list);
-        } else {
-                Alarm( SESSION, "SP_connect: DEBUG: Auth list is empty\n");
+                Alarm( SESSION, "SP_connect: unable to read auth_list %d: %s\n", ret, sock_strerror(sock_errno));
+                close( s );
+                return( CONNECTION_CLOSED );
         }
 
+        Alarm( SESSION, "SP_connect: DEBUG: Auth list is: '%s'\n", auth_list );
+
         /* Here is where we check the list of available methods of authentication and pick one. 
          * For right now we just ignore the list and use the method the app set in SP_set_auth_method.
          * If no method was set we use the NULL method.
          * The global Auth_Methods struct needs to be protected by the Struct_mutex.
          */
+        
         memset(auth_choice, 0, MAX_AUTH_NAME * MAX_AUTH_METHODS);
+        
         Mutex_lock( &Struct_mutex );
-        for (i=0; i< Num_Reg_Auth_Methods; i++)
+        for (i = 0; i < Num_Reg_Auth_Methods; i++)
         {
                 auth_methods[i] = Auth_Methods[i];
                 memcpy(&auth_choice[i * MAX_AUTH_NAME], Auth_Methods[i].name, MAX_AUTH_NAME);
@@ -818,7 +1064,7 @@
         num_auth_methods = Num_Reg_Auth_Methods;
         Mutex_unlock( &Struct_mutex );
 
-        for (i=0; i < num_auth_methods; i++)
+        for ( i = 0; i < num_auth_methods; i++ )
         {
                 if ( !valid_auth_method(auth_methods[i].name, auth_list, auth_list_len) )
                 {
@@ -827,9 +1073,10 @@
                         return( REJECT_AUTH );
                 }
         }
-	while(((ret = send( s, auth_choice, MAX_AUTH_NAME * MAX_AUTH_METHODS, 0 )) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK)) )
-                ;
-	if( ret != (MAX_AUTH_NAME * MAX_AUTH_METHODS) )
+
+        ret = send_n_nointr_nb( s, auth_choice, MAX_AUTH_NAME * MAX_AUTH_METHODS, abs_time_out );
+        
+	if ( ret )
 	{
 		Alarm( SESSION, "SP_connect: unable to send auth_name %d %d: %s\n", ret, MAX_AUTH_NAME * MAX_AUTH_METHODS, sock_strerror(sock_errno));
 		close( s );
@@ -843,72 +1090,82 @@
          * If failure (return 0) the SP_connect returns with an error REJECT_AUTH.
          * If authenticated (return 1 ), SP_connect continues with the rest of the connect protocol.
          */
+        
         failed = FALSE;
-        for (i = 0; i< num_auth_methods; i++)
+        
+        for ( i = 0; i < num_auth_methods; i++ )
         {
-                ret = auth_methods[i].authenticate(s, auth_methods[i].auth_data);
-                if (!ret)
+                ret = auth_methods[i].authenticate( s, auth_methods[i].auth_data );
+                
+                if ( !ret )
                 {
-                        Alarm( SESSION, "SP_connect: authentication of connection failed in method %s\n", auth_methods[i].name);
+                        Alarm( SESSION, "SP_connect: authentication of connection failed in method %s\n", auth_methods[i].name );
                         failed = TRUE;
                 }
         }
+        
         if ( failed )
         {
                 close ( s );
                 return( REJECT_AUTH );
         }
 
-	cval=0;
-        ret = recv_nointr_timeout( s, &cval, 1, 0, &time_out);
-	if( ret <= 0 )
+        /* server connect message looks like:
+	 *
+         * byte - accept / reject
+	 * byte - version of daemon
+	 * byte - subversion of daemon
+         * byte - patch version of daemon
+	 * byte - len of name
+	 * len bytes - name
+	 */
+
+        ret = recv_n_nointr_nb( s, conn, 5, abs_time_out );
+        
+	if ( ret )
 	{
-		Alarm( SESSION, "SP_connect: unable to read answer %d: %s\n", ret, sock_strerror(sock_errno));
-		close( s );
+                close( s );
+
+                if ( ret < 5 && conn[0] != ACCEPT_SESSION )
+                {
+                        Alarm( SESSION, "SP_connect: session rejected %d\n", conn[0] );
+                        return( conn[0] );
+                }
+                
+		Alarm( SESSION, "SP_connect: unable to read answer %d: %s\n", ret, sock_strerror(sock_errno) );
 		return( CONNECTION_CLOSED );
 	}
-	if( cval != ACCEPT_SESSION )
+        
+	if ( conn[0] != ACCEPT_SESSION )
 	{
-		Alarm( SESSION, "SP_connect: session rejected %d\n", cval);
 		close( s );
-		return( cval );
+		return( conn[0] );
 	}
-        ret = recv_nointr_timeout( s, &cval, 1, 0, &time_out);
-	if( ret <= 0 )
-	{
-		Alarm( SESSION, "SP_connect: unable to read version %d: %s\n", ret, sock_strerror(sock_errno));
-		close( s );
-		return( CONNECTION_CLOSED );
-	}
-	sp_v1 = cval;
 
-        ret = recv_nointr_timeout( s, &cval, 1, 0, &time_out);
-	if( ret <= 0 )
-	{
-		Alarm( SESSION, "SP_connect: unable to read subversion %d: %s\n", ret, sock_strerror(sock_errno));
-		close( s );
-		return( CONNECTION_CLOSED );
-	}
-	sp_v2 = cval;
+        sp_v1 = conn[1];
+        sp_v2 = conn[2];
+        sp_v3 = conn[3];
+        len   = conn[4];
+        
+	/* checking daemon version */
 
-        ret = recv_nointr_timeout( s, &cval, 1, 0, &time_out);
-	if( ret <= 0 )
-	{
-		Alarm( SESSION, "SP_connect: unable to read patch version %d: %s\n", ret, sock_strerror(sock_errno));
+        if ( sp_v1 < 0 || sp_v2 < 0 || sp_v3 < 0 || len < 0 || len >= MAX_GROUP_NAME )
+        {
+                Alarm( PRINT  , "SP_connect: illegal values received! %d.%d.%d; %d\n",
+                       sp_v1, sp_v2, sp_v3, len );
 		close( s );
 		return( CONNECTION_CLOSED );
-	}
-	sp_v3 = cval;
-
-	/* checking spread version. Should be at least 3.01 */
-	if( sp_v1*10000 + sp_v2*100 + sp_v3 < 30100 )
+        }
+        
+	if ( sp_v1 < 3 )
 	{
-		Alarm( PRINT  , "SP_connect: old spread version %d.%d.%d not suppoted\n", 
+		Alarm( PRINT  , "SP_connect: old daemon version %d.%d.%d not supported\n", 
 			sp_v1, sp_v2, sp_v3 );
 		close( s );
 		return( REJECT_VERSION );
 	}
-	if( (sp_v1*10000 + sp_v2*100 + sp_v3 < 30800) && priority > 0 )
+        
+	if ( priority > 0 && sp_v1 == 3 && sp_v2 < 8 )
 	{
 		Alarm( PRINT, "SP_connect: old spread version %d.%d.%d does not support priority other than 0\n", 
 			sp_v1, sp_v2, sp_v3 );
@@ -916,29 +1173,33 @@
 		return( REJECT_VERSION );
 	}
 
-        ret = recv_nointr_timeout( s, &cval, 1, 0, &time_out);
-	if( ret <= 0 )
+        ret = recv_n_nointr_nb( s, private_group, len, abs_time_out);
+        
+	if ( ret )
 	{
-		Alarm( SESSION, "SP_connect: unable to read size of group %d: %s\n", ret, sock_strerror(sock_errno));
-                close( s );
-		return( CONNECTION_CLOSED );
-	}
-	len = cval;
-        ret = recv_nointr_timeout( s, private_group, len, 0, &time_out);
-	if( ret <= 0 )
-	{
-		Alarm( SESSION, "SP_connect: unable to read private group %d:  %s\n", ret, sock_strerror(sock_errno));
+		Alarm( SESSION, "SP_connect: unable to read private group %d: %s\n", ret, sock_strerror(sock_errno));
 		close( s );
 		return( CONNECTION_CLOSED );
 	}
-	private_group[len]=0;
+        
+	private_group[len] = 0;
+        
 	Alarm( DEBUG, "SP_connect: connected with private group(%d bytes): %s\n", 
 		ret, private_group );
+        
 	*mbox = s;
 
+        if ( ioctl( s, FIONBIO, ( tmp = 0, &tmp ) ) == -1 )
+        {
+		Alarm( SESSION, "SP_connect: unable to set blocking mode on mailbox %d: %s\n", s, sock_strerror( sock_errno ) );
+		close( s );
+		return( CONNECTION_CLOSED );
+        }
+
 	Mutex_lock( &Struct_mutex );
 
-	if (Num_sessions >= MAX_LIB_SESSIONS) {
+	if (Num_sessions >= MAX_LIB_SESSIONS)
+        {
 	        Alarm( SESSION, "SP_connect: too many sessions in local process!\n");
 		close( s );
 		Mutex_unlock( &Struct_mutex );
@@ -951,13 +1212,13 @@
 
 	ses = base_ses = MBOX_TO_BASE_SES(s);
 
-	while( Sessions[ses].state != SESS_UNUSED ) {
-
-	        if( ++ses == MAX_LIB_SESSIONS) {
+	while( Sessions[ses].state != SESS_UNUSED )
+        {
+	        if( ++ses == MAX_LIB_SESSIONS)
 	                ses = 0;
-		}
 
-		if( ses == base_ses ) {
+		if( ses == base_ses )
+                {
 		        Alarm( SESSION, "SP_connect: BUG! No unused sessions when there should be!\n");
 			close( s );
 			Mutex_unlock( &Struct_mutex );
@@ -2164,6 +2425,7 @@
         case MESSAGE_TOO_LONG:     ret = "Message (body + group names) too large.";                       break;
         case NET_ERROR_ON_SESSION: ret = "Network socket error. SP_kill() the mailbox.";                  break;
         case SP_BUG:               ret = "Internal Spread bug detected.";                                 break;
+        case ILLEGAL_TIME:         ret = "Illegal time.";                                                 break;
 	}
 
         return ret;

Modified: trunk/release_announcement_5.0.txt
===================================================================
--- trunk/release_announcement_5.0.txt	2017-01-23 08:22:11 UTC (rev 877)
+++ trunk/release_announcement_5.0.txt	2017-01-23 08:45:40 UTC (rev 878)
@@ -1,12 +1,33 @@
-Spread 5.0.0 http://www.spread.org
+Spread 5.0.0 RC1 http://www.spread.org
 
-Spread Concepts LLC is happy to announce the release of a 
-new version, 5.0.0, of The Spread Toolkit. 
+Spread Concepts LLC is happy to announce a release candidate for a 
+new version, 5.0.0 RC1, of The Spread Toolkit.  It can be downloaded here:
 
-Spread 5.0 is an important release that adds support for IPv6.
+http://www.spread.org/download/spread-src-5.0.0rc1.tar.gz
 
-For details check the Readme.IPv6 and docs/sample.spread.conf files.
+Spread 5 is an important release that adds support for IPv6.
 
+Spread version 5 adds support for IPv6 in the Spread daemon, C
+language client library and several example and support programs
+(e.g. - spmonitor, spuser, spsend, sprecv, spflooder).  This version
+of Spread supports Posix environments (e.g. - Linux) and Windows.
+
+Spread 5 can work on IPv4-only hosts, IPv6-only hosts or dual stack
+hosts.  However, all daemons in a Spread deployment must run using
+only IPv4 or IPv6 addresses.  Spread 5 does not yet support
+configurations where some daemons use IPv4 addresses while others use
+IPv6 addresses, even if transition mechanisms such as network address
+translation (e.g. - stateless IP/ICMP translation) would allow such
+hosts to communicate using those addresses.
+
+Daemons' IP addresses can be configured explicitly or by using names
+which will be looked up using standard system services (i.e. - DNS,
+/etc/hosts, etc.) in order to map them back to IP addresses.  Clients
+can similarly specify either explicit addresses or names to connect to
+daemons.
+
+For more details check the Readme.IPv6 and docs/sample.spread.conf files.
+
 This release maintains the previous client API, so applications should
 be able to be relinked or recompiled with the new Spread library
 without changes.  However, if you used functionality from




More information about the Spread-cvs mailing list