commit: r878 - in trunk: . buildtools daemon include libspread
[email protected] Mon, 23 Jan 2017 03:45:41 -0500
| Newsgroups | gmane.network.spread.cvs |
|---|---|
| Message-ID | <[email protected]> |
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