Compare commits

...
3 Commits
22 changed files with 2068 additions and 194 deletions
+15 -4
View File
@@ -19,9 +19,20 @@ rpm: dist-gzip
cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES" cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES"
rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@ rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@
## assumes --enable-static --disable-shared, so bin/hio-webs is the program
## itself and libhio is linked into it. what is still missing from a FROM scratch
## image is the system libraries it links against and the dynamic loader, so each
## goes in at the path it is loaded from - there is no /etc/ld.so.cache in the
## image to redirect the search.
docker: all docker: all
mkdir -p data rm -rf hio-webs-root hio-webs.tar
rm -rf data/* mkdir -p hio-webs-root/bin hio-webs-root/data
tar -cvf hio-webs.tar bin/hio-webs data cp bin/hio-webs hio-webs-root/bin/hio-webs
ldd bin/hio-webs | $(AWK) '$$2 == "=>" { print $$3 } $$1 ~ /^\// { print $$1 }' | \
while read -r so; do \
mkdir -p "hio-webs-root$${so%/*}"; \
cp -L "$$so" "hio-webs-root$$so" || exit 1; \
done
tar -C hio-webs-root -cvf hio-webs.tar .
docker build -t hio:webs -f Dockerfile . docker build -t hio:webs -f Dockerfile .
rm -f hio-webs.tar rm -rf hio-webs-root hio-webs.tar
+12 -4
View File
@@ -295,6 +295,8 @@ PTHREAD_LIBS = @PTHREAD_LIBS@
QUADMATH_LIBS = @QUADMATH_LIBS@ QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
SCTP_ENABLED = @SCTP_ENABLED@ SCTP_ENABLED = @SCTP_ENABLED@
SCTP_MULTIHOMING_ENABLED = @SCTP_MULTIHOMING_ENABLED@
SCTP_PEELOFF_ENABLED = @SCTP_PEELOFF_ENABLED@
SED = @SED@ SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@ SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
@@ -865,11 +867,17 @@ rpm: dist-gzip
rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@ rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@
docker: all docker: all
mkdir -p data rm -rf hio-webs-root hio-webs.tar
rm -rf data/* mkdir -p hio-webs-root/bin hio-webs-root/data
tar -cvf hio-webs.tar bin/hio-webs data cp bin/hio-webs hio-webs-root/bin/hio-webs
ldd bin/hio-webs | $(AWK) '$$2 == "=>" { print $$3 } $$1 ~ /^\// { print $$1 }' | \
while read -r so; do \
mkdir -p "hio-webs-root$${so%/*}"; \
cp -L "$$so" "hio-webs-root$$so" || exit 1; \
done
tar -C hio-webs-root -cvf hio-webs.tar .
docker build -t hio:webs -f Dockerfile . docker build -t hio:webs -f Dockerfile .
rm -f hio-webs.tar rm -rf hio-webs-root hio-webs.tar
# Tell versions [3.59,3.63) of GNU make to not export all variables. # Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded. # Otherwise a system limit (for SysV at least) may be exceeded.
+2
View File
@@ -329,6 +329,8 @@ PTHREAD_LIBS = @PTHREAD_LIBS@
QUADMATH_LIBS = @QUADMATH_LIBS@ QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
SCTP_ENABLED = @SCTP_ENABLED@ SCTP_ENABLED = @SCTP_ENABLED@
SCTP_MULTIHOMING_ENABLED = @SCTP_MULTIHOMING_ENABLED@
SCTP_PEELOFF_ENABLED = @SCTP_PEELOFF_ENABLED@
SED = @SED@ SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@ SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
Vendored
+215 -59
View File
@@ -689,6 +689,8 @@ ax_pthread_config
CPP CPP
SENDFILE_LIBS SENDFILE_LIBS
SOCKET_LIBS SOCKET_LIBS
SCTP_MULTIHOMING_ENABLED
SCTP_PEELOFF_ENABLED
SCTP_ENABLED SCTP_ENABLED
LIBM LIBM
MACOSX_FALSE MACOSX_FALSE
@@ -1860,6 +1862,65 @@ printf "%s\n" "$ac_res" >&6; }
} # ac_fn_check_decl } # ac_fn_check_decl
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) eval "$3=no"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
main (void)
{
if (sizeof ($2))
return 0;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
main (void)
{
if (sizeof (($2)))
return 0;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
else case e in #(
e) eval "$3=yes" ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_type
# ac_fn_c_try_cpp LINENO # ac_fn_c_try_cpp LINENO
# ---------------------- # ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded. # Try to preprocess conftest.$ac_ext, and return whether this succeeded.
@@ -1962,65 +2023,6 @@ printf "%s\n" "$ac_res" >&6; }
} # ac_fn_c_check_member } # ac_fn_c_check_member
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) eval "$3=no"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
main (void)
{
if (sizeof ($2))
return 0;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
main (void)
{
if (sizeof (($2)))
return 0;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
else case e in #(
e) eval "$3=yes" ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_type
# ac_fn_c_try_run LINENO # ac_fn_c_try_run LINENO
# ---------------------- # ----------------------
# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
@@ -16298,7 +16300,159 @@ printf "%s\n" "#define HIO_ENABLE_SCTP 1" >>confdefs.h
fi fi
fi fi
if test "x$SCTP_ENABLED" = "xyes"
then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sctp_bindx" >&5
printf %s "checking for library containing sctp_bindx... " >&6; }
if test ${ac_cv_search_sctp_bindx+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) ac_func_search_save_LIBS=$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.
The 'extern "C"' is for builds by C++ compilers;
although this is not generally supported in C code supporting it here
has little cost and some practical benefit (sr 110532). */
#ifdef __cplusplus
extern "C"
#endif
char sctp_bindx (void);
int
main (void)
{
return sctp_bindx ();
;
return 0;
}
_ACEOF
for ac_lib in '' sctp
do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi fi
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_search_sctp_bindx=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
if test ${ac_cv_search_sctp_bindx+y}
then :
break
fi
done
if test ${ac_cv_search_sctp_bindx+y}
then :
else case e in #(
e) ac_cv_search_sctp_bindx=no ;;
esac
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sctp_bindx" >&5
printf "%s\n" "$ac_cv_search_sctp_bindx" >&6; }
ac_res=$ac_cv_search_sctp_bindx
if test "$ac_res" != no
then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
ac_fn_c_check_func "$LINENO" "sctp_bindx" "ac_cv_func_sctp_bindx"
if test "x$ac_cv_func_sctp_bindx" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_BINDX 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "sctp_peeloff" "ac_cv_func_sctp_peeloff"
if test "x$ac_cv_func_sctp_peeloff" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_PEELOFF 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "sctp_getpaddrs" "ac_cv_func_sctp_getpaddrs"
if test "x$ac_cv_func_sctp_getpaddrs" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_GETPADDRS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "sctp_getladdrs" "ac_cv_func_sctp_getladdrs"
if test "x$ac_cv_func_sctp_getladdrs" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_GETLADDRS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "sctp_freepaddrs" "ac_cv_func_sctp_freepaddrs"
if test "x$ac_cv_func_sctp_freepaddrs" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_FREEPADDRS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "sctp_freeladdrs" "ac_cv_func_sctp_freeladdrs"
if test "x$ac_cv_func_sctp_freeladdrs" = xyes
then :
printf "%s\n" "#define HAVE_SCTP_FREELADDRS 1" >>confdefs.h
fi
if test "x$ac_cv_func_sctp_peeloff" = "xyes"
then
SCTP_PEELOFF_ENABLED="yes"
fi
if test "x$ac_cv_func_sctp_bindx" = "xyes" -a \
"x$ac_cv_func_sctp_getpaddrs" = "xyes" -a \
"x$ac_cv_func_sctp_getladdrs" = "xyes"
then
SCTP_MULTIHOMING_ENABLED="yes"
fi
ac_fn_c_check_type "$LINENO" "struct sctp_prim" "ac_cv_type_struct_sctp_prim" "
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
"
if test "x$ac_cv_type_struct_sctp_prim" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_SCTP_PRIM 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "struct sctp_setprim" "ac_cv_type_struct_sctp_setprim" "
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
"
if test "x$ac_cv_type_struct_sctp_setprim" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_SCTP_SETPRIM 1" >>confdefs.h
fi
fi
fi
test -z "$SCTP_PEELOFF_ENABLED" && SCTP_PEELOFF_ENABLED="no"
test -z "$SCTP_MULTIHOMING_ENABLED" && SCTP_MULTIHOMING_ENABLED="no"
ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" " ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "
#include <sys/types.h> #include <sys/types.h>
@@ -24904,6 +25058,8 @@ echo " Socket library: ${SOCKET_LIBS}"
echo " Sendfile library: ${SENDFILE_LIBS}" echo " Sendfile library: ${SENDFILE_LIBS}"
echo " SSL library: ${SSL_LIBS}" echo " SSL library: ${SSL_LIBS}"
echo " SCTP support: ${SCTP_ENABLED}" echo " SCTP support: ${SCTP_ENABLED}"
echo " SCTP peel-off: ${SCTP_PEELOFF_ENABLED}"
echo " SCTP multi-homing: ${SCTP_MULTIHOMING_ENABLED}"
echo "-------------------------------------------------------------------------" echo "-------------------------------------------------------------------------"
+42
View File
@@ -142,8 +142,48 @@ then
#include <netinet/in.h> #include <netinet/in.h>
]]) ]])
fi fi
if test "x$SCTP_ENABLED" = "xyes"
then
dnl these library calls are a separate matter from the socket type. on
dnl the bsds they are in libc; on linux they live in libsctp
dnl (lksctp-tools), which may well be absent on a machine whose kernel
dnl and headers have sctp. so they are probed on their own and the basic
dnl one-to-one and one-to-many support stands either way.
dnl
dnl peel-off and multi-homing are reported apart because they are
dnl separate features sharing nothing but the library they come from:
dnl peel-off needs sctp_peeloff() and multi-homing needs the address
dnl calls. a system missing one must not lose both.
AC_SEARCH_LIBS([sctp_bindx], [sctp])
AC_CHECK_FUNCS([sctp_bindx sctp_peeloff sctp_getpaddrs sctp_getladdrs sctp_freepaddrs sctp_freeladdrs])
if test "x$ac_cv_func_sctp_peeloff" = "xyes"
then
SCTP_PEELOFF_ENABLED="yes"
fi
if test "x$ac_cv_func_sctp_bindx" = "xyes" -a \
"x$ac_cv_func_sctp_getpaddrs" = "xyes" -a \
"x$ac_cv_func_sctp_getladdrs" = "xyes"
then
SCTP_MULTIHOMING_ENABLED="yes"
fi
dnl SCTP_PRIMARY_ADDR takes a structure the two families spell
dnl differently - struct sctp_prim on linux, struct sctp_setprim on
dnl the bsds - with identical members.
AC_CHECK_TYPES([struct sctp_prim, struct sctp_setprim], [], [], [[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
]])
fi
fi fi
AC_SUBST(SCTP_ENABLED) AC_SUBST(SCTP_ENABLED)
test -z "$SCTP_PEELOFF_ENABLED" && SCTP_PEELOFF_ENABLED="no"
AC_SUBST(SCTP_PEELOFF_ENABLED)
test -z "$SCTP_MULTIHOMING_ENABLED" && SCTP_MULTIHOMING_ENABLED="no"
AC_SUBST(SCTP_MULTIHOMING_ENABLED)
AC_CHECK_HEADERS([net/if.h net/if_dl.h netinet/if_ether.h netpacket/packet.h net/bpf.h], [], [], [ AC_CHECK_HEADERS([net/if.h net/if_dl.h netinet/if_ether.h netpacket/packet.h net/bpf.h], [], [], [
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>]) #include <sys/socket.h>])
@@ -947,5 +987,7 @@ echo " Socket library: ${SOCKET_LIBS}"
echo " Sendfile library: ${SENDFILE_LIBS}" echo " Sendfile library: ${SENDFILE_LIBS}"
echo " SSL library: ${SSL_LIBS}" echo " SSL library: ${SSL_LIBS}"
echo " SCTP support: ${SCTP_ENABLED}" echo " SCTP support: ${SCTP_ENABLED}"
echo " SCTP peel-off: ${SCTP_PEELOFF_ENABLED}"
echo " SCTP multi-homing: ${SCTP_MULTIHOMING_ENABLED}"
echo "-------------------------------------------------------------------------" echo "-------------------------------------------------------------------------"
] ]
+2
View File
@@ -374,6 +374,8 @@ PTHREAD_LIBS = @PTHREAD_LIBS@
QUADMATH_LIBS = @QUADMATH_LIBS@ QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
SCTP_ENABLED = @SCTP_ENABLED@ SCTP_ENABLED = @SCTP_ENABLED@
SCTP_MULTIHOMING_ENABLED = @SCTP_MULTIHOMING_ENABLED@
SCTP_PEELOFF_ENABLED = @SCTP_PEELOFF_ENABLED@
SED = @SED@ SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@ SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
+24
View File
@@ -295,6 +295,24 @@
/* Define to 1 if you have the 'recvmsg' function. */ /* Define to 1 if you have the 'recvmsg' function. */
#undef HAVE_RECVMSG #undef HAVE_RECVMSG
/* Define to 1 if you have the 'sctp_bindx' function. */
#undef HAVE_SCTP_BINDX
/* Define to 1 if you have the 'sctp_freeladdrs' function. */
#undef HAVE_SCTP_FREELADDRS
/* Define to 1 if you have the 'sctp_freepaddrs' function. */
#undef HAVE_SCTP_FREEPADDRS
/* Define to 1 if you have the 'sctp_getladdrs' function. */
#undef HAVE_SCTP_GETLADDRS
/* Define to 1 if you have the 'sctp_getpaddrs' function. */
#undef HAVE_SCTP_GETPADDRS
/* Define to 1 if you have the 'sctp_peeloff' function. */
#undef HAVE_SCTP_PEELOFF
/* Define to 1 if you have the 'select' function. */ /* Define to 1 if you have the 'select' function. */
#undef HAVE_SELECT #undef HAVE_SELECT
@@ -382,6 +400,12 @@
/* Define to 1 if the system has the type 'struct lifreq'. */ /* Define to 1 if the system has the type 'struct lifreq'. */
#undef HAVE_STRUCT_LIFREQ #undef HAVE_STRUCT_LIFREQ
/* Define to 1 if the system has the type 'struct sctp_prim'. */
#undef HAVE_STRUCT_SCTP_PRIM
/* Define to 1 if the system has the type 'struct sctp_setprim'. */
#undef HAVE_STRUCT_SCTP_SETPRIM
/* Define to 1 if 'sin6_scope_id' is a member of 'struct sockaddr_in6'. */ /* Define to 1 if 'sin6_scope_id' is a member of 'struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+141 -6
View File
@@ -262,6 +262,38 @@ typedef void (*hio_dev_sck_on_connect_t) (
* *
* Leave it unset to have notifications discarded. * Leave it unset to have notifications discarded.
*/ */
/**
* A decoded SCTP_ASSOC_CHANGE notification, as filled in by
* hio_dev_sck_parse_assoc_event(). The negotiated stream counts are worth
* having on their own: they are the outcome of the SCTP_INITMSG request from
* both ends, and are not knowable any other way.
*/
typedef struct hio_sctp_assoc_event_t hio_sctp_assoc_event_t;
struct hio_sctp_assoc_event_t
{
int state; /**< #hio_sctp_assoc_state_t */
int error; /**< the notification's error field, 0 if none */
hio_int32_t assoc_id; /**< pass this to hio_dev_sck_peeloff() */
hio_uint16_t ostreams; /**< outbound streams negotiated */
hio_uint16_t instreams; /**< inbound streams negotiated */
};
/**
* The states an association can report. The names mirror the SCTP_COMM_UP
* family so a reader of RFC 6458 recognises them, without the header's types
* appearing in this interface.
*/
enum hio_sctp_assoc_state_t
{
HIO_SCTP_ASSOC_COMM_UP = 0, /**< a new association is usable */
HIO_SCTP_ASSOC_COMM_LOST, /**< it failed */
HIO_SCTP_ASSOC_RESTART, /**< the peer restarted it */
HIO_SCTP_ASSOC_SHUTDOWN_COMP, /**< it closed in an orderly way */
HIO_SCTP_ASSOC_CANT_STR_ASSOC, /**< setup never completed */
HIO_SCTP_ASSOC_STATE_UNKNOWN /**< something this build does not name */
};
typedef enum hio_sctp_assoc_state_t hio_sctp_assoc_state_t;
typedef void (*hio_dev_sck_on_notification_t) ( typedef void (*hio_dev_sck_on_notification_t) (
hio_dev_sck_t* dev, hio_dev_sck_t* dev,
const void* data, const void* data,
@@ -297,8 +329,8 @@ enum hio_dev_sck_type_t
HIO_DEV_SCK_SCTP4, /* one-to-one sctp stream */ HIO_DEV_SCK_SCTP4, /* one-to-one sctp stream */
HIO_DEV_SCK_SCTP6, /* one-to-one sctp stream */ HIO_DEV_SCK_SCTP6, /* one-to-one sctp stream */
HIO_DEV_SCK_SCTP4_SP, /* one-to-one sctp seqpacket */ HIO_DEV_SCK_SCTP4_SEQPKT, /* one-to-one sctp seqpacket */
HIO_DEV_SCK_SCTP6_SP, /* one-to-one sctp seqpacket */ HIO_DEV_SCK_SCTP6_SEQPKT, /* one-to-one sctp seqpacket */
/* ICMP at the IPv4 layer */ /* ICMP at the IPv4 layer */
HIO_DEV_SCK_ICMP4, HIO_DEV_SCK_ICMP4,
@@ -388,12 +420,13 @@ struct hio_dev_sck_connect_t
hio_ntime_t connect_tmout; hio_ntime_t connect_tmout;
}; };
#if 0 /** flags for hio_dev_sck_bindx() */
enum hio_dev_sck_listen_option_t enum hio_dev_sck_bindx_flag_t
{ {
HIO_DEV_SCK_BINDX_ADD = 0, /**< add the addresses to the endpoint */
HIO_DEV_SCK_BINDX_REM = 1 /**< take them away from it */
}; };
typedef enum hio_dev_sck_listen_option_t hio_dev_sck_listen_option_t; typedef enum hio_dev_sck_bindx_flag_t hio_dev_sck_bindx_flag_t;
#endif
typedef struct hio_dev_sck_listen_t hio_dev_sck_listen_t; typedef struct hio_dev_sck_listen_t hio_dev_sck_listen_t;
struct hio_dev_sck_listen_t struct hio_dev_sck_listen_t
@@ -647,6 +680,108 @@ HIO_EXPORT int hio_dev_sck_shutdown (
int how /* bitwise-ORed of hio_dev_sck_shutdown_how_t enumerators */ int how /* bitwise-ORed of hio_dev_sck_shutdown_how_t enumerators */
); );
/**
* The hio_dev_sck_peeloff() function takes one association off a one-to-many
* SCTP socket and gives it a socket, and a device, of its own. The new device
* arrives through on_connect() in the #HIO_DEV_SCK_ACCEPTED state carrying the
* one-to-one methods - a write queue of its own, a read-enable bit of its own,
* and addresses of its own, which is what per-association multi-homing needs.
* It is the same door an accepted tcp connection comes through.
*
* It may be called at any point in an association's life, and where it is
* called from is the whole point:
*
* - from on_notification(), on an SCTP_COMM_UP whose peer address you like -
* use hio_dev_sck_parse_assoc_event() to get the association id;
* - from on_read(), when a message tells you this peer deserves a session -
* the association id is already there, on the source address, via
* hio_skad_get_assoc().
*
* Peeling mid-stream leaves a clean seam: messages already handed to on_read()
* are yours, whatever is still queued in the kernel moves to the new socket,
* and everything after arrives on the new device. Nothing is lost or
* duplicated. Call it synchronously from inside the callback though - defer it
* and this socket may read another message for that association first, which
* widens the seam by however long you waited.
*
* Only for the one-to-many SCTP types; anything else fails with #HIO_EINVAL.
* A build whose system lacks sctp_peeloff() fails with #HIO_ENOIMPL.
*/
HIO_EXPORT int hio_dev_sck_peeloff (
hio_dev_sck_t* dev,
hio_int32_t assoc_id
);
/**
* The hio_dev_sck_parse_assoc_event() function decodes what on_notification()
* hands over, when what it hands over is an association change. It exists so
* that deciding what to do about a new association does not require picking
* apart a kernel structure by hand.
*
* Returns 0 and fills 'ev' if the notification is an association change, or -1
* if it is not - some other kind of event, or a buffer too short to be one.
*
* -1 is an answer, not a failure: no error number is set, and none can be, as
* this is a pure decoder with no hio_t to set one on. A caller walking
* notifications simply ignores the ones it gets -1 for.
*/
HIO_EXPORT int hio_dev_sck_parse_assoc_event (
const void* data,
hio_iolen_t dlen,
hio_sctp_assoc_event_t* ev
);
/**
* The hio_dev_sck_bindx() function adds or removes local addresses on an
* already bound SCTP endpoint - which is what local multi-homing is. The
* addresses belong to the endpoint rather than to any one association, so this
* is a socket operation and works the same whether associations are peeled off
* or kept on the one socket.
*
* hio_dev_sck_bind() must have been called first: sctp_bindx() adds to an
* existing binding, it does not replace it.
*
* Available only for the SCTP socket types; anything else fails with
* #HIO_ENOIMPL.
*/
HIO_EXPORT int hio_dev_sck_bindx (
hio_dev_sck_t* dev,
const hio_skad_t* addrs,
hio_oow_t naddrs,
hio_dev_sck_bindx_flag_t flags
);
/**
* The hio_dev_sck_getladdrs() function reports the local addresses of the
* endpoint, and hio_dev_sck_getpaddrs() the peer addresses of the association -
* the two halves of what multi-homing established.
*
* On entry *naddrs is the room available in 'addrs'; on return it is how many
* were written. #HIO_EBUFFULL is reported if there were more, with *naddrs set
* to the number needed.
*/
HIO_EXPORT int hio_dev_sck_getladdrs (
hio_dev_sck_t* dev,
hio_skad_t* addrs,
hio_oow_t* naddrs
);
HIO_EXPORT int hio_dev_sck_getpaddrs (
hio_dev_sck_t* dev,
hio_skad_t* addrs,
hio_oow_t* naddrs
);
/**
* The hio_dev_sck_setprimaryaddr() function asks the peer to prefer one of its
* addresses as the primary path. It must be one of the addresses
* hio_dev_sck_getpaddrs() reports.
*/
HIO_EXPORT int hio_dev_sck_setprimaryaddr (
hio_dev_sck_t* dev,
const hio_skad_t* addr
);
HIO_EXPORT int hio_dev_sck_sendfileok ( HIO_EXPORT int hio_dev_sck_sendfileok (
hio_dev_sck_t* dev hio_dev_sck_t* dev
); );
+3
View File
@@ -408,10 +408,13 @@ static int dev_pro_make_master (hio_dev_t* dev, void* ctx)
return 0; return 0;
oops: oops:
if (minidx >= 0 && maxidx >= 0)
{
for (i = minidx; i <= maxidx; i++) for (i = minidx; i <= maxidx; i++)
{ {
if (pfds[i] != HIO_SYSHND_INVALID) close(pfds[i]); if (pfds[i] != HIO_SYSHND_INVALID) close(pfds[i]);
} }
}
if (rdev->mcmd) if (rdev->mcmd)
{ {
+464 -30
View File
@@ -51,6 +51,24 @@
# include <netinet/sctp.h> # include <netinet/sctp.h>
# if defined(IPPROTO_SCTP) # if defined(IPPROTO_SCTP)
# define ENABLE_SCTP # define ENABLE_SCTP
/* these library calls are a separate question from the socket type. on
* linux they live in libsctp, which a machine with sctp headers and an
* sctp kernel may not have installed. the basic one-to-one and
* one-to-many transports need none of them, so they stand either way.
*
* peel-off and multi-homing are probed apart because they are separate
* features that share nothing but the library they come from: peel-off
* needs sctp_peeloff() and multi-homing needs the address calls, and
* neither calls into the other. bundling them would mean a system
* missing one silently loses both - the same "they always come
* together" assumption that let the old header-derived ENABLE_SCTP
* stay wrong for so long. */
# if defined(HAVE_SCTP_PEELOFF)
# define ENABLE_SCTP_PEELOFF
# endif
# if defined(HAVE_SCTP_BINDX) && defined(HAVE_SCTP_GETPADDRS) && defined(HAVE_SCTP_GETLADDRS)
# define ENABLE_SCTP_MH
# endif
# endif # endif
#endif #endif
@@ -322,13 +340,23 @@ static struct sck_type_map_t sck_type_map[] =
/* HIO_DEV_SCK_SCTP6 */ /* HIO_DEV_SCK_SCTP6 */
{ AF_INET6, SOCK_STREAM, IPPROTO_SCTP, 1, 1, HIO_DEV_CAP_STREAM }, { AF_INET6, SOCK_STREAM, IPPROTO_SCTP, 1, 1, HIO_DEV_CAP_STREAM },
/* HIO_DEV_SCK_SCTP4_SP - one-to-many. listen() is called but hio never /* HIO_DEV_SCK_SCTP4_SEQPKT - one-to-many. listen() is called but hio never
* accepts: associations are not devices in this model, they are told apart * accepts: associations are not devices in this model, they are told apart
* by the source address on each message. */ * by the source address on each message.
{ AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 1, 1, 0 }, *
* marked unconnectable, as udp is. the socket api does allow connect() on a
* one-to-many socket - it forms an association and makes it the default
* destination - but nothing here can finish the job: a device with no
* HIO_DEV_CAP_STREAM gets dev_evcb_sck_ready_stateless(), which looks only
* at ERR and HUP and never at the progress bits, so on_connect() would
* never fire. the device would sit in HIO_DEV_SCK_CONNECTING for good -
* writes failing, a second connect() refused as already in progress, and
* with a connect timeout set, silently halted a few seconds later.
* refusing outright beats handing back a bricked device. */
{ AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0, 1, 0 },
/* HIO_DEV_SCK_SCTP6_SP */ /* HIO_DEV_SCK_SCTP6_SEQPKT */
{ AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 1, 1, 0 }, { AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0, 1, 0 },
#else #else
{ -1, 0, 0, 0, 0, 0 }, { -1, 0, 0, 0, 0, 0 },
{ -1, 0, 0, 0, 0, 0 }, { -1, 0, 0, 0, 0, 0 },
@@ -605,10 +633,18 @@ oops:
return -1; return -1;
} }
/* hio_dev_make() hands this back exactly what was passed to it, for the case
* where it fails before the make() method could take ownership of the handle.
*
* [NOTE] the ctx used to be a bare hio_syshnd_t and is now a struct whose first
* member is one. the old cast still read the right value - a pointer to a
* struct points to its first member - but only by accident of layout: put any
* field ahead of 'hnd' and this would close (int)type instead, which is a small
* integer, which is to say some other part of the program's descriptor. */
static void dev_sck_fail_before_make_client (void* ctx) static void dev_sck_fail_before_make_client (void* ctx)
{ {
hio_syshnd_t* clisckhnd = (hio_syshnd_t*)ctx; sck_make_client_ctx_t* mc = (sck_make_client_ctx_t*)ctx;
close(*clisckhnd); close(mc->hnd);
} }
static int dev_sck_kill (hio_dev_t* dev, int force) static int dev_sck_kill (hio_dev_t* dev, int force)
@@ -884,7 +920,14 @@ static int sendmsg_sctp(
* addressing by msg_name. it is ignored on a one-to-one socket. */ * addressing by msg_name. it is ignored on a one-to-one socket. */
sinfo->sinfo_assoc_id = (sctp_assoc_t)assoc_id; sinfo->sinfo_assoc_id = (sctp_assoc_t)assoc_id;
/* the plain stream and stateless send paths all ask for this; without it a
* failing sctp write raises SIGPIPE and kills the process where the
* equivalent tcp write merely returns EPIPE. */
#if defined(MSG_NOSIGNAL)
return sendmsg(s, &msg, MSG_NOSIGNAL);
#else
return sendmsg(s, &msg, 0); return sendmsg(s, &msg, 0);
#endif
} }
/* the core passes no destination for a connected socket - hio_dev_sck_write() /* the core passes no destination for a connected socket - hio_dev_sck_write()
@@ -915,9 +958,8 @@ static HIO_INLINE hio_int32_t dstaddr_assoc (const hio_devaddr_t* dstaddr)
return (dstaddr && dstaddr->ptr)? hio_skad_get_assoc((const hio_skad_t*)dstaddr->ptr): 0; return (dstaddr && dstaddr->ptr)? hio_skad_get_assoc((const hio_skad_t*)dstaddr->ptr): 0;
} }
static int dev_sck_read_sctp_sp (hio_dev_t* dev, void* buf, hio_iolen_t* len, hio_devaddr_t* srcaddr) static int dev_sck_read_sctp_seqpkt (hio_dev_t* dev, void* buf, hio_iolen_t* len, hio_devaddr_t* srcaddr)
{ {
/* NOTE: sctp support is far away from complete */
hio_t* hio = dev->hio; hio_t* hio = dev->hio;
hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev; hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev;
hio_scklen_t srcaddrlen; hio_scklen_t srcaddrlen;
@@ -944,7 +986,12 @@ static int dev_sck_read_sctp_sp (hio_dev_t* dev, void* buf, hio_iolen_t* len, hi
if (msg_flags & MSG_NOTIFICATION) if (msg_flags & MSG_NOTIFICATION)
{ {
/* an association or path event, not payload. handing this to /* an association or path event, not payload. handing this to
* on_read() would splice an event record into the data stream. */ * on_read() would splice an event record into the data stream.
*
* every one of these is passed on, association changes included. this
* socket takes no view on which associations deserve a device of their
* own - hio_dev_sck_peeloff() is a call the application makes, from
* here or from on_read() later, for the associations it picks. */
if (rdev->on_notification) rdev->on_notification(rdev, buf, x); if (rdev->on_notification) rdev->on_notification(rdev, buf, x);
return 0; /* nothing readable for the caller this time round */ return 0; /* nothing readable for the caller this time round */
} }
@@ -1260,9 +1307,8 @@ static int dev_sck_writev_bpf (hio_dev_t* dev, const hio_iovec_t* iov, hio_iolen
/* ------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------ */
#if defined(ENABLE_SCTP) #if defined(ENABLE_SCTP)
static int dev_sck_write_sctp_sp (hio_dev_t* dev, const void* data, hio_iolen_t* len, const hio_devaddr_t* dstaddr) static int dev_sck_write_sctp_seqpkt (hio_dev_t* dev, const void* data, hio_iolen_t* len, const hio_devaddr_t* dstaddr)
{ {
/* NOTE: sctp support is far away from complete */
hio_t* hio = dev->hio; hio_t* hio = dev->hio;
hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev; hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev;
ssize_t x; ssize_t x;
@@ -1292,7 +1338,7 @@ static int dev_sck_write_sctp_sp (hio_dev_t* dev, const void* data, hio_iolen_t*
/* the one-to-one sctp types carry HIO_DEV_CAP_STREAM, so the core treats them /* the one-to-one sctp types carry HIO_DEV_CAP_STREAM, so the core treats them
* like a tcp socket: a zero-length write is the writing-end shutdown, and a * like a tcp socket: a zero-length write is the writing-end shutdown, and a
* zero-length read is EOF. the seqpacket methods above answer neither of those * zero-length read is EOF. the seqpkt methods above answer neither of those
* conventions - a zero-length sendmsg() puts an empty message on the wire * conventions - a zero-length sendmsg() puts an empty message on the wire
* rather than closing anything - so the stream variants need their own pair. * rather than closing anything - so the stream variants need their own pair.
* *
@@ -1403,7 +1449,7 @@ static int dev_sck_writev_sctp_stream (hio_dev_t* dev, const hio_iovec_t* iov, h
return 1; return 1;
} }
static int dev_sck_writev_sctp_sp (hio_dev_t* dev, const hio_iovec_t* iov, hio_iolen_t* iovcnt, const hio_devaddr_t* dstaddr) static int dev_sck_writev_sctp_seqpkt (hio_dev_t* dev, const hio_iovec_t* iov, hio_iolen_t* iovcnt, const hio_devaddr_t* dstaddr)
{ {
hio_t* hio = dev->hio; hio_t* hio = dev->hio;
hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev; hio_dev_sck_t* rdev = (hio_dev_sck_t*)dev;
@@ -2118,7 +2164,7 @@ static hio_dev_mth_t dev_mth_clisck_sctp_stream =
{ {
dev_sck_make_client, dev_sck_make_client,
dev_sck_kill, dev_sck_kill,
HIO_NULL, dev_sck_fail_before_make_client,
dev_sck_getsyshnd, dev_sck_getsyshnd,
HIO_NULL, HIO_NULL,
dev_sck_ioctl, dev_sck_ioctl,
@@ -2153,7 +2199,7 @@ static hio_dev_mth_t dev_mth_sck_stream =
}; };
#if defined(ENABLE_SCTP) #if defined(ENABLE_SCTP)
static hio_dev_mth_t dev_mth_sck_sctp_sp = static hio_dev_mth_t dev_mth_sck_sctp_seqpkt =
{ {
dev_sck_make, dev_sck_make,
dev_sck_kill, dev_sck_kill,
@@ -2162,9 +2208,9 @@ static hio_dev_mth_t dev_mth_sck_sctp_sp =
HIO_NULL, HIO_NULL,
dev_sck_ioctl, /* ioctl */ dev_sck_ioctl, /* ioctl */
dev_sck_read_sctp_sp, dev_sck_read_sctp_seqpkt,
dev_sck_write_sctp_sp, dev_sck_write_sctp_seqpkt,
dev_sck_writev_sctp_sp, dev_sck_writev_sctp_seqpkt,
HIO_NULL, /* sendfile */ HIO_NULL, /* sendfile */
HIO_NULL, /* readpending */ HIO_NULL, /* readpending */
@@ -2210,7 +2256,7 @@ static hio_dev_mth_t dev_mth_clisck_stream =
}; };
#if defined(ENABLE_SCTP) #if defined(ENABLE_SCTP)
static hio_dev_mth_t dev_mth_clisck_sctp_sp = static hio_dev_mth_t dev_mth_clisck_sctp_seqpkt =
{ {
dev_sck_make_client, dev_sck_make_client,
dev_sck_kill, dev_sck_kill,
@@ -2219,12 +2265,12 @@ static hio_dev_mth_t dev_mth_clisck_sctp_sp =
HIO_NULL, HIO_NULL,
dev_sck_ioctl, dev_sck_ioctl,
dev_sck_read_sctp_sp, dev_sck_read_sctp_seqpkt,
dev_sck_write_sctp_sp, dev_sck_write_sctp_seqpkt,
dev_sck_writev_sctp_sp, dev_sck_writev_sctp_seqpkt,
HIO_NULL, /* sendfile */ HIO_NULL, /* sendfile */
HIO_NULL /* readpending - no ssl on a seqpacket socket */ HIO_NULL /* readpending - no ssl on a seqpkt socket */
}; };
#endif #endif
@@ -2344,11 +2390,11 @@ static int harvest_outgoing_connection (hio_dev_sck_t* rdev)
static int make_accepted_client_connection (hio_dev_sck_t* rdev, hio_syshnd_t clisck, hio_skad_t* remoteaddr, hio_dev_sck_type_t clisck_type) static int make_accepted_client_connection (hio_dev_sck_t* rdev, hio_syshnd_t clisck, hio_skad_t* remoteaddr, hio_dev_sck_type_t clisck_type)
{ {
sck_make_client_ctx_t mc;
hio_t* hio = rdev->hio; hio_t* hio = rdev->hio;
hio_dev_sck_t* clidev; hio_dev_sck_t* clidev;
hio_scklen_t addrlen; hio_scklen_t addrlen;
hio_dev_mth_t* dev_mth; hio_dev_mth_t* dev_mth;
sck_make_client_ctx_t mc;
if (rdev->on_raw_accept) if (rdev->on_raw_accept)
{ {
@@ -2371,7 +2417,7 @@ static int make_accepted_client_connection (hio_dev_sck_t* rdev, hio_syshnd_t cl
#if defined(ENABLE_SCTP) #if defined(ENABLE_SCTP)
dev_mth = (sck_type_map[clisck_type].extra_dev_cap & HIO_DEV_CAP_STREAM)? dev_mth = (sck_type_map[clisck_type].extra_dev_cap & HIO_DEV_CAP_STREAM)?
((sck_type_map[clisck_type].proto == IPPROTO_SCTP)? &dev_mth_clisck_sctp_stream: &dev_mth_clisck_stream): ((sck_type_map[clisck_type].proto == IPPROTO_SCTP)? &dev_mth_clisck_sctp_stream: &dev_mth_clisck_stream):
(sck_type_map[clisck_type].proto == IPPROTO_SCTP)? &dev_mth_clisck_sctp_sp: &dev_mth_clisck_stateless; ((sck_type_map[clisck_type].proto == IPPROTO_SCTP)? &dev_mth_clisck_sctp_seqpkt: &dev_mth_clisck_stateless);
#else #else
dev_mth = (sck_type_map[clisck_type].extra_dev_cap & HIO_DEV_CAP_STREAM)? &dev_mth_clisck_stream: &dev_mth_clisck_stateless; dev_mth = (sck_type_map[clisck_type].extra_dev_cap & HIO_DEV_CAP_STREAM)? &dev_mth_clisck_stream: &dev_mth_clisck_stateless;
#endif #endif
@@ -2380,7 +2426,7 @@ static int make_accepted_client_connection (hio_dev_sck_t* rdev, hio_syshnd_t cl
clidev = (hio_dev_sck_t*)hio_dev_make(hio, rdev->dev_size, dev_mth, rdev->dev_evcb, &mc); clidev = (hio_dev_sck_t*)hio_dev_make(hio, rdev->dev_size, dev_mth, rdev->dev_evcb, &mc);
if (HIO_UNLIKELY(!clidev)) if (HIO_UNLIKELY(!clidev))
{ {
/* [NOTE] 'clisck' is closed by callback methods called by hio_dev_make() upon failure */ /* [NOTE] 'clisck' is closed by callback(fail_before_make) methods called by hio_dev_make() upon failure */
HIO_DEBUG3(hio, "SCK(%p) - unable to make a new accepted device for %d - %js\n", rdev, (int)clisck, hio_geterrmsg(hio)); HIO_DEBUG3(hio, "SCK(%p) - unable to make a new accepted device for %d - %js\n", rdev, (int)clisck, hio_geterrmsg(hio));
return -1; return -1;
} }
@@ -2529,6 +2575,10 @@ static int accept_incoming_connection (hio_dev_sck_t* rdev)
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4) #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4)
accept_done: accept_done:
#endif #endif
/* no separate error handling to close clisck becuase it's supposed to be
* handled by hio_dev_make() via the fail_before_make callback inside
* make_accepted_client_connection(). if it fails even before hio_dev_make()
* inside make_accepted_client_connection(), it should close the socket explicitly */
return make_accepted_client_connection(rdev, clisck, &remoteaddr, rdev->type); return make_accepted_client_connection(rdev, clisck, &remoteaddr, rdev->type);
} }
@@ -2634,7 +2684,6 @@ static int dev_evcb_sck_ready_stream (hio_dev_t* dev, int events)
#endif #endif
case HIO_DEV_SCK_LISTENING: case HIO_DEV_SCK_LISTENING:
if (events & HIO_DEV_EVENT_HUP) if (events & HIO_DEV_EVENT_HUP)
{ {
/* device hang-up */ /* device hang-up */
@@ -2798,7 +2847,7 @@ static hio_dev_evcb_t dev_sck_event_callbacks_stateless =
dev_evcb_sck_on_write_stateless dev_evcb_sck_on_write_stateless
}; };
static hio_dev_evcb_t dev_sck_event_callbacks_sctp_sp = static hio_dev_evcb_t dev_sck_event_callbacks_sctp_seqpkt =
{ {
dev_evcb_sck_ready_stateless, dev_evcb_sck_ready_stateless,
dev_evcb_sck_on_read_stateless, dev_evcb_sck_on_read_stateless,
@@ -2972,7 +3021,7 @@ hio_dev_sck_t* hio_dev_sck_make (hio_t* hio, hio_oow_t xtnsize, const hio_dev_sc
{ {
rdev = (hio_dev_sck_t*)hio_dev_make( rdev = (hio_dev_sck_t*)hio_dev_make(
hio, HIO_SIZEOF(hio_dev_sck_t) + xtnsize, hio, HIO_SIZEOF(hio_dev_sck_t) + xtnsize,
&dev_mth_sck_sctp_sp, &dev_sck_event_callbacks_sctp_sp, (void*)info); &dev_mth_sck_sctp_seqpkt, &dev_sck_event_callbacks_sctp_seqpkt, (void*)info);
} }
#endif #endif
else else
@@ -3161,6 +3210,391 @@ int hio_dev_sck_shutdown (hio_dev_sck_t* dev, int how)
return 0; return 0;
} }
/* ------------------------------------------------------------------------- */
/* sctp peel-off */
/* ------------------------------------------------------------------------- */
#if defined(ENABLE_SCTP_PEELOFF)
/* the one-to-one type a peeled-off association becomes. sctp_peeloff() hands
* back a SOCK_STREAM socket carrying one association, which is precisely what
* the one-to-one types already describe - so the peeled device gets the
* existing one-to-one methods, write queue and all. */
static int sctp_one_to_one_type (hio_dev_sck_type_t sp_type, hio_dev_sck_type_t* one_to_one)
{
switch (sp_type)
{
case HIO_DEV_SCK_SCTP4_SEQPKT:
*one_to_one = HIO_DEV_SCK_SCTP4;
return 0;
case HIO_DEV_SCK_SCTP6_SEQPKT:
*one_to_one = HIO_DEV_SCK_SCTP6;
return 0;
default:
return -1;
}
}
int hio_dev_sck_peeloff (hio_dev_sck_t* rdev, hio_int32_t assoc_id)
{
hio_t* hio = rdev->hio;
hio_dev_sck_type_t clitype;
hio_syshnd_t clisck;
hio_skad_t remoteaddr;
hio_scklen_t addrlen;
if (sctp_one_to_one_type(rdev->type, &clitype) <= -1)
{
hio_seterrbfmt(hio, HIO_EINVAL, "not a one-to-many sctp socket");
return -1;
}
/* move the association onto a socket of its own. anything still queued for
* it in the kernel moves with it, which is what makes a mid-stream peel
* safe: messages already handed to on_read() are the caller's, the rest
* arrive on the new device, and none are lost or seen twice. */
clisck = sctp_peeloff(rdev->hnd, (sctp_assoc_t)assoc_id);
if (clisck <= -1)
{
hio_seterrwithsyserr(hio, 0, errno);
return -1;
}
/* the extra area past the sockaddr is not written by getpeername(), so it
* is cleared here rather than left holding the stream and ppid of whatever
* message last used this device's remoteaddr. */
HIO_MEMSET(&remoteaddr, 0, HIO_SIZEOF(remoteaddr));
addrlen = HIO_SIZEOF(remoteaddr);
if (getpeername(clisck, (struct sockaddr*)&remoteaddr, &addrlen) <= -1)
{
/* fall back on the address the notification came from - the primary
* path of the same association. the remaining addresses of a
* multi-homed peer are reachable with hio_dev_sck_getpaddrs(). */
remoteaddr = rdev->remoteaddr;
hio_skad_set_chan(&remoteaddr, 0);
hio_skad_set_ppid(&remoteaddr, 0);
hio_skad_set_assoc(&remoteaddr, 0);
}
/* no separate error handling to close clisck becuase it's supposed to be
* handled by hio_dev_make() via the fail_before_make callback inside
* make_accepted_client_connection(). if it fails even before hio_dev_make()
* inside make_accepted_client_connection(), it should close the socket explicitly */
return make_accepted_client_connection(rdev, clisck, &remoteaddr, clitype);
}
#else /* ENABLE_SCTP_PEELOFF */
int hio_dev_sck_peeloff (hio_dev_sck_t* rdev, hio_int32_t assoc_id)
{
hio_seterrbfmt(rdev->hio, HIO_ENOIMPL, "sctp peel-off not supported");
return -1;
}
#endif /* ENABLE_SCTP_PEELOFF */
/* ------------------------------------------------------------------------- */
#if defined(ENABLE_SCTP)
int hio_dev_sck_parse_assoc_event (const void* data, hio_iolen_t dlen, hio_sctp_assoc_event_t* ev)
{
struct sctp_assoc_change ac;
/* copied out rather than read in place: a caller may hand over a buffer
* whose alignment is not this structure's to assume. */
if (dlen < (hio_iolen_t)HIO_SIZEOF(ac)) return -1; /* too short to be one */
HIO_MEMCPY(&ac, data, HIO_SIZEOF(ac));
if (ac.sac_type != SCTP_ASSOC_CHANGE) return -1; /* a different event, not an error */
switch (ac.sac_state)
{
case SCTP_COMM_UP: ev->state = HIO_SCTP_ASSOC_COMM_UP; break;
case SCTP_COMM_LOST: ev->state = HIO_SCTP_ASSOC_COMM_LOST; break;
case SCTP_RESTART: ev->state = HIO_SCTP_ASSOC_RESTART; break;
case SCTP_SHUTDOWN_COMP: ev->state = HIO_SCTP_ASSOC_SHUTDOWN_COMP; break;
case SCTP_CANT_STR_ASSOC: ev->state = HIO_SCTP_ASSOC_CANT_STR_ASSOC; break;
default: ev->state = HIO_SCTP_ASSOC_STATE_UNKNOWN; break;
}
ev->error = ac.sac_error;
ev->assoc_id = (hio_int32_t)ac.sac_assoc_id;
/* the negotiated counts - the outcome of both ends' SCTP_INITMSG requests,
* and not reachable any other way */
ev->ostreams = ac.sac_outbound_streams;
ev->instreams = ac.sac_inbound_streams;
return 0;
}
#else
int hio_dev_sck_parse_assoc_event (const void* data, hio_iolen_t dlen, hio_sctp_assoc_event_t* ev)
{
return -1;
}
#endif
/* ------------------------------------------------------------------------- */
/* sctp multi-homing */
/* ------------------------------------------------------------------------- */
#if defined(ENABLE_SCTP_MH)
static HIO_INLINE int is_sctp_sck (hio_dev_sck_t* dev)
{
return sck_type_map[dev->type].proto == IPPROTO_SCTP;
}
/* the sctp calls take addresses as a packed run of sockaddrs of mixed length,
* not an array of a fixed-size type. these two convert between that and
* hio_skad_t, which is fixed-size and carries an extra area the kernel neither
* writes nor reads. */
static int pack_skads (hio_t* hio, const hio_skad_t* addrs, hio_oow_t naddrs, hio_uint8_t** buf)
{
hio_uint8_t* b, * p;
hio_oow_t total = 0, i;
for (i = 0; i < naddrs; i++)
{
int len = hio_skad_get_size(&addrs[i]);
if (len <= 0)
{
hio_seterrbfmt(hio, HIO_EINVAL, "address #%zu is not of a supported family", i);
return -1;
}
total += len;
}
b = (hio_uint8_t*)hio_allocmem(hio, total);
if (HIO_UNLIKELY(!b)) return -1;
for (i = 0, p = b; i < naddrs; i++)
{
int len = hio_skad_get_size(&addrs[i]);
HIO_MEMCPY(p, &addrs[i], len);
p += len;
}
*buf = b;
return 0;
}
static int unpack_skads (hio_t* hio, const struct sockaddr* packed, int count, hio_skad_t* addrs, hio_oow_t* naddrs)
{
hio_oow_t room = *naddrs, i;
const hio_uint8_t* p = (const hio_uint8_t*)packed;
/* every address is reported, so the caller learns how much room it needed
* even when it did not have enough. what does not fit is not written. */
for (i = 0; i < (hio_oow_t)count; i++)
{
hio_oow_t len;
switch (((const struct sockaddr*)p)->sa_family)
{
case AF_INET:
len = HIO_SIZEOF(struct sockaddr_in);
break;
#if defined(AF_INET6)
case AF_INET6:
len = HIO_SIZEOF(struct sockaddr_in6);
break;
#endif
default:
/* the run cannot be walked past an address of unknown length */
hio_seterrbfmt(hio, HIO_EINVAL, "unsupported address family %d in the sctp address list", (int)((const struct sockaddr*)p)->sa_family);
*naddrs = i;
return -1;
}
if (i < room)
{
/* the extra area past the sockaddr belongs to hio, not the kernel */
HIO_MEMSET(&addrs[i], 0, HIO_SIZEOF(addrs[i]));
HIO_MEMCPY(&addrs[i], p, len);
}
p += len;
}
*naddrs = (hio_oow_t)count;
if ((hio_oow_t)count > room)
{
hio_seterrbfmt(hio, HIO_EBUFFULL, "%d addresses do not fit in %zu slot(s)", count, room);
return -1;
}
return 0;
}
int hio_dev_sck_bindx (hio_dev_sck_t* dev, const hio_skad_t* addrs, hio_oow_t naddrs, hio_dev_sck_bindx_flag_t flags)
{
hio_t* hio = dev->hio;
hio_uint8_t* buf;
int x;
if (!is_sctp_sck(dev))
{
hio_seterrbfmt(hio, HIO_ENOIMPL, "not an sctp socket device");
return -1;
}
if (naddrs <= 0)
{
hio_seterrbfmt(hio, HIO_EINVAL, "no address given");
return -1;
}
if (pack_skads(hio, addrs, naddrs, &buf) <= -1) return -1;
x = sctp_bindx(dev->hnd, (struct sockaddr*)buf, (int)naddrs,
(flags == HIO_DEV_SCK_BINDX_REM)? SCTP_BINDX_REM_ADDR: SCTP_BINDX_ADD_ADDR);
if (x <= -1) hio_seterrwithsyserr(hio, 0, errno);
hio_freemem (hio, buf);
return (x <= -1)? -1: 0;
}
int hio_dev_sck_getladdrs (hio_dev_sck_t* dev, hio_skad_t* addrs, hio_oow_t* naddrs)
{
hio_t* hio = dev->hio;
struct sockaddr* packed = HIO_NULL;
int count, x;
if (!is_sctp_sck(dev))
{
hio_seterrbfmt(hio, HIO_ENOIMPL, "not an sctp socket device");
return -1;
}
/* association 0 asks about the endpoint, which is what local multi-homing
* is about - the addresses belong to the socket, not to one association. */
count = sctp_getladdrs(dev->hnd, 0, &packed);
if (count <= -1)
{
hio_seterrwithsyserr(hio, 0, errno);
return -1;
}
x = unpack_skads(hio, packed, count, addrs, naddrs);
sctp_freeladdrs(packed);
return x;
}
int hio_dev_sck_getpaddrs (hio_dev_sck_t* dev, hio_skad_t* addrs, hio_oow_t* naddrs)
{
hio_t* hio = dev->hio;
struct sockaddr* packed = HIO_NULL;
int count, x;
if (!is_sctp_sck(dev))
{
hio_seterrbfmt(hio, HIO_ENOIMPL, "not an sctp socket device");
return -1;
}
/* peer addresses belong to an association, and only a one-to-one socket has
* exactly one. that is what a peeled-off or connected device is; a
* one-to-many socket holds many and cannot answer the question. */
if (sck_type_map[dev->type].type == SOCK_SEQPACKET)
{
hio_seterrbfmt(hio, HIO_EPERM, "peer addresses are per-association - peel the association off first");
return -1;
}
count = sctp_getpaddrs(dev->hnd, 0, &packed);
if (count <= -1)
{
hio_seterrwithsyserr(hio, 0, errno);
return -1;
}
x = unpack_skads(hio, packed, count, addrs, naddrs);
sctp_freepaddrs(packed);
return x;
}
/* SCTP_PRIMARY_ADDR takes the same two members under two names: struct
* sctp_prim on linux, struct sctp_setprim on the bsds. */
#if defined(HAVE_STRUCT_SCTP_PRIM)
# define sctp_prim_t struct sctp_prim
#elif defined(HAVE_STRUCT_SCTP_SETPRIM)
# define sctp_prim_t struct sctp_setprim
#endif
int hio_dev_sck_setprimaryaddr (hio_dev_sck_t* dev, const hio_skad_t* addr)
{
hio_t* hio = dev->hio;
#if defined(sctp_prim_t)
sctp_prim_t prim;
int len;
if (!is_sctp_sck(dev))
{
hio_seterrbfmt(hio, HIO_ENOIMPL, "not an sctp socket device");
return -1;
}
len = hio_skad_get_size(addr);
if (len <= 0 || (hio_oow_t)len > HIO_SIZEOF(prim.ssp_addr))
{
hio_seterrbfmt(hio, HIO_EINVAL, "address is not of a supported family");
return -1;
}
HIO_MEMSET(&prim, 0, HIO_SIZEOF(prim));
prim.ssp_assoc_id = 0; /* the only association, on a one-to-one socket */
HIO_MEMCPY(&prim.ssp_addr, addr, len);
if (setsockopt(dev->hnd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, HIO_SIZEOF(prim)) <= -1)
{
hio_seterrwithsyserr(hio, 0, errno);
return -1;
}
return 0;
#else
hio_seterrbfmt(hio, HIO_ENOIMPL, "no structure for SCTP_PRIMARY_ADDR on this system");
return -1;
#endif
}
#else /* ENABLE_SCTP_MH */
/* the declarations are unconditional, so the symbols have to exist. they say
* so rather than being absent at link time. */
int hio_dev_sck_bindx (hio_dev_sck_t* dev, const hio_skad_t* addrs, hio_oow_t naddrs, hio_dev_sck_bindx_flag_t flags)
{
hio_seterrbfmt(dev->hio, HIO_ENOIMPL, "sctp multi-homing not supported");
return -1;
}
int hio_dev_sck_getladdrs (hio_dev_sck_t* dev, hio_skad_t* addrs, hio_oow_t* naddrs)
{
hio_seterrbfmt(dev->hio, HIO_ENOIMPL, "sctp multi-homing not supported");
return -1;
}
int hio_dev_sck_getpaddrs (hio_dev_sck_t* dev, hio_skad_t* addrs, hio_oow_t* naddrs)
{
hio_seterrbfmt(dev->hio, HIO_ENOIMPL, "sctp multi-homing not supported");
return -1;
}
int hio_dev_sck_setprimaryaddr (hio_dev_sck_t* dev, const hio_skad_t* addr)
{
hio_seterrbfmt(dev->hio, HIO_ENOIMPL, "sctp multi-homing not supported");
return -1;
}
#endif /* ENABLE_SCTP_MH */
int hio_dev_sck_sendfileok (hio_dev_sck_t* dev) int hio_dev_sck_sendfileok (hio_dev_sck_t* dev)
{ {
/* the transport has to actually implement it. the sctp methods deliberately /* the transport has to actually implement it. the sctp methods deliberately
+2
View File
@@ -588,6 +588,8 @@ PTHREAD_LIBS = @PTHREAD_LIBS@
QUADMATH_LIBS = @QUADMATH_LIBS@ QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
SCTP_ENABLED = @SCTP_ENABLED@ SCTP_ENABLED = @SCTP_ENABLED@
SCTP_MULTIHOMING_ENABLED = @SCTP_MULTIHOMING_ENABLED@
SCTP_PEELOFF_ENABLED = @SCTP_PEELOFF_ENABLED@
SED = @SED@ SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@ SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
+2 -2
View File
@@ -654,8 +654,8 @@ int main (int argc, char* argv[])
else if (strcmp(argv[i], "-ss") == 0) else if (strcmp(argv[i], "-ss") == 0)
{ {
i++; i++;
g_dev_type4 = HIO_DEV_SCK_SCTP4_SP; g_dev_type4 = HIO_DEV_SCK_SCTP4_SEQPKT;
g_dev_type6 = HIO_DEV_SCK_SCTP6_SP; g_dev_type6 = HIO_DEV_SCK_SCTP6_SEQPKT;
} }
else if (strcmp(argv[i], "-t") == 0) else if (strcmp(argv[i], "-t") == 0)
{ {
+1057 -2
View File
File diff suppressed because it is too large Load Diff