1660 lines
35 KiB
C
1660 lines
35 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <qse/si/nwio.h>
|
|
#include <qse/cmn/time.h>
|
|
#include "../cmn/mem-prv.h"
|
|
|
|
#if defined(_WIN32)
|
|
# include <winsock2.h>
|
|
# include <ws2tcpip.h> /* sockaddr_in6 */
|
|
# include <windows.h>
|
|
# define USE_SELECT
|
|
#elif defined(__OS2__)
|
|
# if defined(TCPV40HDRS)
|
|
# define BSD_SELECT
|
|
# endif
|
|
# include <types.h>
|
|
# include <sys/socket.h>
|
|
# include <netinet/in.h>
|
|
# include <sys/ioctl.h>
|
|
# include <nerrno.h>
|
|
# if defined(TCPV40HDRS)
|
|
# define USE_SELECT
|
|
# include <sys/select.h>
|
|
# else
|
|
# include <unistd.h>
|
|
# endif
|
|
#elif defined(__DOS__)
|
|
# include <tcp.h>
|
|
# include <sys/ioctl.h>
|
|
# define memset QSE_MEMSET /* FD_SET hardcodes memset() */
|
|
# define select select_s
|
|
# define USE_SELECT
|
|
/* SO_RCVTIMEO doesn't work or i don't know how to get it to work. */
|
|
# undef SO_RCVTIMEO
|
|
# undef SO_SNDTIMEO
|
|
#elif defined(HAVE_T_CONNECT) && !defined(HAVE_CONNECT) && defined(HAVE_TIUSER_H)
|
|
# include "../cmn/syscall.h"
|
|
# include <tiuser.h>
|
|
# include <sys/socket.h>
|
|
# include <netinet/in.h>
|
|
# define USE_TLI
|
|
# define USE_SELECT
|
|
|
|
|
|
extern int t_accept(int, int, struct t_call *);
|
|
extern void *t_alloc(int, int, int);
|
|
extern int t_bind(int, struct t_bind *, struct t_bind *);
|
|
extern int t_close(int);
|
|
extern int t_connect(int, struct t_call *, struct t_call *);
|
|
extern int t_listen(int, struct t_call *);
|
|
extern int t_open(const char *, int, struct t_info *);
|
|
extern int t_errno;
|
|
extern int t_snd(int fd, char* buf, unsigned int nbytes, int flags);
|
|
extern int t_rcv(int fd, char* buf, unsigned int nbytes, int* flags);
|
|
#elif defined(HAVE_POLL_H)
|
|
# include "../cmn/syscall.h"
|
|
# include <sys/socket.h>
|
|
# include <netinet/in.h>
|
|
# include <poll.h>
|
|
# define USE_POLL
|
|
#else
|
|
# include "../cmn/syscall.h"
|
|
# include <sys/socket.h>
|
|
# include <netinet/in.h>
|
|
# define USE_SELECT
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
STATUS_UDP_CONNECT = (1 << 0),
|
|
STATUS_TMOUT_R_PRESET = (1 << 1),
|
|
STATUS_TMOUT_W_PRESET = (1 << 2)
|
|
};
|
|
|
|
static qse_ssize_t socket_output (
|
|
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
|
|
static qse_ssize_t socket_input (
|
|
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
|
|
|
|
#define TMOUT_ENABLED(tmout) (tmout.sec >= 0 && tmout.nsec >= 0)
|
|
|
|
#if defined(_WIN32)
|
|
static qse_nwio_errnum_t skerr_to_errnum (DWORD e)
|
|
{
|
|
switch (e)
|
|
{
|
|
case WSA_NOT_ENOUGH_MEMORY:
|
|
return QSE_NWIO_ENOMEM;
|
|
|
|
case WSA_INVALID_PARAMETER:
|
|
case WSA_INVALID_HANDLE:
|
|
return QSE_NWIO_EINVAL;
|
|
|
|
case WSAEACCES:
|
|
return QSE_NWIO_EACCES;
|
|
|
|
case WSAEINTR:
|
|
return QSE_NWIO_EINTR;
|
|
|
|
case WSAECONNREFUSED:
|
|
case WSAENETUNREACH:
|
|
case WSAEHOSTUNREACH:
|
|
case WSAEHOSTDOWN:
|
|
return QSE_NWIO_ECONN;
|
|
|
|
default:
|
|
return QSE_NWIO_ESYSERR;
|
|
}
|
|
}
|
|
#elif defined(__OS2__)
|
|
static qse_nwio_errnum_t skerr_to_errnum (int e)
|
|
{
|
|
switch (e)
|
|
{
|
|
#if defined(SOCENOMEM)
|
|
case SOCENOMEM:
|
|
return QSE_NWIO_ENOMEM;
|
|
#endif
|
|
|
|
case SOCEINVAL:
|
|
return QSE_NWIO_EINVAL;
|
|
|
|
case SOCEACCES:
|
|
return QSE_NWIO_EACCES;
|
|
|
|
#if defined(SOCENOENT)
|
|
case SOCENOENT:
|
|
return QSE_NWIO_ENOENT;
|
|
#endif
|
|
|
|
#if defined(SOCEXIST)
|
|
case SOCEEXIST:
|
|
return QSE_NWIO_EEXIST;
|
|
#endif
|
|
|
|
case SOCEINTR:
|
|
return QSE_NWIO_EINTR;
|
|
|
|
case SOCEPIPE:
|
|
return QSE_NWIO_EPIPE;
|
|
|
|
case SOCECONNREFUSED:
|
|
case SOCENETUNREACH:
|
|
case SOCEHOSTUNREACH:
|
|
case SOCEHOSTDOWN:
|
|
return QSE_NWIO_ECONN;
|
|
|
|
default:
|
|
return QSE_NWIO_ESYSERR;
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
static qse_nwio_errnum_t skerr_to_errnum (int e)
|
|
{
|
|
switch (e)
|
|
{
|
|
case ENOMEM:
|
|
return QSE_NWIO_ENOMEM;
|
|
|
|
case EINVAL:
|
|
return QSE_NWIO_EINVAL;
|
|
|
|
case EACCES:
|
|
return QSE_NWIO_EACCES;
|
|
|
|
case ENOENT:
|
|
return QSE_NWIO_ENOENT;
|
|
|
|
case EEXIST:
|
|
return QSE_NWIO_EEXIST;
|
|
|
|
case EINTR:
|
|
return QSE_NWIO_EINTR;
|
|
|
|
case EPIPE:
|
|
return QSE_NWIO_EPIPE;
|
|
|
|
#if defined(EAGAIN) || defined(EWOULDBLOCK)
|
|
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK)
|
|
case EAGAIN:
|
|
#if (EWOULDBLOCK != EAGAIN)
|
|
case EWOULDBLOCK:
|
|
#endif
|
|
#elif defined(EAGAIN)
|
|
case EAGAIN:
|
|
#else
|
|
case EWOULDBLOCK;
|
|
#endif
|
|
return QSE_NWIO_EAGAIN;
|
|
#endif
|
|
|
|
#if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN)
|
|
#if defined(ECONNREFUSED)
|
|
case ECONNREFUSED:
|
|
#endif
|
|
#if defined(ENETUNREACH)
|
|
case ENETUNREACH:
|
|
#endif
|
|
#if defined(EHOSTUNREACH)
|
|
case EHOSTUNREACH:
|
|
#endif
|
|
#if defined(EHOSTDOWN)
|
|
case EHOSTDOWN:
|
|
#endif
|
|
return QSE_NWIO_ECONN;
|
|
#endif
|
|
|
|
default:
|
|
return QSE_NWIO_ESYSERR;
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(USE_TLI)
|
|
static qse_nwio_errnum_t tlierr_to_errnum (int te, int se)
|
|
{
|
|
switch (te)
|
|
{
|
|
/* TODO: add more t_error conversion */
|
|
|
|
case TACCES:
|
|
return QSE_NWIO_EACCES;
|
|
|
|
case TSYSERR:
|
|
return skerr_to_errnum (se);
|
|
|
|
default:
|
|
return QSE_NWIO_ESYSERR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#endif
|
|
|
|
static qse_nwio_errnum_t tio_errnum_to_nwio_errnum (qse_tio_t* tio)
|
|
{
|
|
switch (tio->errnum)
|
|
{
|
|
case QSE_TIO_ENOMEM:
|
|
return QSE_NWIO_ENOMEM;
|
|
case QSE_TIO_EINVAL:
|
|
return QSE_NWIO_EINVAL;
|
|
case QSE_TIO_EACCES:
|
|
return QSE_NWIO_EACCES;
|
|
case QSE_TIO_ENOENT:
|
|
return QSE_NWIO_ENOENT;
|
|
case QSE_TIO_EILSEQ:
|
|
return QSE_NWIO_EILSEQ;
|
|
case QSE_TIO_EICSEQ:
|
|
return QSE_NWIO_EICSEQ;
|
|
case QSE_TIO_EILCHR:
|
|
return QSE_NWIO_EILCHR;
|
|
default:
|
|
return QSE_NWIO_EOTHER;
|
|
}
|
|
}
|
|
|
|
static int wait_for_data (qse_nwio_t* nwio, const qse_ntime_t* tmout, int what)
|
|
{
|
|
int xret;
|
|
|
|
#if defined(USE_POLL)
|
|
struct pollfd pfd;
|
|
|
|
pfd.fd = nwio->handle;
|
|
pfd.revents = 0;
|
|
switch (what)
|
|
{
|
|
case 0:
|
|
pfd.events = POLLIN;
|
|
break;
|
|
|
|
case 1:
|
|
pfd.events = POLLOUT;
|
|
break;
|
|
|
|
case 2:
|
|
pfd.events = POLLIN | POLLOUT;
|
|
break;
|
|
|
|
default:
|
|
nwio->errnum = QSE_NWIO_EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
xret = poll (&pfd, 1, QSE_SECNSEC_TO_MSEC(tmout->sec, tmout->nsec));
|
|
if (xret <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
return -1;
|
|
}
|
|
else if (xret == 0)
|
|
{
|
|
nwio->errnum = QSE_NWIO_ETMOUT;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
#elif defined(USE_SELECT)
|
|
fd_set fds[2];
|
|
struct timeval tv;
|
|
|
|
FD_ZERO (&fds[0]);
|
|
FD_ZERO (&fds[1]);
|
|
|
|
switch (what)
|
|
{
|
|
case 0: /* read */
|
|
case 1: /* write */
|
|
FD_SET (nwio->handle, &fds[what]);
|
|
break;
|
|
|
|
case 2: /* both */
|
|
FD_SET (nwio->handle, &fds[0]);
|
|
FD_SET (nwio->handle, &fds[1]);
|
|
break;
|
|
|
|
default:
|
|
nwio->errnum = QSE_NWIO_EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
tv.tv_sec = tmout->sec;
|
|
tv.tv_usec = QSE_NSEC_TO_USEC (tmout->nsec);
|
|
|
|
xret = select (nwio->handle + 1, &fds[0], &fds[1], QSE_NULL, &tv);
|
|
#if defined(_WIN32)
|
|
if (xret == SOCKET_ERROR)
|
|
#else
|
|
if (xret <= -1)
|
|
#endif
|
|
{
|
|
#if defined(_WIN32)
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
#elif defined(__OS2__)
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
#else
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
#endif
|
|
return -1;
|
|
}
|
|
else if (xret == 0)
|
|
{
|
|
nwio->errnum = QSE_NWIO_ETMOUT;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
#elif defined(__OS2__)
|
|
int count[2] = { 0, 0 };
|
|
long tmout_msecs;
|
|
|
|
count[what]++;
|
|
|
|
tmout_msecs = QSE_SECNSEC_TO_MSEC (tmout->sec, tmout->nsec);
|
|
xret = os2_select (&nwio->handle, count[0], count[1], 0, tmout_msecs);
|
|
if (xret <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
return -1;
|
|
}
|
|
else if (xret == 0)
|
|
{
|
|
nwio->errnum = QSE_NWIO_ETMOUT;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
#else
|
|
nwio->errnum = QSE_NWIO_ENOIMPL;
|
|
return -1;
|
|
#endif
|
|
|
|
}
|
|
|
|
qse_nwio_t* qse_nwio_open (
|
|
qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_nwad_t* nwad,
|
|
int flags, const qse_nwio_tmout_t* tmout)
|
|
{
|
|
qse_nwio_t* nwio;
|
|
|
|
nwio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_nwio_t) + xtnsize);
|
|
if (nwio == QSE_NULL) return QSE_NULL;
|
|
|
|
if (qse_nwio_init (nwio, mmgr, nwad, flags, tmout) <= -1)
|
|
{
|
|
QSE_MMGR_FREE (mmgr, nwio);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
QSE_MEMSET (nwio + 1, 0, xtnsize);
|
|
return nwio;
|
|
}
|
|
|
|
void qse_nwio_close (qse_nwio_t* nwio)
|
|
{
|
|
qse_nwio_fini (nwio);
|
|
QSE_MMGR_FREE (nwio->mmgr, nwio);
|
|
}
|
|
|
|
static int preset_tmout (qse_nwio_t* nwio)
|
|
{
|
|
#if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
|
|
#if defined(_WIN32)
|
|
DWORD tv;
|
|
#elif defined(__OS2__)
|
|
long tv;
|
|
#else
|
|
struct timeval tv;
|
|
#endif
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.r))
|
|
{
|
|
#if defined(_WIN32) || defined(__OS2__)
|
|
tv = QSE_SEC_TO_MSEC(nwio->tmout.r.sec) + QSE_NSEC_TO_MSEC (nwio->tmout.r.nsec);
|
|
#else
|
|
tv.tv_sec = nwio->tmout.r.sec;
|
|
tv.tv_usec = QSE_NSEC_TO_USEC (nwio->tmout.r.nsec);
|
|
#endif
|
|
|
|
if (setsockopt (nwio->handle, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, QSE_SIZEOF(tv)) <= -1)
|
|
{
|
|
#if defined(_WIN32)
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
#elif defined(__OS2__)
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
#else
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
#endif
|
|
return -1; /* tried to set but failed */
|
|
}
|
|
|
|
nwio->status |= STATUS_TMOUT_R_PRESET;
|
|
}
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.w))
|
|
{
|
|
#if defined(_WIN32) || defined(__OS2__)
|
|
tv = QSE_SEC_TO_MSEC(nwio->tmout.w.sec) + QSE_NSEC_TO_MSEC (nwio->tmout.w.nsec);
|
|
#else
|
|
tv.tv_sec = nwio->tmout.w.sec;
|
|
tv.tv_usec = QSE_NSEC_TO_USEC (nwio->tmout.w.nsec);
|
|
#endif
|
|
if (setsockopt (nwio->handle, SOL_SOCKET, SO_SNDTIMEO, (void*)&tv, QSE_SIZEOF(tv)) <= -1)
|
|
{
|
|
#if defined(_WIN32)
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
#elif defined(__OS2__)
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
#else
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
#endif
|
|
return -1; /* tried to set but failed */
|
|
}
|
|
|
|
nwio->status |= STATUS_TMOUT_W_PRESET;
|
|
}
|
|
|
|
return 1; /* set successfully - don't need a multiplexer */
|
|
#endif
|
|
|
|
return 0; /* no measn to set it */
|
|
}
|
|
|
|
int qse_nwio_init (
|
|
qse_nwio_t* nwio, qse_mmgr_t* mmgr, const qse_nwad_t* nwad,
|
|
int flags, const qse_nwio_tmout_t* tmout)
|
|
{
|
|
qse_skad_t addr;
|
|
qse_sck_len_t addrlen;
|
|
int family, type, tmp;
|
|
|
|
QSE_MEMSET (nwio, 0, QSE_SIZEOF(*nwio));
|
|
nwio->mmgr = mmgr;
|
|
nwio->flags = flags;
|
|
nwio->errnum = QSE_NWIO_ENOERR;
|
|
if (tmout) nwio->tmout = *tmout;
|
|
else
|
|
{
|
|
nwio->tmout.r.sec = -1;
|
|
nwio->tmout.w.sec = -1;
|
|
nwio->tmout.c.sec = -1;
|
|
nwio->tmout.a.sec = -1;
|
|
}
|
|
|
|
tmp = qse_nwadtoskad (nwad, &addr);
|
|
if (tmp <= -1)
|
|
{
|
|
nwio->errnum = QSE_NWIO_EINVAL;
|
|
return -1;
|
|
}
|
|
addrlen = tmp;
|
|
|
|
#if defined(SOCK_STREAM) && defined(SOCK_DGRAM)
|
|
if (flags & QSE_NWIO_TCP) type = SOCK_STREAM;
|
|
else if (flags & QSE_NWIO_UDP) type = SOCK_DGRAM;
|
|
else
|
|
#endif
|
|
{
|
|
nwio->errnum = QSE_NWIO_EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
family = qse_skadfamily (&addr);
|
|
|
|
#if defined(_WIN32)
|
|
nwio->handle = socket (family, type, 0);
|
|
if (nwio->handle == INVALID_SOCKET)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
|
|
if ((flags & QSE_NWIO_TCP) && (flags & QSE_NWIO_KEEPALIVE))
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (flags & QSE_NWIO_PASSIVE)
|
|
{
|
|
qse_nwio_hnd_t handle;
|
|
|
|
if (flags & QSE_NWIO_REUSEADDR)
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
|
|
if (flags & QSE_NWIO_TCP)
|
|
{
|
|
if (listen (nwio->handle, 10) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
|
|
|
|
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
|
|
if (handle == INVALID_SOCKET)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
|
|
closesocket (nwio->handle);
|
|
nwio->handle = handle;
|
|
}
|
|
else if (flags & QSE_NWIO_UDP)
|
|
{
|
|
nwio->status |= STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int xret;
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
unsigned long cmd = 1;
|
|
|
|
if (ioctlsocket(nwio->handle, FIONBIO, &cmd) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen);
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
unsigned long cmd = 0;
|
|
|
|
if ((xret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) ||
|
|
ioctlsocket (nwio->handle, FIONBIO, &cmd) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
|
|
if (wait_for_data (nwio, &nwio->tmout.c, 1) <= -1) goto oops;
|
|
else
|
|
{
|
|
int xlen;
|
|
DWORD xerr;
|
|
|
|
xlen = QSE_SIZEOF(xerr);
|
|
if (getsockopt (nwio->handle, SOL_SOCKET, SO_ERROR, (char*)&xerr, &xlen) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
else if (xerr != 0)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (xerr);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xret == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif defined(__OS2__)
|
|
nwio->handle = socket (family, type, 0);
|
|
if (nwio->handle <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
|
|
if ((flags & QSE_NWIO_TCP) && (flags & QSE_NWIO_KEEPALIVE))
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (flags & QSE_NWIO_PASSIVE)
|
|
{
|
|
qse_nwio_hnd_t handle;
|
|
|
|
if (flags & QSE_NWIO_REUSEADDR)
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
|
|
if (flags & QSE_NWIO_TCP)
|
|
{
|
|
if (listen (nwio->handle, 10) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
|
|
|
|
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
|
|
if (handle <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
|
|
soclose (nwio->handle);
|
|
nwio->handle = handle;
|
|
}
|
|
else if (flags & QSE_NWIO_UDP)
|
|
{
|
|
nwio->status |= STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int xret;
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int noblk = 1;
|
|
|
|
if (ioctl (nwio->handle, FIONBIO, (void*)&noblk, QSE_SIZEOF(noblk)) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen);
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int noblk = 0;
|
|
|
|
if ((xret <= -1 && sock_errno() != SOCEINPROGRESS) ||
|
|
ioctl (nwio->handle, FIONBIO, (void*)&noblk, QSE_SIZEOF(noblk)) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
|
|
if (wait_for_data (nwio, &nwio->tmout.c, 1) <= -1) goto oops;
|
|
else
|
|
{
|
|
int xlen, xerr;
|
|
|
|
xlen = QSE_SIZEOF(xerr);
|
|
if (getsockopt (nwio->handle, SOL_SOCKET, SO_ERROR, (char*)&xerr, &xlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
else if (xerr != 0)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (xerr);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xret <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
nwio->handle = socket (family, type, 0);
|
|
if (nwio->handle <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if ((flags & QSE_NWIO_TCP) && (flags & QSE_NWIO_KEEPALIVE))
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (flags & QSE_NWIO_PASSIVE)
|
|
{
|
|
qse_nwio_hnd_t handle;
|
|
|
|
#if defined(SO_REUSEADDR)
|
|
if (flags & QSE_NWIO_REUSEADDR)
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
#endif
|
|
|
|
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (flags & QSE_NWIO_TCP)
|
|
{
|
|
if (listen (nwio->handle, 10) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
|
|
|
|
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
|
|
if (handle <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
close_s (nwio->handle);
|
|
nwio->handle = handle;
|
|
}
|
|
else if (flags & QSE_NWIO_UDP)
|
|
{
|
|
nwio->status |= STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int xret;
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int cmd = 1;
|
|
|
|
if (ioctlsocket(nwio->handle, FIONBIO, (char*)&cmd) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen);
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int cmd = 0;
|
|
|
|
if ((xret == SOCKET_ERROR && errno != EWOULDBLOCK) ||
|
|
ioctlsocket (nwio->handle, FIONBIO, (char*)&cmd) == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (wait_for_data (nwio, &nwio->tmout.c, 1) <= -1) goto oops;
|
|
else
|
|
{
|
|
int xlen, xerr;
|
|
|
|
xlen = QSE_SIZEOF(xerr);
|
|
if (getsockopt (nwio->handle, SOL_SOCKET, SO_ERROR, (char*)&xerr, &xlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
else if (xerr != 0)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (xerr);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xret <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif defined(USE_TLI)
|
|
|
|
{
|
|
|
|
static const qse_mchar_t* dev_path[2][2] =
|
|
{
|
|
{ "/dev/tcp", "/dev/inet/tcp" },
|
|
{ "/dev/udp", "/dev/inet/tcp" }
|
|
};
|
|
int dev_id;
|
|
|
|
if (flags & QSE_NWIO_TCP) dev_id = 0;
|
|
else
|
|
{
|
|
QSE_ASSERT (flags & QSE_NWIO_UDP);
|
|
dev_id = 1;
|
|
}
|
|
|
|
nwio->handle = t_open (dev_path[dev_id][0], O_RDWR, QSE_NULL);
|
|
if (nwio->handle <= -1)
|
|
{
|
|
nwio->handle = t_open (dev_path[dev_id][1], O_RDWR, QSE_NULL);
|
|
if (nwio->handle <= -1)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
if (flags & QSE_NWIO_PASSIVE)
|
|
{
|
|
/* TODO: */
|
|
nwio->errnum = QSE_NWIO_ENOIMPL;
|
|
goto oops;
|
|
}
|
|
else
|
|
{
|
|
struct t_call call; /* for connecting */
|
|
struct t_bind req, ret; /* for binding */
|
|
qse_skad_t reqaddr, retaddr;
|
|
qse_nwad_t reqnwad;
|
|
|
|
/*
|
|
call = t_alloc (nwio->handle, T_CALL, T_ADDR);
|
|
if (!call)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}*/
|
|
|
|
qse_clearnwad (&reqnwad, nwad->type);
|
|
qse_nwadtoskad (&reqnwad, &reqaddr);
|
|
|
|
QSE_MEMSET (&ret, 0, QSE_SIZEOF(req));
|
|
req.addr.maxlen = addrlen;
|
|
req.addr.len = addrlen;
|
|
req.addr.buf = &reqaddr;
|
|
|
|
QSE_MEMSET (&ret, 0, QSE_SIZEOF(ret));
|
|
ret.addr.maxlen = addrlen;
|
|
ret.addr.len = addrlen;
|
|
ret.addr.buf = &retaddr;
|
|
|
|
if (t_bind (nwio->handle, &req, &ret) <= -1)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}
|
|
|
|
/* TODO: should i use t_alloc() and t_free for call, ret, req? */
|
|
QSE_MEMSET (&call, 0, QSE_SIZEOF(call));
|
|
call.addr.maxlen = addrlen;
|
|
call.addr.len = addrlen;
|
|
call.addr.buf = &addr;
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int orgfl;
|
|
|
|
orgfl = fcntl (nwio->handle, F_GETFL, 0);
|
|
if (orgfl <= -1 || fcntl (nwio->handle, F_SETFL, orgfl | O_NONBLOCK) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (t_connect (nwio->handle, &call, 0) <= -1)
|
|
{
|
|
if (t_errno != TNODATA)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}
|
|
|
|
/* TODO: this doesn't seem to work wel... REDO THE WORK */
|
|
if (wait_for_data (nwio, &nwio->tmout.c, 0) <= -1) goto oops;
|
|
|
|
if (t_rcvconnect (nwio->handle, QSE_NULL) <= -1)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
if (fcntl (nwio->handle, F_SETFL, orgfl) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (t_connect (nwio->handle, &call, 0) <= -1)
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#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 = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
#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);
|
|
}
|
|
#endif
|
|
|
|
if ((flags & QSE_NWIO_TCP) && (flags & QSE_NWIO_KEEPALIVE))
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
|
|
if (flags & QSE_NWIO_PASSIVE)
|
|
{
|
|
qse_nwio_hnd_t handle;
|
|
|
|
#if defined(SO_REUSEADDR)
|
|
if (flags & QSE_NWIO_REUSEADDR)
|
|
{
|
|
int optval = 1;
|
|
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
|
|
}
|
|
#endif
|
|
|
|
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (flags & QSE_NWIO_TCP)
|
|
{
|
|
if (listen (nwio->handle, 10) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
|
|
|
|
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
|
|
if (handle <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
qse_close_sck (nwio->handle); /* close the listening socket */
|
|
nwio->handle = handle; /* set the handle to the accepted socket */
|
|
}
|
|
else if (flags & QSE_NWIO_UDP)
|
|
{
|
|
nwio->status |= STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int xret;
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
|
|
{
|
|
int orgfl;
|
|
|
|
orgfl = fcntl (nwio->handle, F_GETFL, 0);
|
|
if (orgfl <= -1 || fcntl (nwio->handle, F_SETFL, orgfl | O_NONBLOCK) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen);
|
|
|
|
if ((xret <= -1 && errno != EINPROGRESS) ||
|
|
fcntl (nwio->handle, F_SETFL, orgfl) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
|
|
if (wait_for_data (nwio, &nwio->tmout.c, 1) <= -1) goto oops;
|
|
else
|
|
{
|
|
qse_sck_len_t xlen;
|
|
xlen = QSE_SIZEOF(xret);
|
|
if (getsockopt (nwio->handle, SOL_SOCKET, SO_ERROR, (char*)&xret, &xlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
else if (xret != 0)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (xret);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen);
|
|
if (xret <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
goto oops;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (flags & QSE_NWIO_TEXT)
|
|
{
|
|
int topt = 0;
|
|
|
|
if (flags & QSE_NWIO_IGNOREMBWCERR) topt |= QSE_TIO_IGNOREMBWCERR;
|
|
if (flags & QSE_NWIO_NOAUTOFLUSH) topt |= QSE_TIO_NOAUTOFLUSH;
|
|
|
|
nwio->tio = qse_tio_open (mmgr, QSE_SIZEOF(qse_nwio_t*), topt);
|
|
if (nwio->tio == QSE_NULL)
|
|
{
|
|
nwio->errnum = QSE_NWIO_ENOMEM;
|
|
goto oops;
|
|
}
|
|
|
|
/* store the back-reference to nwio in the extension area.*/
|
|
*(qse_nwio_t**)QSE_XTN(nwio->tio) = nwio;
|
|
|
|
if (qse_tio_attachin (nwio->tio, socket_input, QSE_NULL, 4096) <= -1 ||
|
|
qse_tio_attachout (nwio->tio, socket_output, QSE_NULL, 4096) <= -1)
|
|
{
|
|
if (nwio->errnum == QSE_NWIO_ENOERR)
|
|
nwio->errnum = tio_errnum_to_nwio_errnum (nwio->tio);
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
preset_tmout (nwio);
|
|
return 0;
|
|
|
|
oops:
|
|
if (nwio->tio)
|
|
{
|
|
qse_tio_close (nwio->tio);
|
|
nwio->tio = QSE_NULL;
|
|
}
|
|
|
|
if (qse_is_sck_valid(nwio->handle)) qse_close_sck (nwio->handle);
|
|
return -1;
|
|
}
|
|
|
|
void qse_nwio_fini (qse_nwio_t* nwio)
|
|
{
|
|
/*if (qse_nwio_flush (nwio) <= -1) return -1;*/
|
|
qse_nwio_flush (nwio);
|
|
if (nwio->tio)
|
|
{
|
|
qse_tio_close (nwio->tio);
|
|
nwio->tio = QSE_NULL;
|
|
}
|
|
|
|
qse_close_sck (nwio->handle);
|
|
}
|
|
|
|
qse_mmgr_t* qse_nwio_getmmgr (qse_nwio_t* nwio)
|
|
{
|
|
return nwio->mmgr;
|
|
}
|
|
|
|
void* qse_nwio_getxtn (qse_nwio_t* nwio)
|
|
{
|
|
return QSE_XTN (nwio);
|
|
}
|
|
|
|
qse_nwio_errnum_t qse_nwio_geterrnum (const qse_nwio_t* nwio)
|
|
{
|
|
return nwio->errnum;
|
|
}
|
|
|
|
qse_cmgr_t* qse_nwio_getcmgr (qse_nwio_t* nwio)
|
|
{
|
|
return nwio->tio? qse_tio_getcmgr (nwio->tio): QSE_NULL;
|
|
}
|
|
|
|
void qse_nwio_setcmgr (qse_nwio_t* nwio, qse_cmgr_t* cmgr)
|
|
{
|
|
if (nwio->tio) qse_tio_setcmgr (nwio->tio, cmgr);
|
|
}
|
|
|
|
qse_nwio_hnd_t qse_nwio_gethnd (const qse_nwio_t* nwio)
|
|
{
|
|
return nwio->handle;
|
|
}
|
|
|
|
qse_ssize_t qse_nwio_flush (qse_nwio_t* nwio)
|
|
{
|
|
qse_ssize_t n;
|
|
|
|
if (nwio->tio)
|
|
{
|
|
nwio->errnum = QSE_NWIO_ENOERR;
|
|
n = qse_tio_flush (nwio->tio);
|
|
if (n <= -1 && nwio->errnum == QSE_NWIO_ENOERR)
|
|
nwio->errnum = tio_errnum_to_nwio_errnum (nwio->tio);
|
|
}
|
|
else n = 0;
|
|
|
|
return n;
|
|
}
|
|
|
|
void qse_nwio_drain (qse_nwio_t* nwio)
|
|
{
|
|
if (nwio->tio) qse_tio_drain (nwio->tio);
|
|
}
|
|
|
|
/* ---------------------------------------------------------- */
|
|
|
|
static qse_ssize_t nwio_read (qse_nwio_t* nwio, void* buf, qse_size_t size)
|
|
{
|
|
#if defined(_WIN32)
|
|
int count;
|
|
#elif defined(__OS2__)
|
|
int n;
|
|
#elif defined(__DOS__)
|
|
int n;
|
|
#else
|
|
qse_ssize_t n;
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
if (nwio->status & STATUS_UDP_CONNECT)
|
|
{
|
|
qse_skad_t addr;
|
|
int addrlen;
|
|
|
|
addrlen = QSE_SIZEOF(addr);
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
|
|
|
|
count = recvfrom (
|
|
nwio->handle, buf, size, 0,
|
|
(struct sockaddr*)&addr, &addrlen);
|
|
if (count == SOCKET_ERROR)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
}
|
|
else if (count >= 1)
|
|
{
|
|
/* for udp, it just creates a stream with the
|
|
* first sender */
|
|
if (connect (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
return -1;
|
|
}
|
|
nwio->status &= ~STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.r) &&
|
|
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1) return -1;
|
|
|
|
count = recv (nwio->handle, buf, size, 0);
|
|
if (count == SOCKET_ERROR) nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
}
|
|
|
|
return count;
|
|
|
|
#elif defined(__OS2__)
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
if (nwio->status & STATUS_UDP_CONNECT)
|
|
{
|
|
qse_skad_t addr;
|
|
int addrlen;
|
|
|
|
addrlen = QSE_SIZEOF(addr);
|
|
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
|
|
|
|
n = recvfrom (
|
|
nwio->handle, buf, size, 0,
|
|
(struct sockaddr*)&addr, &addrlen);
|
|
if (n <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
}
|
|
else if (n >= 1)
|
|
{
|
|
/* for udp, it just creates a stream with the
|
|
* first sender */
|
|
if (connect (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (sock_errno());
|
|
return -1;
|
|
}
|
|
nwio->status &= ~STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.r) &&
|
|
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1) return -1;
|
|
|
|
n = recv (nwio->handle, buf, size, 0);
|
|
if (n <= -1) nwio->errnum = skerr_to_errnum (sock_errno());
|
|
}
|
|
|
|
return n;
|
|
|
|
#elif defined(USE_TLI)
|
|
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
reread:
|
|
if (nwio->status & STATUS_UDP_CONNECT)
|
|
{
|
|
qse_skad_t addr;
|
|
qse_sck_len_t addrlen;
|
|
|
|
addrlen = QSE_SIZEOF(addr);
|
|
|
|
/* it's similar to accept for tcp because i'm expecting
|
|
* the first sender and call connect() to it below just
|
|
* like the 'nc' utility does.
|
|
* so i treat this recvfrom() as if it is accept().
|
|
*/
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
|
|
|
|
/* TODO: */
|
|
nwio->errnum = QSE_NWIO_ENOIMPL;
|
|
return -1;
|
|
/*
|
|
n = recvfrom (
|
|
nwio->handle, buf, size, 0,
|
|
(struct sockaddr*)&addr, &addrlen);
|
|
*/
|
|
|
|
if (n <= -1)
|
|
{
|
|
if (t_errno == TSYSERR && errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_READNORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto reread;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
}
|
|
}
|
|
else if (n >= 1)
|
|
{
|
|
/* TODO: */
|
|
nwio->errnum = QSE_NWIO_ENOIMPL;
|
|
return -1;
|
|
|
|
/* for udp, it just creates a stream with the
|
|
* first sender */
|
|
/*
|
|
if (t_connect (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
return -1;
|
|
}
|
|
nwio->status &= ~STATUS_UDP_CONNECT;
|
|
*/
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int flags;
|
|
|
|
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.r) &&
|
|
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
n = t_rcv (nwio->handle, buf, size, &flags);
|
|
if (n <= -1)
|
|
{
|
|
if (t_errno == TSYSERR && errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_READNORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto reread;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
}
|
|
}
|
|
}
|
|
|
|
return n;
|
|
|
|
#else
|
|
|
|
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
|
|
|
|
reread:
|
|
if (nwio->status & STATUS_UDP_CONNECT)
|
|
{
|
|
qse_skad_t addr;
|
|
qse_sck_len_t addrlen;
|
|
|
|
addrlen = QSE_SIZEOF(addr);
|
|
|
|
/* it's similar to accept for tcp because i'm expecting
|
|
* the first sender and call connect() to it below just
|
|
* like the 'nc' utility does.
|
|
* so i treat this recvfrom() as if it is accept().
|
|
*/
|
|
if (TMOUT_ENABLED(nwio->tmout.a) &&
|
|
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
|
|
|
|
n = recvfrom (
|
|
nwio->handle, buf, size, 0,
|
|
(struct sockaddr*)&addr, &addrlen);
|
|
if (n <= -1)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_READNORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto reread;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
}
|
|
}
|
|
else if (n >= 1)
|
|
{
|
|
/* for udp, it just creates a stream with the
|
|
* first sender */
|
|
if (connect (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
return -1;
|
|
}
|
|
nwio->status &= ~STATUS_UDP_CONNECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.r) &&
|
|
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1) return -1;
|
|
|
|
n = recv (nwio->handle, buf, size, 0);
|
|
if (n <= -1)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_READNORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto reread;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
}
|
|
}
|
|
}
|
|
|
|
return n;
|
|
#endif
|
|
}
|
|
|
|
qse_ssize_t qse_nwio_read (qse_nwio_t* nwio, void* buf, qse_size_t size)
|
|
{
|
|
if (nwio->tio == QSE_NULL)
|
|
return nwio_read (nwio, buf, size);
|
|
else
|
|
{
|
|
qse_ssize_t n;
|
|
|
|
nwio->errnum = QSE_NWIO_ENOERR;
|
|
n = qse_tio_read (nwio->tio, buf, size);
|
|
if (n <= -1 && nwio->errnum == QSE_NWIO_ENOERR)
|
|
nwio->errnum = tio_errnum_to_nwio_errnum (nwio->tio);
|
|
|
|
return n;
|
|
}
|
|
}
|
|
|
|
static qse_ssize_t nwio_write (qse_nwio_t* nwio, const void* data, qse_size_t size)
|
|
{
|
|
#if defined(_WIN32)
|
|
int count;
|
|
#elif defined(__OS2__)
|
|
int n;
|
|
#elif defined(__DOS__)
|
|
int n;
|
|
#else
|
|
qse_ssize_t n;
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
if (!(nwio->status & STATUS_TMOUT_W_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.w) &&
|
|
wait_for_data (nwio, &nwio->tmout.w, 1) <= -1) return -1;
|
|
|
|
count = send (nwio->handle, data, size, 0);
|
|
if (count == SOCKET_ERROR) nwio->errnum = skerr_to_errnum (WSAGetLastError());
|
|
return count;
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
if (!(nwio->status & STATUS_TMOUT_W_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.w) &&
|
|
wait_for_data (nwio, &nwio->tmout.w, 1) <= -1) return -1;
|
|
|
|
n = send (nwio->handle, data, size, 0);
|
|
if (n <= -1) nwio->errnum = skerr_to_errnum (sock_errno());
|
|
return n;
|
|
|
|
#elif defined(USE_TLI)
|
|
|
|
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
|
|
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
|
|
|
|
rewrite:
|
|
if (!(nwio->status & STATUS_TMOUT_W_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.w) &&
|
|
wait_for_data (nwio, &nwio->tmout.w, 1) <= -1) return -1;
|
|
|
|
n = t_snd (nwio->handle, data, size, 0);
|
|
if (n <= -1)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_WRITENORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto rewrite;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = tlierr_to_errnum (t_errno, errno);
|
|
}
|
|
}
|
|
return n;
|
|
|
|
#else
|
|
|
|
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
|
|
|
|
rewrite:
|
|
if (!(nwio->status & STATUS_TMOUT_W_PRESET) &&
|
|
TMOUT_ENABLED(nwio->tmout.w) &&
|
|
wait_for_data (nwio, &nwio->tmout.w, 1) <= -1) return -1;
|
|
|
|
n = send (nwio->handle, data, size, 0);
|
|
if (n <= -1)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
if (nwio->flags & QSE_NWIO_WRITENORETRY)
|
|
nwio->errnum = QSE_NWIO_EINTR;
|
|
else goto rewrite;
|
|
}
|
|
else
|
|
{
|
|
nwio->errnum = skerr_to_errnum (errno);
|
|
}
|
|
}
|
|
return n;
|
|
|
|
#endif
|
|
}
|
|
|
|
qse_ssize_t qse_nwio_write (qse_nwio_t* nwio, const void* data, qse_size_t size)
|
|
{
|
|
if (nwio->tio == QSE_NULL)
|
|
{
|
|
return nwio_write(nwio, data, size);
|
|
}
|
|
else
|
|
{
|
|
qse_ssize_t n;
|
|
|
|
nwio->errnum = QSE_NWIO_ENOERR;
|
|
n = qse_tio_write(nwio->tio, data, size);
|
|
if (n <= -1 && nwio->errnum == QSE_NWIO_ENOERR)
|
|
nwio->errnum = tio_errnum_to_nwio_errnum (nwio->tio);
|
|
|
|
return n;
|
|
}
|
|
}
|
|
|
|
|
|
qse_ssize_t qse_nwio_writebytes (qse_nwio_t* nwio, const void* data, qse_size_t size)
|
|
{
|
|
if (nwio->tio == QSE_NULL)
|
|
return nwio_write(nwio, data, size);
|
|
else
|
|
return qse_tio_writembs(nwio->tio, data, size);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------- */
|
|
|
|
static qse_ssize_t socket_input (
|
|
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
|
|
{
|
|
if (cmd == QSE_TIO_DATA)
|
|
{
|
|
qse_nwio_t* nwio;
|
|
|
|
nwio = *(qse_nwio_t**)QSE_XTN(tio);
|
|
QSE_ASSERT (nwio != QSE_NULL);
|
|
|
|
return nwio_read (nwio, buf, size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static qse_ssize_t socket_output (
|
|
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
|
|
{
|
|
if (cmd == QSE_TIO_DATA)
|
|
{
|
|
qse_nwio_t* nwio;
|
|
|
|
nwio = *(qse_nwio_t**)QSE_XTN(tio);
|
|
QSE_ASSERT (nwio != QSE_NULL);
|
|
|
|
return nwio_write (nwio, buf, size);
|
|
}
|
|
|
|
return 0;
|
|
}
|