diff --git a/qse/configure b/qse/configure index b3f92d4f..d6fc62c0 100755 --- a/qse/configure +++ b/qse/configure @@ -16082,6 +16082,18 @@ fi done +for ac_header in net/if.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NET_IF_H 1 +_ACEOF + +fi + +done + ac_fn_c_check_type "$LINENO" "wchar_t" "ac_cv_type_wchar_t" "#include " @@ -16233,6 +16245,18 @@ _ACEOF fi done +for ac_func in if_nametoindex if_indextoname +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" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + OLDLIBS="$LIBS" LIBS="$LIBM $LIBS" diff --git a/qse/configure.ac b/qse/configure.ac index 0b57e482..599e6fa3 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -85,6 +85,7 @@ AC_HEADER_STDC AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h]) AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h]) AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/sendfile.h sys/epoll.h]) +AC_CHECK_HEADERS([net/if.h]) dnl check data types AC_CHECK_TYPE([wchar_t], @@ -106,6 +107,7 @@ AC_CHECK_FUNCS([sysconf]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([fdopendir]) AC_CHECK_FUNCS([fork vfork posix_spawn]) +AC_CHECK_FUNCS([if_nametoindex if_indextoname]) OLDLIBS="$LIBS" LIBS="$LIBM $LIBS" diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h index 94e2fd28..06b3212d 100644 --- a/qse/include/qse/cmn/nwad.h +++ b/qse/include/qse/cmn/nwad.h @@ -25,15 +25,18 @@ #include #include +enum qse_nwad_type_t +{ + QSE_NWAD_IN4, + QSE_NWAD_IN6 +}; +typedef enum qse_nwad_type_t qse_nwad_type_t; + typedef struct qse_nwad_t qse_nwad_t; struct qse_nwad_t { - enum - { - QSE_NWAD_IN4, - QSE_NWAD_IN6 - } type; + qse_nwad_type_t type; union { diff --git a/qse/include/qse/cmn/sio.h b/qse/include/qse/cmn/sio.h index 83f5c731..893159e1 100644 --- a/qse/include/qse/cmn/sio.h +++ b/qse/include/qse/cmn/sio.h @@ -214,12 +214,22 @@ qse_ssize_t qse_sio_getmbsn ( qse_size_t size ); +/** + * The qse_sio_getwcs() function reads at most @a size - 1 characters + * from the stream @a sio into the buffer @a buf. If a new line or EOF + * is encountered, it stops reading from the stream. It null-terminates + * the buffer if @a size is greater than 0. */ qse_ssize_t qse_sio_getwcs ( qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size ); +/** + * The qse_sio_getwcsn() function reads at most @a size characters + * from the stream @a sio into the buffer @a buf. If a new line or EOF + * is encountered, it stops reading from the stream. + */ qse_ssize_t qse_sio_getwcsn ( qse_sio_t* sio, qse_wchar_t* buf, diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index 6deddba9..8da88fb0 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -115,6 +115,12 @@ /* Define to 1 if you have the `gethostbyname' function. */ #undef HAVE_GETHOSTBYNAME +/* Define to 1 if you have the `if_indextoname' function. */ +#undef HAVE_IF_INDEXTONAME + +/* Define to 1 if you have the `if_nametoindex' function. */ +#undef HAVE_IF_NAMETOINDEX + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H @@ -169,6 +175,9 @@ /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_H + /* Define to 1 if you have the `posix_spawn' function. */ #undef HAVE_POSIX_SPAWN diff --git a/qse/include/qse/net/upxd.h b/qse/include/qse/net/upxd.h index b6f41cf3..9732b200 100644 --- a/qse/include/qse/net/upxd.h +++ b/qse/include/qse/net/upxd.h @@ -126,13 +126,8 @@ struct qse_upxd_cbs_t int (*delhnd) (qse_upxd_t* upxd, void* mux, qse_ubi_t handle); int (*poll) (qse_upxd_t* upxd, void* mux, qse_ntime_t timeout); } mux; - - struct - { - void (*acquire) (qse_upxd_t* upxd); - void (*release) (qse_upxd_t* upxd); - } lock; }; + typedef struct qse_upxd_cbs_t qse_upxd_cbs_t; #ifdef __cplusplus @@ -190,6 +185,11 @@ qse_upxd_server_t* qse_upxd_addserver ( const qse_char_t* dev ); +void qse_upxd_delserver ( + qse_upxd_t* upxd, + qse_upxd_server_t* server +); + void* qse_upxd_getserverctx ( qse_upxd_t* upxd, qse_upxd_server_t* server @@ -210,6 +210,21 @@ int qse_upxd_loop ( qse_ntime_t timeout ); +int qse_upxd_enableserver ( + qse_upxd_t* upxd, + qse_upxd_server_t* server +); + +int qse_upxd_disableserver ( + qse_upxd_t* upxd, + qse_upxd_server_t* server +); + +int qse_upxd_poll ( + qse_upxd_t* upxd, + qse_ntime_t timeout +); + #ifdef __cplusplus } #endif diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c index 07a53f07..2ce1dacd 100644 --- a/qse/lib/cmn/nwad.c +++ b/qse/lib/cmn/nwad.c @@ -24,121 +24,83 @@ #include #include "mem.h" -#if 0 -int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) +#if defined(HAVE_NET_IF_H) +#include +#include + +#if !defined(IF_NAMESIZE) +# define IF_NAMESIZE 63 +#endif + +#if defined(HAVE_IF_NAMETOINDEX) +static QSE_INLINE unsigned int mbsn_to_ifindex (const qse_mchar_t* ptr, qse_size_t len) { - const qse_mchar_t* p; - qse_mcstr_t tmp; - qse_nwad_t tmpad; - - QSE_MEMSET (&tmpad, 0, QSE_SIZEOF(tmpad)); - - p = str; - if (*p == QSE_MT('[')) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + if (qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), ptr, len) < len) { - /* IPv6 address */ - tmp.ptr = ++p; /* skip [ and remember the position */ - while (*p != QSE_MT('\0') && *p != QSE_MT('%') && *p != QSE_MT(']')) p++; - - if (*p == QSE_MT('\0')) return -1; - - tmp.len = p - tmp.ptr; - if (*p == QSE_MT('%')) - { - /* handle scope id */ - qse_uint32_t x; - - p++; /* skip % */ - - if (!(*p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1; - tmpad.u.in6.scope = 0; - do - { - x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; - } - while (*p >= QSE_MT('0') && *p <= QSE_MT('9')); - - if (*p != QSE_MT(']')) return -1; - } - p++; /* skip ] */ - - if (qse_mbsntoipad6 (tmp.ptr, tmp.len, &tmpad.u.in6.addr) <= -1) return -1; - tmpad.type = QSE_NWAD_IN6; + /* name too long */ + return 0; } - else - { - /* host name or IPv4 address */ - tmp.ptr = p; - while (*p != QSE_MT('\0') && *p != QSE_MT(':')) p++; - tmp.len = p - tmp.ptr; + return if_nametoindex (tmp); +} - if (qse_mbsntoipad4 (tmp.ptr, tmp.len, &tmpad.u.in4.addr) <= -1) - { - /* check if it is an IPv6 address not enclosed in []. - * the port number can't be specified in this format. */ +static QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len) +{ + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t wl, ml; - while (*p != QSE_MT('\0') && *p != QSE_MT('%')) p++; - tmp.len = p - tmp.ptr; + wl = len; ml = QSE_COUNTOF(tmp) - 1; + if (qse_wcsntombsn (ptr, &wl, tmp, &ml) <= -1) return 0; + tmp[ml] = QSE_MT('\0'); + return if_nametoindex (tmp); +} +#else +staitc QSE_INLINE unsigned int mbsn_to_ifindex (const qse_mchar_t* ptr, qse_size_t len) +{ + return 0U; +} +staitc QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len) +{ + return 0U; +} +#endif - if (qse_mbsntoipad6 (tmp.ptr, tmp.len, &tmpad.u.in6.addr) <= -1) - return -1; +#if defined(HAVE_IF_INDEXTONAME) +static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len) +{ + qse_mchar_t tmp[IF_NAMESIZE + 1]; + if (if_indextoname (index, tmp) == QSE_NULL) return 0; + return qse_mbsxcpy (buf, len, tmp); +} - if (*p == QSE_MT('%')) - { - /* handle scope id */ - qse_uint32_t x; +static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len) +{ + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t ml, wl; + int x; - p++; /* skip % */ - if (!(*p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1; - tmpad.u.in6.scope = 0; - do - { - x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; - } - while (*p >= QSE_MT('0') && *p <= QSE_MT('9')); - } + if (if_indextoname (index, tmp) == QSE_NULL) return 0; + wl = len; + x = qse_mbstowcs (tmp, &ml, buf, &wl); + if (x == -2 && wl > 1) buf[wl - 1] = QSE_WT('\0'); + else if (x != 0) return 0; + return wl; +} - if (*p != QSE_MT('\0')) return -1; - - tmpad.type = QSE_NWAD_IN6; - goto done; - } - - tmpad.type = QSE_NWAD_IN4; - } - - if (*p == QSE_MT(':')) - { - /* port number */ - qse_uint32_t port = 0; - - p++; /* skip : */ - - for (tmp.ptr = p; *p >= QSE_MT('0') && *p <= QSE_MT('9'); p++) - port = port * 10 + (*p - QSE_MT('0')); - - tmp.len = p - tmp.ptr; - if (tmp.len <= 0 || tmp.len >= 6 || - port > QSE_TYPE_MAX(qse_uint16_t)) return -1; - - if (tmpad.type == QSE_NWAD_IN4) - tmpad.u.in4.port = qse_hton16 (port); - else - tmpad.u.in6.port = qse_hton16 (port); - } - -done: - if (nwad) *nwad = tmpad; +#else +static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len) +{ + return 0; +} +static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len) +{ return 0; } #endif +#endif + + int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) { return qse_mbsntonwad (str, qse_mbslen(str), nwad); @@ -174,16 +136,33 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad) p++; /* skip % */ - if (!(p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1; - tmpad.u.in6.scope = 0; - do + if (p >= end) { - x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; + /* premature end */ + return -1; + } + + if (*p >= QSE_MT('0') && *p <= QSE_MT('9')) + { + /* numeric scope id */ + tmpad.u.in6.scope = 0; + do + { + x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); + if (x < tmpad.u.in6.scope) return -1; /* overflow */ + tmpad.u.in6.scope = x; + p++; + } + while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); + } + else + { + /* interface name as a scope id? */ + const qse_mchar_t* stmp = p; + do p++; while (p < end && *p != QSE_MT(']')); + tmpad.u.in6.scope = mbsn_to_ifindex (stmp, p - stmp); + if (tmpad.u.in6.scope <= 0) return -1; } - while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); if (p >= end || *p != QSE_MT(']')) return -1; } @@ -218,16 +197,34 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad) qse_uint32_t x; p++; /* skip % */ - if (!(p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1; - tmpad.u.in6.scope = 0; - do + + if (p >= end) { - x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; + /* premature end */ + return -1; + } + + if (*p >= QSE_MT('0') && *p <= QSE_MT('9')) + { + /* numeric scope id */ + tmpad.u.in6.scope = 0; + do + { + x = tmpad.u.in6.scope * 10 + (*p - QSE_MT('0')); + if (x < tmpad.u.in6.scope) return -1; /* overflow */ + tmpad.u.in6.scope = x; + p++; + } + while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); + } + else + { + /* interface name as a scope id? */ + const qse_mchar_t* stmp = p; + do p++; while (p < end); + tmpad.u.in6.scope = mbsn_to_ifindex (stmp, p - stmp); + if (tmpad.u.in6.scope <= 0) return -1; } - while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); } if (p < end) return -1; @@ -303,16 +300,33 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad) p++; /* skip % */ - if (!(p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9'))) return -1; - tmpad.u.in6.scope = 0; - do + if (p >= end) { - x = tmpad.u.in6.scope * 10 + (*p - QSE_WT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; + /* premature end */ + return -1; + } + + if (*p >= QSE_WT('0') && *p <= QSE_WT('9')) + { + /* numeric scope id */ + tmpad.u.in6.scope = 0; + do + { + x = tmpad.u.in6.scope * 10 + (*p - QSE_WT('0')); + if (x < tmpad.u.in6.scope) return -1; /* overflow */ + tmpad.u.in6.scope = x; + p++; + } + while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); + } + else + { + /* interface name as a scope id? */ + const qse_wchar_t* stmp = p; + do p++; while (p < end && *p != QSE_WT(']')); + tmpad.u.in6.scope = wcsn_to_ifindex (stmp, p - stmp); + if (tmpad.u.in6.scope <= 0) return -1; } - while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); if (p >= end || *p != QSE_WT(']')) return -1; } @@ -347,16 +361,34 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad) qse_uint32_t x; p++; /* skip % */ - if (!(p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9'))) return -1; - tmpad.u.in6.scope = 0; - do + + if (p >= end) { - x = tmpad.u.in6.scope * 10 + (*p - QSE_WT('0')); - if (x < tmpad.u.in6.scope) return -1; /* overflow */ - tmpad.u.in6.scope = x; - p++; + /* premature end */ + return -1; + } + + if (*p >= QSE_WT('0') && *p <= QSE_WT('9')) + { + /* numeric scope id */ + tmpad.u.in6.scope = 0; + do + { + x = tmpad.u.in6.scope * 10 + (*p - QSE_WT('0')); + if (x < tmpad.u.in6.scope) return -1; /* overflow */ + tmpad.u.in6.scope = x; + p++; + } + while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); + } + else + { + /* interface name as a scope id? */ + const qse_wchar_t* stmp = p; + do p++; while (p < end); + tmpad.u.in6.scope = wcsn_to_ifindex (stmp, p - stmp); + if (tmpad.u.in6.scope <= 0) return -1; } - while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); } if (p < end) return -1; @@ -446,18 +478,27 @@ qse_size_t qse_nwadtombs ( if (flags & QSE_NWADTOMBS_ADDR) { + if (xlen + 1 >= len) goto done; xlen += qse_ipad6tombs (&nwad->u.in6.addr, &buf[xlen], len - xlen); if (nwad->u.in6.scope != 0) { + int tmp; + if (xlen + 1 >= len) goto done; buf[xlen++] = QSE_MT('%'); if (xlen + 1 >= len) goto done; - xlen += qse_fmtuintmaxtombs ( - &buf[xlen], len - xlen, - nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL); + + tmp = ifindex_to_mbsn (nwad->u.in6.scope, &buf[xlen], len - xlen); + if (tmp <= 0) + { + xlen += qse_fmtuintmaxtombs ( + &buf[xlen], len - xlen, + nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL); + } + else xlen += tmp; } } @@ -547,13 +588,21 @@ qse_size_t qse_nwadtowcs ( if (nwad->u.in6.scope != 0) { + int tmp; + if (xlen + 1 >= len) goto done; buf[xlen++] = QSE_WT('%'); if (xlen + 1 >= len) goto done; - xlen += qse_fmtuintmaxtowcs ( - &buf[xlen], len - xlen, - nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); + + tmp = ifindex_to_wcsn (nwad->u.in6.scope, &buf[xlen], len - xlen); + if (tmp <= 0) + { + xlen += qse_fmtuintmaxtowcs ( + &buf[xlen], len - xlen, + nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); + } + else xlen += tmp; } } diff --git a/qse/lib/cmn/nwio.c b/qse/lib/cmn/nwio.c index 1a5f45c3..d5ae8bcd 100644 --- a/qse/lib/cmn/nwio.c +++ b/qse/lib/cmn/nwio.c @@ -437,14 +437,18 @@ int qse_nwio_init ( return -1; #else + #if defined(SOCK_CLOEXEC) + nwio->handle = socket (family, type | SOCK_CLOEXEC, 0); + #else nwio->handle = socket (family, type, 0); + #endif if (nwio->handle <= -1) { nwio->errnum = syserr_to_errnum (errno); goto oops; } - #if defined(FD_CLOEXEC) + #if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC) { int tmp = fcntl (nwio->handle, F_GETFD); if (tmp >= 0) fcntl (nwio->handle, F_SETFD, tmp | FD_CLOEXEC); diff --git a/qse/lib/net/upxd.c b/qse/lib/net/upxd.c index d431dd0c..4ecedfd2 100644 --- a/qse/lib/net/upxd.c +++ b/qse/lib/net/upxd.c @@ -23,6 +23,7 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (upxd) +static void disable_all_servers (qse_upxd_t* upxd); static void free_all_servers (qse_upxd_t* upxd); static qse_upxd_server_session_t* find_server_session ( qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from); @@ -63,8 +64,14 @@ int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr) void qse_upxd_fini (qse_upxd_t* upxd) { - QSE_ASSERTX (upxd->server.nactive == 0, - "Deactivate all servers before destroying me"); + if (upxd->server.nactive > 0) disable_all_servers (upxd); + + if (upxd->mux) + { + upxd->cbs->mux.close (upxd, upxd->mux); + upxd->mux = QSE_NULL; + } + free_all_servers (upxd); } @@ -98,10 +105,6 @@ QSE_INLINE void qse_upxd_freemem (qse_upxd_t* upxd, void* ptr) QSE_MMGR_FREE (upxd->mmgr, ptr); } -void qse_upxd_stop (qse_upxd_t* upxd) -{ - upxd->stopreq = 1; -} static int perform_session_task ( qse_upxd_t* upxd, void* mux, qse_ubi_t handle, void* cbarg) @@ -203,7 +206,6 @@ static qse_upxd_server_session_t* find_server_session ( QSE_MEMSET (session, 0, QSE_SIZEOF(*session)); - if (qse_gettime (&session->created) <= -1) { qse_upxd_freemem (upxd, session); @@ -275,10 +277,10 @@ static void release_session ( qse_upxd_freemem (upxd, session); } -static int activate_server (qse_upxd_t* upxd, qse_upxd_server_t* server) +static int enable_server (qse_upxd_t* upxd, qse_upxd_server_t* server) { QSE_ASSERT (upxd->cbs != QSE_NULL); - QSE_ASSERT (!(server->flags & QSE_UPXD_SERVER_ACTIVE)); + QSE_ASSERT (!(server->flags & QSE_UPXD_SERVER_ENABLED)); if (upxd->cbs->sock.open (upxd, &server->local) <= -1) { @@ -293,17 +295,17 @@ static int activate_server (qse_upxd_t* upxd, qse_upxd_server_t* server) return -1; } - server->flags |= QSE_UPXD_SERVER_ACTIVE; + server->flags |= QSE_UPXD_SERVER_ENABLED; upxd->server.nactive++; return 0; } -static void deactivate_server (qse_upxd_t* upxd, qse_upxd_server_t* server) +static void disable_server (qse_upxd_t* upxd, qse_upxd_server_t* server) { qse_upxd_server_session_t* session; QSE_ASSERT (upxd->cbs != QSE_NULL); - QSE_ASSERT (server->flags & QSE_UPXD_SERVER_ACTIVE); + QSE_ASSERT (server->flags & QSE_UPXD_SERVER_ENABLED); session = server->session.list; while (session) @@ -316,32 +318,32 @@ static void deactivate_server (qse_upxd_t* upxd, qse_upxd_server_t* server) upxd->cbs->mux.delhnd (upxd, upxd->mux, server->local.handle); upxd->cbs->sock.close (upxd, &server->local); - server->flags &= ~QSE_UPXD_SERVER_ACTIVE; + server->flags &= ~QSE_UPXD_SERVER_ENABLED; upxd->server.nactive--; } -static void activate_all_servers (qse_upxd_t* upxd) +static void enable_all_servers (qse_upxd_t* upxd) { qse_upxd_server_t* server; for (server = upxd->server.list; server; server = server->next) { - if (!(server->flags & QSE_UPXD_SERVER_ACTIVE)) + if (!(server->flags & QSE_UPXD_SERVER_ENABLED)) { - activate_server (upxd, server); + enable_server (upxd, server); } } } -static void deactivate_all_servers (qse_upxd_t* upxd) +static void disable_all_servers (qse_upxd_t* upxd) { qse_upxd_server_t* server; server = upxd->server.list; while (server) { - if (server->flags & QSE_UPXD_SERVER_ACTIVE) - deactivate_server (upxd, server); + if (server->flags & QSE_UPXD_SERVER_ENABLED) + disable_server (upxd, server); server = server->next; } @@ -362,29 +364,6 @@ static void free_all_servers (qse_upxd_t* upxd) upxd->server.list = QSE_NULL; } -static void purge_deleted_servers (qse_upxd_t* upxd) -{ - qse_upxd_server_t* server; - qse_upxd_server_t* next; - - server = upxd->server.list; - while (server) - { - next = server->next; - - if (server->flags & QSE_UPXD_SERVER_DELETED) - { - if (server->flags & QSE_UPXD_SERVER_ACTIVE) - deactivate_server (upxd, server); - - if (server == upxd->server.list) upxd->server.list = next; - - QSE_MMGR_FREE (upxd->mmgr, server); - } - server = next; - } -} - qse_upxd_server_t* qse_upxd_addserver ( qse_upxd_t* upxd, const qse_nwad_t* nwad, const qse_char_t* dev) { @@ -411,10 +390,11 @@ qse_upxd_server_t* qse_upxd_addserver ( } server->local.bind = *nwad; - upxd->cbs->lock.acquire (upxd); + /* chain it to the head of the list */ + if (upxd->server.list) + upxd->server.list->prev = server; server->next = upxd->server.list; upxd->server.list = server; - upxd->cbs->lock.release (upxd); return server; } @@ -422,7 +402,13 @@ qse_upxd_server_t* qse_upxd_addserver ( void qse_upxd_delserver ( qse_upxd_t* upxd, qse_upxd_server_t* server) { - server->flags |= QSE_UPXD_SERVER_DELETED; + if (server->flags & QSE_UPXD_SERVER_ENABLED) + disable_server (upxd, server); + + /* unchain the session from the list */ + if (server->next) server->next->prev = server->prev; + if (server->prev) server->prev->next = server->next; + else upxd->server.list = server->next; } void* qse_upxd_getserverctx ( @@ -478,7 +464,7 @@ static void purge_idle_sessions (qse_upxd_t* upxd) for (server = upxd->server.list; server; server = server->next) { - if (server->flags & QSE_UPXD_SERVER_ACTIVE) + if (server->flags & QSE_UPXD_SERVER_ENABLED) { purge_idle_sessions_in_server (upxd, server); } @@ -491,27 +477,26 @@ int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout) QSE_ASSERTX (upxd->cbs != QSE_NULL, "Call qse_upxd_setcbs() before calling qse_upxd_loop()"); - QSE_ASSERT (upxd->mux == QSE_NULL); - if (upxd->cbs == QSE_NULL || upxd->mux /*|| - upxd->server.list == QSE_NULL*/) + if (upxd->cbs == QSE_NULL) { upxd->errnum = QSE_UPXD_EINVAL; goto oops; } + if (upxd->mux) + { + /* close the mutiplexer if it's open */ + upxd->cbs->mux.close (upxd, upxd->mux); + upxd->mux = QSE_NULL; + } + upxd->stopreq = 0; upxd->mux = upxd->cbs-> mux.open (upxd); if (upxd->mux == QSE_NULL) goto oops; - activate_all_servers (upxd); - if (upxd->server.nactive == 0) - { - /* at least 1 server must be activated here */ - upxd->errnum = QSE_UPXD_EINVAL; - goto oops; - } - + enable_all_servers (upxd); + while (!upxd->stopreq) { int count; @@ -521,18 +506,66 @@ int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout) { /* TODO: anything? */ } - - upxd->cbs->lock.acquire (upxd); + purge_idle_sessions (upxd); - purge_deleted_servers (upxd); - activate_all_servers (upxd); - upxd->cbs->lock.release (upxd); + enable_all_servers (upxd); } retv = 0; oops: - if (upxd->server.nactive > 0) deactivate_all_servers (upxd); - if (upxd->mux) upxd->cbs->mux.close (upxd, upxd->mux); + if (upxd->server.nactive > 0) disable_all_servers (upxd); + if (upxd->mux) + { + upxd->cbs->mux.close (upxd, upxd->mux); + upxd->mux = QSE_NULL; + } return retv; } + +void qse_upxd_stop (qse_upxd_t* upxd) +{ + upxd->stopreq = 1; +} + +int qse_upxd_enableserver (qse_upxd_t* upxd, qse_upxd_server_t* server) +{ + if (server->flags & QSE_UPXD_SERVER_ENABLED) + { + upxd->errnum = QSE_UPXD_EINVAL; + return -1; + } + + return enable_server (upxd, server); +} + +int qse_upxd_disableserver (qse_upxd_t* upxd, qse_upxd_server_t* server) +{ + if (!(server->flags & QSE_UPXD_SERVER_ENABLED)) + { + upxd->errnum = QSE_UPXD_EINVAL; + return -1; + } + + disable_server (upxd, server); + return 0; +} + +int qse_upxd_poll (qse_upxd_t* upxd, qse_ntime_t timeout) +{ + int ret; + + QSE_ASSERTX (upxd->cbs != QSE_NULL, + "Call qse_upxd_setcbs() before calling qse_upxd_loop()"); + + if (upxd->mux == QSE_NULL) + { + upxd->mux = upxd->cbs-> mux.open (upxd); + if (upxd->mux == QSE_NULL) return -1; + } + + ret = upxd->cbs->mux.poll (upxd, upxd->mux, timeout); + purge_idle_sessions (upxd); + + return ret; +} diff --git a/qse/lib/net/upxd.h b/qse/lib/net/upxd.h index ac06ad6d..3422b7df 100644 --- a/qse/lib/net/upxd.h +++ b/qse/lib/net/upxd.h @@ -29,9 +29,9 @@ typedef struct qse_upxd_server_session_t qse_upxd_server_session_t; struct qse_upxd_server_t { qse_upxd_server_t* next; + qse_upxd_server_t* prev; -#define QSE_UPXD_SERVER_ACTIVE (1 << 0) -#define QSE_UPXD_SERVER_DELETED (1 << 1) +#define QSE_UPXD_SERVER_ENABLED (1 << 0) int flags; /* the socket can be bound to this interface. diff --git a/qse/samples/cmn/nwad01.c b/qse/samples/cmn/nwad01.c index 03a2203a..6bea5e16 100644 --- a/qse/samples/cmn/nwad01.c +++ b/qse/samples/cmn/nwad01.c @@ -33,6 +33,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_T("::ffff:0:0"), QSE_T("::ffff:192.168.1.1"), QSE_T("::ffff:192.168.1.1%88"), + QSE_T("::ffff:192.168.1.1%eth0"), + QSE_T("::ffff:192.168.1.1%eth1"), QSE_T("[::]:10"), QSE_T("[::1]:20"), QSE_T("[fe80::f27b:cbff:fea3:f40c]:30"), @@ -40,7 +42,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_T("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"), QSE_T("[::ffff:0:0]:60"), QSE_T("[::ffff:192.168.1.1]:70"), - QSE_T("[::ffff:192.168.1.1%999]:70") + QSE_T("[::ffff:192.168.1.1%999]:70"), + QSE_T("[::ffff:192.168.1.1%eth0]:70") }; static qse_mchar_t* ipstr_mbs[] = @@ -60,6 +63,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_MT("::ffff:0:0"), QSE_MT("::ffff:192.168.1.1"), QSE_MT("::ffff:192.168.1.1%88"), + QSE_MT("::ffff:192.168.1.1%eth0"), + QSE_MT("::ffff:192.168.1.1%eth1"), QSE_MT("[::]:10"), QSE_MT("[::1]:20"), QSE_MT("[fe80::f27b:cbff:fea3:f40c]:30"), @@ -67,7 +72,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_MT("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"), QSE_MT("[::ffff:0:0]:60"), QSE_MT("[::ffff:192.168.1.1]:70"), - QSE_MT("[::ffff:192.168.1.1%999]:70") + QSE_MT("[::ffff:192.168.1.1%999]:70"), + QSE_MT("[::ffff:192.168.1.1%eth0]:70") }; static qse_wchar_t* ipstr_wcs[] = @@ -87,6 +93,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_WT("::ffff:0:0"), QSE_WT("::ffff:192.168.1.1"), QSE_WT("::ffff:192.168.1.1%88"), + QSE_WT("::ffff:192.168.1.1%eth0"), + QSE_WT("::ffff:192.168.1.1%eth1"), QSE_WT("[::]:10"), QSE_WT("[::1]:20"), QSE_WT("[fe80::f27b:cbff:fea3:f40c]:30"), @@ -94,14 +102,15 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_WT("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"), QSE_WT("[::ffff:0:0]:60"), QSE_WT("[::ffff:192.168.1.1]:70"), - QSE_WT("[::ffff:192.168.1.1%999]:70") + QSE_WT("[::ffff:192.168.1.1%999]:70"), + QSE_WT("[::ffff:192.168.1.1%eth0]:70") }; for (i = 0; i < QSE_COUNTOF(ipstr); i++) { if (qse_strtonwad (ipstr[i], &nwad) <= -1) { - qse_printf (QSE_T("Failed to convert %s\n"), ipstr[i]); + qse_printf (QSE_T("Failed to convert <%s>\n"), ipstr[i]); } else { @@ -115,7 +124,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) { if (qse_mbstonwad (ipstr_mbs[i], &nwad) <= -1) { - qse_printf (QSE_T("Failed to convert %hs\n"), ipstr_mbs[i]); + qse_printf (QSE_T("Failed to convert <%hs>\n"), ipstr_mbs[i]); } else { @@ -129,7 +138,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) { if (qse_wcstonwad (ipstr_wcs[i], &nwad) <= -1) { - qse_printf (QSE_T("Failed to convert %ls\n"), ipstr_wcs[i]); + qse_printf (QSE_T("Failed to convert <%ls>\n"), ipstr_wcs[i]); } else { @@ -138,6 +147,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) } } + qse_printf (QSE_T("================================================\n")); return 0; } diff --git a/qse/samples/net/upxd01.c b/qse/samples/net/upxd01.c index 3cd48a04..8904a59f 100644 --- a/qse/samples/net/upxd01.c +++ b/qse/samples/net/upxd01.c @@ -5,10 +5,12 @@ #include #include #include +#include #include #include #include +#include #if defined(_WIN32) # include @@ -466,33 +468,32 @@ static int mux_poll (qse_upxd_t* upxd, void* vmux, qse_ntime_t timeout) struct mux_ev_t* mev; int nfds, i; - nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout); - if (nfds <= -1) + if (mux->ee.len < 0) { - qse_upxd_seterrnum (upxd, syserr_to_errnum(errno)); - return -1; + /* nothing to monitor yet */ + sleep (timeout / 1000); } - - for (i = 0; i < nfds; i++) + else { - mev = mux->ee.ptr[i].data.ptr; + nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout); + if (nfds <= -1) + { + qse_upxd_seterrnum (upxd, syserr_to_errnum(errno)); + return -1; + } - if (mux->ee.ptr[i].events & (EPOLLIN | EPOLLHUP)) - mev->cbfun (upxd, mux, mev->handle, mev->cbarg); + for (i = 0; i < nfds; i++) + { + mev = mux->ee.ptr[i].data.ptr; + + if (mux->ee.ptr[i].events & (EPOLLIN | EPOLLHUP)) + mev->cbfun (upxd, mux, mev->handle, mev->cbarg); + } } + return 0; } -/* ------------------------------------------------------------------- */ - -void lock_acquire (qse_upxd_t* upxd) -{ -} - -void lock_release (qse_upxd_t* upxd) -{ -} - /* ------------------------------------------------------------------- */ static qse_upxd_cbs_t upxd_cbs = { @@ -503,12 +504,179 @@ static qse_upxd_cbs_t upxd_cbs = { session_config, session_error }, /* multiplexer */ - { mux_open, mux_close, mux_addhnd, mux_delhnd, mux_poll }, - - /* lock */ - { lock_acquire, lock_release } + { mux_open, mux_close, mux_addhnd, mux_delhnd, mux_poll } }; + +/* ------------------------------------------------------------------- */ +typedef struct tr_t tr_t; +struct tr_t +{ + qse_sio_t* sio; + qse_str_t* t; +}; + +tr_t* tr_open (const qse_char_t* name) +{ + tr_t* tr; + + tr = malloc (QSE_SIZEOF(*tr)); + if (tr == QSE_NULL) return QSE_NULL; + + tr->sio = qse_sio_open (QSE_MMGR_GETDFL(), 0, name, QSE_SIO_READ); + if (tr->sio == QSE_NULL) + { + free (tr); + return QSE_NULL; + } + + tr->t = qse_str_open (QSE_MMGR_GETDFL(), 0, 128); + if (tr->t == QSE_NULL) + { + qse_sio_close (tr->sio); + free (tr); + return QSE_NULL; + } + + return tr; +} + +void tr_close (tr_t* tr) +{ + qse_str_close (tr->t); + qse_sio_close (tr->sio); + free (tr); +} + +qse_char_t* tr_getnext (tr_t* tr) +{ + qse_char_t c; + + qse_str_clear (tr->t); + + while (1) + { + if (qse_sio_getc (tr->sio, &c) <= -1) return QSE_NULL; + if (c == QSE_CHAR_EOF) return QSE_NULL; + if (!QSE_ISSPACE(c)) + { + if (qse_str_ccat (tr->t, c) == (qse_ssize_t)-1) return QSE_NULL; + break; + } + } + + while (1) + { + if (qse_sio_getc (tr->sio, &c) <= -1) return QSE_NULL; + if (c == QSE_CHAR_EOF || QSE_ISSPACE(c)) break; + + if (qse_str_ccat (tr->t, c) == (qse_ssize_t)-1) return QSE_NULL; + } + + return QSE_STR_PTR(tr->t); +} + +/* ------------------------------------------------------------------- */ + +#if 0 +struct svc_rule_t +{ + struct + { + qse_ipad_t ipad; + qse_ipad_t mask; + } src; + + int action; /* DROP, FORWARD */ + + struct + { + qse_nwad_t via; + qse_char_t via_dev[64]; + qse_nwad_t to_nwad; + } fwd; +}; + +struct svc_t +{ + qse_nwad_t nwad; + qse_char_t* dev; +}; +#endif + +typedef struct cfg_t cfg_t; +struct cfg_t +{ + qse_nwad_t nwad; +}; + +static cfg_t* load_cfg (const qse_char_t* name) +{ + tr_t* tr; + + tr = tr_open (name); + if (tr == QSE_NULL) return QSE_NULL; + + do + { + t = tr_getnext(tr); + if (qse_strcmp (t, QSE_T("listen")) == 0) + { + nwad = tr_getnext (tr); + dev = tr_getnext (tr); + + tmp = tr_getnext (tr); + if (qse_strcmp (tmp, QSE_T("{")) != 0) + { + } + + while (1) + { + from = tr_getnext (tr); + if (qse_strcmp (tmp, QSE_T("from")) != 0) + { + } + + src.nwad = tr_getnext (tr); + action = tr_getnext(tr); + + + if (qse_strcmp (action, QSE_T("drop")) == 0) + { + } + else if (qse_strcmp (action, QSE_T("forward")) == 0) + { + } + else + { + } + + tmp = tr_getnext (tr); + if (qse_strcmp (tmp, QSE_T(";")) != 0) + { + } + } + + tmp = tr_getnext (tr); + if (qse_strcmp (tmp, QSE_T("}")) != 0) + { + } + } + else break; + } + while (1); + + tr_close (tr); +} + +static void free_cfg (cfg_t* cfg) +{ +} + + +/* ------------------------------------------- */ + + static qse_upxd_t* g_upxd = QSE_NULL; static void sigint (int sig) @@ -519,6 +687,7 @@ static void sigint (int sig) int upxd_main (int argc, qse_char_t* argv[]) { qse_upxd_t* upxd = QSE_NULL; + cfg_t* cfg = QSE_NULL; int ret = -1, i; if (argc <= 1) @@ -527,6 +696,13 @@ int upxd_main (int argc, qse_char_t* argv[]) goto oops; } + cfg = load_cfg (argv[1]); + if (cfg == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot load %s\n"), argv[1]); + goto oops; + } + upxd = qse_upxd_open (QSE_MMGR_GETDFL(), 0); if (upxd == QSE_NULL) { @@ -569,6 +745,7 @@ int upxd_main (int argc, qse_char_t* argv[]) oops: if (upxd) qse_upxd_close (upxd); + if (cfg) free_cfg (cfg); return ret; }