[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