enhanced nwad functions

This commit is contained in:
hyung-hwan 2012-07-02 14:21:40 +00:00
parent c60ca301c4
commit a62984d47a
12 changed files with 583 additions and 247 deletions

24
qse/configure vendored
View File

@ -16082,6 +16082,18 @@ fi
done 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 <stddef.h> ac_fn_c_check_type "$LINENO" "wchar_t" "ac_cv_type_wchar_t" "#include <stddef.h>
" "
@ -16233,6 +16245,18 @@ _ACEOF
fi fi
done 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" OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS" LIBS="$LIBM $LIBS"

View File

@ -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([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([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([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 dnl check data types
AC_CHECK_TYPE([wchar_t], AC_CHECK_TYPE([wchar_t],
@ -106,6 +107,7 @@ AC_CHECK_FUNCS([sysconf])
AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([fdopendir]) AC_CHECK_FUNCS([fdopendir])
AC_CHECK_FUNCS([fork vfork posix_spawn]) AC_CHECK_FUNCS([fork vfork posix_spawn])
AC_CHECK_FUNCS([if_nametoindex if_indextoname])
OLDLIBS="$LIBS" OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS" LIBS="$LIBM $LIBS"

View File

@ -25,15 +25,18 @@
#include <qse/macros.h> #include <qse/macros.h>
#include <qse/cmn/ipad.h> #include <qse/cmn/ipad.h>
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; typedef struct qse_nwad_t qse_nwad_t;
struct qse_nwad_t struct qse_nwad_t
{ {
enum qse_nwad_type_t type;
{
QSE_NWAD_IN4,
QSE_NWAD_IN6
} type;
union union
{ {

View File

@ -214,12 +214,22 @@ qse_ssize_t qse_sio_getmbsn (
qse_size_t size 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_ssize_t qse_sio_getwcs (
qse_sio_t* sio, qse_sio_t* sio,
qse_wchar_t* buf, qse_wchar_t* buf,
qse_size_t size 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_ssize_t qse_sio_getwcsn (
qse_sio_t* sio, qse_sio_t* sio,
qse_wchar_t* buf, qse_wchar_t* buf,

View File

@ -115,6 +115,12 @@
/* Define to 1 if you have the `gethostbyname' function. */ /* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME #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 <inttypes.h> header file. */ /* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H #undef HAVE_INTTYPES_H
@ -169,6 +175,9 @@
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H #undef HAVE_NDIR_H
/* Define to 1 if you have the <net/if.h> header file. */
#undef HAVE_NET_IF_H
/* Define to 1 if you have the `posix_spawn' function. */ /* Define to 1 if you have the `posix_spawn' function. */
#undef HAVE_POSIX_SPAWN #undef HAVE_POSIX_SPAWN

View File

@ -126,13 +126,8 @@ struct qse_upxd_cbs_t
int (*delhnd) (qse_upxd_t* upxd, void* mux, qse_ubi_t handle); int (*delhnd) (qse_upxd_t* upxd, void* mux, qse_ubi_t handle);
int (*poll) (qse_upxd_t* upxd, void* mux, qse_ntime_t timeout); int (*poll) (qse_upxd_t* upxd, void* mux, qse_ntime_t timeout);
} mux; } 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; typedef struct qse_upxd_cbs_t qse_upxd_cbs_t;
#ifdef __cplusplus #ifdef __cplusplus
@ -190,6 +185,11 @@ qse_upxd_server_t* qse_upxd_addserver (
const qse_char_t* dev const qse_char_t* dev
); );
void qse_upxd_delserver (
qse_upxd_t* upxd,
qse_upxd_server_t* server
);
void* qse_upxd_getserverctx ( void* qse_upxd_getserverctx (
qse_upxd_t* upxd, qse_upxd_t* upxd,
qse_upxd_server_t* server qse_upxd_server_t* server
@ -210,6 +210,21 @@ int qse_upxd_loop (
qse_ntime_t timeout 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -24,121 +24,83 @@
#include <qse/cmn/fmt.h> #include <qse/cmn/fmt.h>
#include "mem.h" #include "mem.h"
#if 0 #if defined(HAVE_NET_IF_H)
int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) #include <net/if.h>
#include <qse/cmn/mbwc.h>
#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_mchar_t tmp[IF_NAMESIZE + 1];
qse_mcstr_t tmp; if (qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), ptr, len) < len)
qse_nwad_t tmpad;
QSE_MEMSET (&tmpad, 0, QSE_SIZEOF(tmpad));
p = str;
if (*p == QSE_MT('['))
{ {
/* IPv6 address */ /* name too long */
tmp.ptr = ++p; /* skip [ and remember the position */ return 0;
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')); return if_nametoindex (tmp);
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;
}
else
{
/* host name or IPv4 address */
tmp.ptr = p;
while (*p != QSE_MT('\0') && *p != QSE_MT(':')) p++;
tmp.len = p - tmp.ptr;
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. */
while (*p != QSE_MT('\0') && *p != QSE_MT('%')) p++;
tmp.len = p - tmp.ptr;
if (qse_mbsntoipad6 (tmp.ptr, tmp.len, &tmpad.u.in6.addr) <= -1)
return -1;
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('\0')) return -1; static QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len)
tmpad.type = QSE_NWAD_IN6;
goto done;
}
tmpad.type = QSE_NWAD_IN4;
}
if (*p == QSE_MT(':'))
{ {
/* port number */ qse_mchar_t tmp[IF_NAMESIZE + 1];
qse_uint32_t port = 0; qse_size_t wl, ml;
p++; /* skip : */ 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
for (tmp.ptr = p; *p >= QSE_MT('0') && *p <= QSE_MT('9'); p++) #if defined(HAVE_IF_INDEXTONAME)
port = port * 10 + (*p - QSE_MT('0')); static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len)
{
tmp.len = p - tmp.ptr; qse_mchar_t tmp[IF_NAMESIZE + 1];
if (tmp.len <= 0 || tmp.len >= 6 || if (if_indextoname (index, tmp) == QSE_NULL) return 0;
port > QSE_TYPE_MAX(qse_uint16_t)) return -1; return qse_mbsxcpy (buf, len, tmp);
if (tmpad.type == QSE_NWAD_IN4)
tmpad.u.in4.port = qse_hton16 (port);
else
tmpad.u.in6.port = qse_hton16 (port);
} }
done: static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len)
if (nwad) *nwad = tmpad; {
qse_mchar_t tmp[IF_NAMESIZE + 1];
qse_size_t ml, wl;
int x;
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;
}
#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; return 0;
} }
#endif #endif
#endif
int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad)
{ {
return qse_mbsntonwad (str, qse_mbslen(str), nwad); return qse_mbsntonwad (str, qse_mbslen(str), nwad);
@ -174,7 +136,15 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad)
p++; /* skip % */ p++; /* skip % */
if (!(p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1; if (p >= end)
{
/* premature end */
return -1;
}
if (*p >= QSE_MT('0') && *p <= QSE_MT('9'))
{
/* numeric scope id */
tmpad.u.in6.scope = 0; tmpad.u.in6.scope = 0;
do do
{ {
@ -184,6 +154,15 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad)
p++; p++;
} }
while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); 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;
}
if (p >= end || *p != QSE_MT(']')) return -1; if (p >= end || *p != QSE_MT(']')) return -1;
} }
@ -218,7 +197,16 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad)
qse_uint32_t x; qse_uint32_t x;
p++; /* skip % */ p++; /* skip % */
if (!(p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9'))) return -1;
if (p >= end)
{
/* premature end */
return -1;
}
if (*p >= QSE_MT('0') && *p <= QSE_MT('9'))
{
/* numeric scope id */
tmpad.u.in6.scope = 0; tmpad.u.in6.scope = 0;
do do
{ {
@ -229,6 +217,15 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad)
} }
while (p < end && *p >= QSE_MT('0') && *p <= QSE_MT('9')); 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;
}
}
if (p < end) return -1; if (p < end) return -1;
@ -303,7 +300,15 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad)
p++; /* skip % */ p++; /* skip % */
if (!(p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9'))) return -1; if (p >= end)
{
/* premature end */
return -1;
}
if (*p >= QSE_WT('0') && *p <= QSE_WT('9'))
{
/* numeric scope id */
tmpad.u.in6.scope = 0; tmpad.u.in6.scope = 0;
do do
{ {
@ -313,6 +318,15 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad)
p++; p++;
} }
while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); 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;
}
if (p >= end || *p != QSE_WT(']')) return -1; if (p >= end || *p != QSE_WT(']')) return -1;
} }
@ -347,7 +361,16 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad)
qse_uint32_t x; qse_uint32_t x;
p++; /* skip % */ p++; /* skip % */
if (!(p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9'))) return -1;
if (p >= end)
{
/* premature end */
return -1;
}
if (*p >= QSE_WT('0') && *p <= QSE_WT('9'))
{
/* numeric scope id */
tmpad.u.in6.scope = 0; tmpad.u.in6.scope = 0;
do do
{ {
@ -358,6 +381,15 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad)
} }
while (p < end && *p >= QSE_WT('0') && *p <= QSE_WT('9')); 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;
}
}
if (p < end) return -1; if (p < end) return -1;
@ -446,19 +478,28 @@ qse_size_t qse_nwadtombs (
if (flags & QSE_NWADTOMBS_ADDR) if (flags & QSE_NWADTOMBS_ADDR)
{ {
if (xlen + 1 >= len) goto done; if (xlen + 1 >= len) goto done;
xlen += qse_ipad6tombs (&nwad->u.in6.addr, &buf[xlen], len - xlen); xlen += qse_ipad6tombs (&nwad->u.in6.addr, &buf[xlen], len - xlen);
if (nwad->u.in6.scope != 0) if (nwad->u.in6.scope != 0)
{ {
int tmp;
if (xlen + 1 >= len) goto done; if (xlen + 1 >= len) goto done;
buf[xlen++] = QSE_MT('%'); buf[xlen++] = QSE_MT('%');
if (xlen + 1 >= len) goto done; if (xlen + 1 >= len) goto done;
tmp = ifindex_to_mbsn (nwad->u.in6.scope, &buf[xlen], len - xlen);
if (tmp <= 0)
{
xlen += qse_fmtuintmaxtombs ( xlen += qse_fmtuintmaxtombs (
&buf[xlen], len - xlen, &buf[xlen], len - xlen,
nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL); nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL);
} }
else xlen += tmp;
}
} }
if (flags & QSE_NWADTOMBS_PORT) if (flags & QSE_NWADTOMBS_PORT)
@ -547,14 +588,22 @@ qse_size_t qse_nwadtowcs (
if (nwad->u.in6.scope != 0) if (nwad->u.in6.scope != 0)
{ {
int tmp;
if (xlen + 1 >= len) goto done; if (xlen + 1 >= len) goto done;
buf[xlen++] = QSE_WT('%'); buf[xlen++] = QSE_WT('%');
if (xlen + 1 >= len) goto done; if (xlen + 1 >= len) goto done;
tmp = ifindex_to_wcsn (nwad->u.in6.scope, &buf[xlen], len - xlen);
if (tmp <= 0)
{
xlen += qse_fmtuintmaxtowcs ( xlen += qse_fmtuintmaxtowcs (
&buf[xlen], len - xlen, &buf[xlen], len - xlen,
nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL);
} }
else xlen += tmp;
}
} }
if (flags & QSE_NWADTOWCS_PORT) if (flags & QSE_NWADTOWCS_PORT)

View File

@ -436,15 +436,19 @@ int qse_nwio_init (
nwio->errnum = QSE_NWIO_ENOIMPL; nwio->errnum = QSE_NWIO_ENOIMPL;
return -1; return -1;
#else
#if defined(SOCK_CLOEXEC)
nwio->handle = socket (family, type | SOCK_CLOEXEC, 0);
#else #else
nwio->handle = socket (family, type, 0); nwio->handle = socket (family, type, 0);
#endif
if (nwio->handle <= -1) if (nwio->handle <= -1)
{ {
nwio->errnum = syserr_to_errnum (errno); nwio->errnum = syserr_to_errnum (errno);
goto oops; goto oops;
} }
#if defined(FD_CLOEXEC) #if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
{ {
int tmp = fcntl (nwio->handle, F_GETFD); int tmp = fcntl (nwio->handle, F_GETFD);
if (tmp >= 0) fcntl (nwio->handle, F_SETFD, tmp | FD_CLOEXEC); if (tmp >= 0) fcntl (nwio->handle, F_SETFD, tmp | FD_CLOEXEC);

View File

@ -23,6 +23,7 @@
QSE_IMPLEMENT_COMMON_FUNCTIONS (upxd) QSE_IMPLEMENT_COMMON_FUNCTIONS (upxd)
static void disable_all_servers (qse_upxd_t* upxd);
static void free_all_servers (qse_upxd_t* upxd); static void free_all_servers (qse_upxd_t* upxd);
static qse_upxd_server_session_t* find_server_session ( static qse_upxd_server_session_t* find_server_session (
qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from); 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) void qse_upxd_fini (qse_upxd_t* upxd)
{ {
QSE_ASSERTX (upxd->server.nactive == 0, if (upxd->server.nactive > 0) disable_all_servers (upxd);
"Deactivate all servers before destroying me");
if (upxd->mux)
{
upxd->cbs->mux.close (upxd, upxd->mux);
upxd->mux = QSE_NULL;
}
free_all_servers (upxd); 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); QSE_MMGR_FREE (upxd->mmgr, ptr);
} }
void qse_upxd_stop (qse_upxd_t* upxd)
{
upxd->stopreq = 1;
}
static int perform_session_task ( static int perform_session_task (
qse_upxd_t* upxd, void* mux, qse_ubi_t handle, void* cbarg) 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)); QSE_MEMSET (session, 0, QSE_SIZEOF(*session));
if (qse_gettime (&session->created) <= -1) if (qse_gettime (&session->created) <= -1)
{ {
qse_upxd_freemem (upxd, session); qse_upxd_freemem (upxd, session);
@ -275,10 +277,10 @@ static void release_session (
qse_upxd_freemem (upxd, 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 (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) 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; return -1;
} }
server->flags |= QSE_UPXD_SERVER_ACTIVE; server->flags |= QSE_UPXD_SERVER_ENABLED;
upxd->server.nactive++; upxd->server.nactive++;
return 0; 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_upxd_server_session_t* session;
QSE_ASSERT (upxd->cbs != QSE_NULL); 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; session = server->session.list;
while (session) 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->mux.delhnd (upxd, upxd->mux, server->local.handle);
upxd->cbs->sock.close (upxd, &server->local); upxd->cbs->sock.close (upxd, &server->local);
server->flags &= ~QSE_UPXD_SERVER_ACTIVE; server->flags &= ~QSE_UPXD_SERVER_ENABLED;
upxd->server.nactive--; 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; qse_upxd_server_t* server;
for (server = upxd->server.list; server; server = server->next) 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; qse_upxd_server_t* server;
server = upxd->server.list; server = upxd->server.list;
while (server) while (server)
{ {
if (server->flags & QSE_UPXD_SERVER_ACTIVE) if (server->flags & QSE_UPXD_SERVER_ENABLED)
deactivate_server (upxd, server); disable_server (upxd, server);
server = server->next; server = server->next;
} }
@ -362,29 +364,6 @@ static void free_all_servers (qse_upxd_t* upxd)
upxd->server.list = QSE_NULL; 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_server_t* qse_upxd_addserver (
qse_upxd_t* upxd, const qse_nwad_t* nwad, const qse_char_t* dev) 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; 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; server->next = upxd->server.list;
upxd->server.list = server; upxd->server.list = server;
upxd->cbs->lock.release (upxd);
return server; return server;
} }
@ -422,7 +402,13 @@ qse_upxd_server_t* qse_upxd_addserver (
void qse_upxd_delserver ( void qse_upxd_delserver (
qse_upxd_t* upxd, qse_upxd_server_t* server) 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 ( 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) 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); purge_idle_sessions_in_server (upxd, server);
} }
@ -491,26 +477,25 @@ int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout)
QSE_ASSERTX (upxd->cbs != QSE_NULL, QSE_ASSERTX (upxd->cbs != QSE_NULL,
"Call qse_upxd_setcbs() before calling qse_upxd_loop()"); "Call qse_upxd_setcbs() before calling qse_upxd_loop()");
QSE_ASSERT (upxd->mux == QSE_NULL);
if (upxd->cbs == QSE_NULL || upxd->mux /*|| if (upxd->cbs == QSE_NULL)
upxd->server.list == QSE_NULL*/)
{ {
upxd->errnum = QSE_UPXD_EINVAL; upxd->errnum = QSE_UPXD_EINVAL;
goto oops; 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->stopreq = 0;
upxd->mux = upxd->cbs-> mux.open (upxd); upxd->mux = upxd->cbs-> mux.open (upxd);
if (upxd->mux == QSE_NULL) goto oops; if (upxd->mux == QSE_NULL) goto oops;
activate_all_servers (upxd); enable_all_servers (upxd);
if (upxd->server.nactive == 0)
{
/* at least 1 server must be activated here */
upxd->errnum = QSE_UPXD_EINVAL;
goto oops;
}
while (!upxd->stopreq) while (!upxd->stopreq)
{ {
@ -522,17 +507,65 @@ int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout)
/* TODO: anything? */ /* TODO: anything? */
} }
upxd->cbs->lock.acquire (upxd);
purge_idle_sessions (upxd); purge_idle_sessions (upxd);
purge_deleted_servers (upxd); enable_all_servers (upxd);
activate_all_servers (upxd);
upxd->cbs->lock.release (upxd);
} }
retv = 0; retv = 0;
oops: oops:
if (upxd->server.nactive > 0) deactivate_all_servers (upxd); if (upxd->server.nactive > 0) disable_all_servers (upxd);
if (upxd->mux) upxd->cbs->mux.close (upxd, upxd->mux); if (upxd->mux)
{
upxd->cbs->mux.close (upxd, upxd->mux);
upxd->mux = QSE_NULL;
}
return retv; 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;
}

View File

@ -29,9 +29,9 @@ typedef struct qse_upxd_server_session_t qse_upxd_server_session_t;
struct qse_upxd_server_t struct qse_upxd_server_t
{ {
qse_upxd_server_t* next; qse_upxd_server_t* next;
qse_upxd_server_t* prev;
#define QSE_UPXD_SERVER_ACTIVE (1 << 0) #define QSE_UPXD_SERVER_ENABLED (1 << 0)
#define QSE_UPXD_SERVER_DELETED (1 << 1)
int flags; int flags;
/* the socket can be bound to this interface. /* the socket can be bound to this interface.

View File

@ -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:0:0"),
QSE_T("::ffff:192.168.1.1"), QSE_T("::ffff:192.168.1.1"),
QSE_T("::ffff:192.168.1.1%88"), 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("[::]:10"),
QSE_T("[::1]:20"), QSE_T("[::1]:20"),
QSE_T("[fe80::f27b:cbff:fea3:f40c]:30"), 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("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"),
QSE_T("[::ffff:0:0]:60"), QSE_T("[::ffff:0:0]:60"),
QSE_T("[::ffff:192.168.1.1]:70"), 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[] = 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:0:0"),
QSE_MT("::ffff:192.168.1.1"), QSE_MT("::ffff:192.168.1.1"),
QSE_MT("::ffff:192.168.1.1%88"), 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("[::]:10"),
QSE_MT("[::1]:20"), QSE_MT("[::1]:20"),
QSE_MT("[fe80::f27b:cbff:fea3:f40c]:30"), 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("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"),
QSE_MT("[::ffff:0:0]:60"), QSE_MT("[::ffff:0:0]:60"),
QSE_MT("[::ffff:192.168.1.1]:70"), 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[] = 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:0:0"),
QSE_WT("::ffff:192.168.1.1"), QSE_WT("::ffff:192.168.1.1"),
QSE_WT("::ffff:192.168.1.1%88"), 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("[::]:10"),
QSE_WT("[::1]:20"), QSE_WT("[::1]:20"),
QSE_WT("[fe80::f27b:cbff:fea3:f40c]:30"), 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("[2001:db8:1234:ffff:ffff:ffff:ffff:ffff]:50"),
QSE_WT("[::ffff:0:0]:60"), QSE_WT("[::ffff:0:0]:60"),
QSE_WT("[::ffff:192.168.1.1]:70"), 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++) for (i = 0; i < QSE_COUNTOF(ipstr); i++)
{ {
if (qse_strtonwad (ipstr[i], &nwad) <= -1) 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 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) 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 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) 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 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; return 0;
} }

View File

@ -5,10 +5,12 @@
#include <qse/cmn/mem.h> #include <qse/cmn/mem.h>
#include <qse/cmn/mbwc.h> #include <qse/cmn/mbwc.h>
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
#include <qse/cmn/sio.h>
#include <signal.h> #include <signal.h>
#include <locale.h> #include <locale.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> # include <windows.h>
@ -466,6 +468,13 @@ static int mux_poll (qse_upxd_t* upxd, void* vmux, qse_ntime_t timeout)
struct mux_ev_t* mev; struct mux_ev_t* mev;
int nfds, i; int nfds, i;
if (mux->ee.len < 0)
{
/* nothing to monitor yet */
sleep (timeout / 1000);
}
else
{
nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout); nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout);
if (nfds <= -1) if (nfds <= -1)
{ {
@ -480,19 +489,11 @@ static int mux_poll (qse_upxd_t* upxd, void* vmux, qse_ntime_t timeout)
if (mux->ee.ptr[i].events & (EPOLLIN | EPOLLHUP)) if (mux->ee.ptr[i].events & (EPOLLIN | EPOLLHUP))
mev->cbfun (upxd, mux, mev->handle, mev->cbarg); mev->cbfun (upxd, mux, mev->handle, mev->cbarg);
} }
}
return 0; return 0;
} }
/* ------------------------------------------------------------------- */
void lock_acquire (qse_upxd_t* upxd)
{
}
void lock_release (qse_upxd_t* upxd)
{
}
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
static qse_upxd_cbs_t upxd_cbs = static qse_upxd_cbs_t upxd_cbs =
{ {
@ -503,12 +504,179 @@ static qse_upxd_cbs_t upxd_cbs =
{ session_config, session_error }, { session_config, session_error },
/* multiplexer */ /* multiplexer */
{ mux_open, mux_close, mux_addhnd, mux_delhnd, mux_poll }, { mux_open, mux_close, mux_addhnd, mux_delhnd, mux_poll }
/* lock */
{ lock_acquire, lock_release }
}; };
/* ------------------------------------------------------------------- */
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 qse_upxd_t* g_upxd = QSE_NULL;
static void sigint (int sig) static void sigint (int sig)
@ -519,6 +687,7 @@ static void sigint (int sig)
int upxd_main (int argc, qse_char_t* argv[]) int upxd_main (int argc, qse_char_t* argv[])
{ {
qse_upxd_t* upxd = QSE_NULL; qse_upxd_t* upxd = QSE_NULL;
cfg_t* cfg = QSE_NULL;
int ret = -1, i; int ret = -1, i;
if (argc <= 1) if (argc <= 1)
@ -527,6 +696,13 @@ int upxd_main (int argc, qse_char_t* argv[])
goto oops; 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); upxd = qse_upxd_open (QSE_MMGR_GETDFL(), 0);
if (upxd == QSE_NULL) if (upxd == QSE_NULL)
{ {
@ -569,6 +745,7 @@ int upxd_main (int argc, qse_char_t* argv[])
oops: oops:
if (upxd) qse_upxd_close (upxd); if (upxd) qse_upxd_close (upxd);
if (cfg) free_cfg (cfg);
return ret; return ret;
} }