qse/lib/si/nwio.c

1660 lines
35 KiB
C
Raw Normal View History

2012-04-27 14:33:14 +00:00
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
2012-04-27 14:33:14 +00:00
2014-11-19 14:42:24 +00:00
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.
2012-04-27 14:33:14 +00:00
2014-11-19 14:42:24 +00:00
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.
2012-04-27 14:33:14 +00:00
*/
2016-04-28 14:33:10 +00:00
#include <qse/si/nwio.h>
#include <qse/cmn/time.h>
2016-04-29 03:55:42 +00:00
#include "../cmn/mem-prv.h"
2012-04-27 14:33:14 +00:00
#if defined(_WIN32)
2012-04-30 09:46:58 +00:00
# include <winsock2.h>
# include <ws2tcpip.h> /* sockaddr_in6 */
# include <windows.h>
2012-12-18 08:12:15 +00:00
# define USE_SELECT
2012-04-27 14:33:14 +00:00
#elif defined(__OS2__)
2013-10-21 08:39:53 +00:00
# if defined(TCPV40HDRS)
# define BSD_SELECT
# endif
2012-04-30 15:15:41 +00:00
# include <types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <sys/ioctl.h>
2012-04-30 15:15:41 +00:00
# include <nerrno.h>
2012-12-18 08:12:15 +00:00
# if defined(TCPV40HDRS)
# define USE_SELECT
# include <sys/select.h>
# else
# include <unistd.h>
# endif
2012-04-27 14:33:14 +00:00
#elif defined(__DOS__)
2014-10-20 04:58:15 +00:00
# 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
2012-04-27 14:33:14 +00:00
#else
# include "../cmn/syscall.h"
2012-04-27 14:33:14 +00:00
# include <sys/socket.h>
# include <netinet/in.h>
2012-12-18 08:12:15 +00:00
# define USE_SELECT
2012-04-27 14:33:14 +00:00
#endif
2012-04-29 15:26:44 +00:00
enum
{
STATUS_UDP_CONNECT = (1 << 0),
STATUS_TMOUT_R_PRESET = (1 << 1),
STATUS_TMOUT_W_PRESET = (1 << 2)
2012-04-29 15:26:44 +00:00
};
2012-05-01 01:36:18 +00:00
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)
2012-04-27 14:33:14 +00:00
#if defined(_WIN32)
static qse_nwio_errnum_t skerr_to_errnum (DWORD e)
2012-04-27 14:33:14 +00:00
{
switch (e)
{
2012-04-30 09:46:58 +00:00
case WSA_NOT_ENOUGH_MEMORY:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_ENOMEM;
2012-04-30 09:46:58 +00:00
case WSA_INVALID_PARAMETER:
case WSA_INVALID_HANDLE:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EINVAL;
2012-04-30 09:46:58 +00:00
case WSAEACCES:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EACCES;
2012-04-30 09:46:58 +00:00
case WSAEINTR:
return QSE_NWIO_EINTR;
2012-04-27 14:33:14 +00:00
2012-04-30 09:46:58 +00:00
case WSAECONNREFUSED:
case WSAENETUNREACH:
case WSAEHOSTUNREACH:
case WSAEHOSTDOWN:
return QSE_NWIO_ECONN;
2012-04-27 14:33:14 +00:00
default:
return QSE_NWIO_ESYSERR;
}
}
#elif defined(__OS2__)
static qse_nwio_errnum_t skerr_to_errnum (int e)
2012-04-27 14:33:14 +00:00
{
switch (e)
{
2012-12-18 08:12:15 +00:00
#if defined(SOCENOMEM)
2012-04-30 15:15:41 +00:00
case SOCENOMEM:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_ENOMEM;
2012-12-18 08:12:15 +00:00
#endif
2012-04-27 14:33:14 +00:00
2012-04-30 15:15:41 +00:00
case SOCEINVAL:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EINVAL;
2012-04-30 15:15:41 +00:00
case SOCEACCES:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EACCES;
2012-12-18 08:12:15 +00:00
#if defined(SOCENOENT)
2012-04-30 15:15:41 +00:00
case SOCENOENT:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_ENOENT;
2012-12-18 08:12:15 +00:00
#endif
2012-04-27 14:33:14 +00:00
2012-12-18 08:12:15 +00:00
#if defined(SOCEXIST)
2012-04-30 15:15:41 +00:00
case SOCEEXIST:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EEXIST;
2012-12-18 08:12:15 +00:00
#endif
2012-04-30 15:15:41 +00:00
case SOCEINTR:
return QSE_NWIO_EINTR;
2012-04-27 14:33:14 +00:00
2012-04-30 15:15:41 +00:00
case SOCEPIPE:
2012-04-27 14:33:14 +00:00
return QSE_NWIO_EPIPE;
2012-04-30 15:15:41 +00:00
case SOCECONNREFUSED:
case SOCENETUNREACH:
case SOCEHOSTUNREACH:
case SOCEHOSTDOWN:
return QSE_NWIO_ECONN;
2012-04-27 14:33:14 +00:00
default:
return QSE_NWIO_ESYSERR;
}
}
2012-04-30 15:15:41 +00:00
2012-04-27 14:33:14 +00:00
#else
static qse_nwio_errnum_t skerr_to_errnum (int e)
2012-04-27 14:33:14 +00:00
{
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;
2012-04-27 14:33:14 +00:00
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
2012-04-30 09:46:58 +00:00
#if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN)
2012-04-27 14:33:14 +00:00
#if defined(ECONNREFUSED)
case ECONNREFUSED:
#endif
#if defined(ENETUNREACH)
case ENETUNREACH:
2012-04-30 09:46:58 +00:00
#endif
#if defined(EHOSTUNREACH)
case EHOSTUNREACH:
#endif
#if defined(EHOSTDOWN)
case EHOSTDOWN:
2012-04-27 14:33:14 +00:00
#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
2012-04-27 14:33:14 +00:00
#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)
2012-07-28 14:43:59 +00:00
{
int xret;
2012-08-01 11:25:53 +00:00
#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)
2012-07-28 14:43:59 +00:00
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;
}
2012-07-28 14:43:59 +00:00
tv.tv_sec = tmout->sec;
tv.tv_usec = QSE_NSEC_TO_USEC (tmout->nsec);
2012-07-28 14:43:59 +00:00
xret = select (nwio->handle + 1, &fds[0], &fds[1], QSE_NULL, &tv);
2012-12-18 08:12:15 +00:00
#if defined(_WIN32)
if (xret == SOCKET_ERROR)
2012-12-18 08:12:15 +00:00
#else
if (xret <= -1)
#endif
2014-10-20 04:58:15 +00:00
{
2012-12-18 08:12:15 +00:00
#if defined(_WIN32)
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-12-18 08:12:15 +00:00
#elif defined(__OS2__)
nwio->errnum = skerr_to_errnum (sock_errno());
2014-10-20 04:58:15 +00:00
#else
nwio->errnum = skerr_to_errnum (errno);
2012-12-18 08:12:15 +00:00
#endif
return -1;
}
2012-08-01 11:25:53 +00:00
else if (xret == 0)
{
nwio->errnum = QSE_NWIO_ETMOUT;
return -1;
}
2012-12-18 08:12:15 +00:00
return 0;
#elif defined(__OS2__)
2012-08-01 11:25:53 +00:00
int count[2] = { 0, 0 };
long tmout_msecs;
2012-08-01 11:25:53 +00:00
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)
2014-10-20 04:58:15 +00:00
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-08-01 11:25:53 +00:00
return -1;
}
else if (xret == 0)
{
nwio->errnum = QSE_NWIO_ETMOUT;
return -1;
}
2012-12-18 08:12:15 +00:00
return 0;
2012-08-01 11:25:53 +00:00
2012-12-18 08:12:15 +00:00
#else
2012-08-01 11:25:53 +00:00
nwio->errnum = QSE_NWIO_ENOIMPL;
return -1;
2012-08-01 11:25:53 +00:00
#endif
2012-07-28 14:43:59 +00:00
}
2012-04-27 14:33:14 +00:00
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)
2012-04-27 14:33:14 +00:00
{
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)
2012-04-27 14:33:14 +00:00
{
QSE_MMGR_FREE (mmgr, nwio);
return QSE_NULL;
}
QSE_MEMSET (nwio + 1, 0, xtnsize);
2012-04-27 14:33:14 +00:00
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 */
}
2012-04-27 14:33:14 +00:00
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)
2012-04-27 14:33:14 +00:00
{
qse_skad_t addr;
2014-08-25 16:18:17 +00:00
qse_sck_len_t addrlen;
int family, type, tmp;
2012-04-27 14:33:14 +00:00
QSE_MEMSET (nwio, 0, QSE_SIZEOF(*nwio));
nwio->mmgr = mmgr;
nwio->flags = flags;
2012-04-30 15:15:41 +00:00
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);
2012-04-30 10:25:19 +00:00
if (tmp <= -1)
{
nwio->errnum = QSE_NWIO_EINVAL;
return -1;
}
addrlen = tmp;
2012-04-27 14:33:14 +00:00
#if defined(SOCK_STREAM) && defined(SOCK_DGRAM)
2012-04-29 15:26:44 +00:00
if (flags & QSE_NWIO_TCP) type = SOCK_STREAM;
else if (flags & QSE_NWIO_UDP) type = SOCK_DGRAM;
else
2012-05-01 01:36:18 +00:00
#endif
2012-04-29 15:26:44 +00:00
{
nwio->errnum = QSE_NWIO_EINVAL;
return -1;
}
family = qse_skadfamily (&addr);
2012-04-30 09:46:58 +00:00
#if defined(_WIN32)
nwio->handle = socket (family, type, 0);
if (nwio->handle == INVALID_SOCKET)
{
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
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));
}
2012-04-30 09:46:58 +00:00
if (flags & QSE_NWIO_PASSIVE)
{
qse_nwio_hnd_t handle;
if (flags & QSE_NWIO_REUSEADDR)
2012-05-01 15:02:31 +00:00
{
int optval = 1;
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
}
2012-04-30 09:46:58 +00:00
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) == SOCKET_ERROR)
{
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
goto oops;
}
if (flags & QSE_NWIO_TCP)
{
if (listen (nwio->handle, 10) == SOCKET_ERROR)
{
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
goto oops;
}
if (TMOUT_ENABLED(nwio->tmout.a) &&
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
2012-04-30 09:46:58 +00:00
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
if (handle == INVALID_SOCKET)
{
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
goto oops;
}
closesocket (nwio->handle);
nwio->handle = handle;
}
else if (flags & QSE_NWIO_UDP)
{
2012-04-30 15:15:41 +00:00
nwio->status |= STATUS_UDP_CONNECT;
2012-04-30 09:46:58 +00:00
}
}
else
{
int xret;
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
2012-04-30 09:46:58 +00:00
{
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;
}
2012-04-30 09:46:58 +00:00
}
}
#elif defined(__OS2__)
2012-04-30 15:15:41 +00:00
nwio->handle = socket (family, type, 0);
if (nwio->handle <= -1)
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
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));
}
2012-04-30 15:15:41 +00:00
if (flags & QSE_NWIO_PASSIVE)
{
qse_nwio_hnd_t handle;
if (flags & QSE_NWIO_REUSEADDR)
2012-05-01 15:02:31 +00:00
{
int optval = 1;
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
}
2012-04-30 15:15:41 +00:00
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
goto oops;
}
if (flags & QSE_NWIO_TCP)
{
if (listen (nwio->handle, 10) <= -1)
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
goto oops;
}
if (TMOUT_ENABLED(nwio->tmout.a) &&
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
2012-08-01 11:25:53 +00:00
2012-04-30 15:15:41 +00:00
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
if (handle <= -1)
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
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))
2012-04-30 15:15:41 +00:00
{
int noblk = 1;
2012-12-18 08:12:15 +00:00
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) ||
2012-12-18 08:12:15 +00:00
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;
}
2012-04-30 15:15:41 +00:00
}
}
2012-04-30 09:46:58 +00:00
#elif defined(__DOS__)
2014-10-20 04:58:15 +00:00
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;
}
}
}
}
2012-04-30 09:46:58 +00:00
#else
2012-07-02 14:21:40 +00:00
#if defined(SOCK_CLOEXEC)
nwio->handle = socket (family, type | SOCK_CLOEXEC, 0);
#else
2012-04-29 15:26:44 +00:00
nwio->handle = socket (family, type, 0);
2012-07-02 14:21:40 +00:00
#endif
2012-04-27 14:33:14 +00:00
if (nwio->handle <= -1)
{
nwio->errnum = skerr_to_errnum (errno);
2012-04-27 14:33:14 +00:00
goto oops;
}
2012-07-02 14:21:40 +00:00
#if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
2012-04-27 14:33:14 +00:00
{
int tmp = fcntl (nwio->handle, F_GETFD);
if (tmp >= 0) fcntl (nwio->handle, F_SETFD, tmp | FD_CLOEXEC);
}
2012-04-30 09:46:58 +00:00
#endif
2012-04-27 14:33:14 +00:00
if ((flags & QSE_NWIO_TCP) && (flags & QSE_NWIO_KEEPALIVE))
{
int optval = 1;
setsockopt (nwio->handle, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, QSE_SIZEOF(optval));
}
2012-04-29 15:26:44 +00:00
if (flags & QSE_NWIO_PASSIVE)
2012-04-27 14:33:14 +00:00
{
qse_nwio_hnd_t handle;
2012-05-01 15:02:31 +00:00
#if defined(SO_REUSEADDR)
if (flags & QSE_NWIO_REUSEADDR)
2012-05-01 15:02:31 +00:00
{
int optval = 1;
setsockopt (nwio->handle, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, QSE_SIZEOF(optval));
}
#endif
2012-04-29 15:26:44 +00:00
if (bind (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1)
2012-04-27 14:33:14 +00:00
{
nwio->errnum = skerr_to_errnum (errno);
2012-04-27 14:33:14 +00:00
goto oops;
}
2012-04-29 15:26:44 +00:00
if (flags & QSE_NWIO_TCP)
2012-04-27 14:33:14 +00:00
{
2012-04-29 15:26:44 +00:00
if (listen (nwio->handle, 10) <= -1)
{
nwio->errnum = skerr_to_errnum (errno);
2012-04-29 15:26:44 +00:00
goto oops;
}
if (TMOUT_ENABLED(nwio->tmout.a) &&
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) goto oops;
2012-07-28 14:43:59 +00:00
2012-04-29 15:26:44 +00:00
handle = accept (nwio->handle, (struct sockaddr*)&addr, &addrlen);
if (handle <= -1)
{
nwio->errnum = skerr_to_errnum (errno);
2012-04-29 15:26:44 +00:00
goto oops;
}
qse_close_sck (nwio->handle); /* close the listening socket */
nwio->handle = handle; /* set the handle to the accepted socket */
2012-04-29 15:26:44 +00:00
}
else if (flags & QSE_NWIO_UDP)
{
2012-04-30 15:15:41 +00:00
nwio->status |= STATUS_UDP_CONNECT;
2012-04-27 14:33:14 +00:00
}
}
else
{
int xret;
if (TMOUT_ENABLED(nwio->tmout.c) && (flags & QSE_NWIO_TCP))
2012-04-27 14:33:14 +00:00
{
int orgfl;
orgfl = fcntl (nwio->handle, F_GETFL, 0);
2014-10-20 04:58:15 +00:00
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
{
2014-08-25 16:18:17 +00:00
qse_sck_len_t xlen;
2012-07-28 14:43:59 +00:00
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)
2014-08-25 16:18:17 +00:00
{
nwio->errnum = skerr_to_errnum (errno);
goto oops;
}
2012-04-27 14:33:14 +00:00
}
}
#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);
2012-04-27 14:33:14 +00:00
return 0;
oops:
2012-04-30 09:46:58 +00:00
if (nwio->tio)
{
qse_tio_close (nwio->tio);
nwio->tio = QSE_NULL;
}
2012-04-27 14:33:14 +00:00
if (qse_is_sck_valid(nwio->handle)) qse_close_sck (nwio->handle);
2012-04-27 14:33:14 +00:00
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;
}
2012-04-30 09:46:58 +00:00
qse_close_sck (nwio->handle);
2012-04-27 14:33:14 +00:00
}
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);
}
2012-04-27 14:33:14 +00:00
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)
2012-04-27 14:33:14 +00:00
{
2012-04-30 09:46:58 +00:00
return nwio->handle;
2012-04-27 14:33:14 +00:00
}
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)
2012-04-27 14:33:14 +00:00
{
if (nwio->tio) qse_tio_drain (nwio->tio);
2012-04-27 14:33:14 +00:00
}
/* ---------------------------------------------------------- */
static qse_ssize_t nwio_read (qse_nwio_t* nwio, void* buf, qse_size_t size)
{
#if defined(_WIN32)
2012-04-30 09:46:58 +00:00
int count;
2012-04-27 14:33:14 +00:00
#elif defined(__OS2__)
2012-04-30 15:15:41 +00:00
int n;
2012-04-27 14:33:14 +00:00
#elif defined(__DOS__)
int n;
#else
qse_ssize_t n;
#endif
#if defined(_WIN32)
2012-04-30 09:46:58 +00:00
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(int);
2012-04-30 15:15:41 +00:00
if (nwio->status & STATUS_UDP_CONNECT)
2012-04-30 09:46:58 +00:00
{
qse_skad_t addr;
2012-04-30 09:46:58 +00:00
int addrlen;
addrlen = QSE_SIZEOF(addr);
if (TMOUT_ENABLED(nwio->tmout.a) &&
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
2012-04-30 09:46:58 +00:00
count = recvfrom (
nwio->handle, buf, size, 0,
(struct sockaddr*)&addr, &addrlen);
2012-04-30 15:15:41 +00:00
if (count == SOCKET_ERROR)
{
nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 15:15:41 +00:00
}
2012-04-30 09:46:58 +00:00
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;
2012-04-30 09:46:58 +00:00
}
2012-04-30 15:15:41 +00:00
nwio->status &= ~STATUS_UDP_CONNECT;
2012-04-30 09:46:58 +00:00
}
}
else
{
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
TMOUT_ENABLED(nwio->tmout.r) &&
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1) return -1;
2012-04-30 09:46:58 +00:00
count = recv (nwio->handle, buf, size, 0);
if (count == SOCKET_ERROR) nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
}
return count;
2012-04-27 14:33:14 +00:00
#elif defined(__OS2__)
2012-04-30 15:15:41 +00:00
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;
2012-04-30 15:15:41 +00:00
int addrlen;
addrlen = QSE_SIZEOF(addr);
2012-08-01 11:25:53 +00:00
if (TMOUT_ENABLED(nwio->tmout.a) &&
wait_for_data (nwio, &nwio->tmout.a, 0) <= -1) return -1;
2012-08-01 11:25:53 +00:00
2012-04-30 15:15:41 +00:00
n = recvfrom (
nwio->handle, buf, size, 0,
(struct sockaddr*)&addr, &addrlen);
if (n <= -1)
{
nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
}
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;
2012-04-30 15:15:41 +00:00
}
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;
2012-08-01 11:25:53 +00:00
2012-04-30 15:15:41 +00:00
n = recv (nwio->handle, buf, size, 0);
if (n <= -1) nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
}
return n;
2012-04-27 14:33:14 +00:00
#elif defined(USE_TLI)
2012-04-30 09:46:58 +00:00
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;
2012-04-30 09:46:58 +00:00
2012-04-27 14:33:14 +00:00
#else
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
2012-04-27 14:33:14 +00:00
reread:
2012-04-30 15:15:41 +00:00
if (nwio->status & STATUS_UDP_CONNECT)
2012-04-27 14:33:14 +00:00
{
qse_skad_t addr;
2014-08-25 16:18:17 +00:00
qse_sck_len_t addrlen;
2012-04-29 15:26:44 +00:00
addrlen = QSE_SIZEOF(addr);
2012-07-28 14:43:59 +00:00
/* 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;
2012-07-28 14:43:59 +00:00
2012-04-29 15:26:44 +00:00
n = recvfrom (
nwio->handle, buf, size, 0,
(struct sockaddr*)&addr, &addrlen);
if (n <= -1)
2012-04-27 14:33:14 +00:00
{
2012-04-29 15:26:44 +00:00
if (errno == EINTR)
{
if (nwio->flags & QSE_NWIO_READNORETRY)
nwio->errnum = QSE_NWIO_EINTR;
else goto reread;
}
else
{
nwio->errnum = skerr_to_errnum (errno);
2012-04-29 15:26:44 +00:00
}
2012-04-27 14:33:14 +00:00
}
2012-04-29 15:26:44 +00:00
else if (n >= 1)
2012-04-27 14:33:14 +00:00
{
2012-04-29 15:26:44 +00:00
/* 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;
2012-04-29 15:26:44 +00:00
}
2012-04-30 15:15:41 +00:00
nwio->status &= ~STATUS_UDP_CONNECT;
2012-04-29 15:26:44 +00:00
}
}
else
{
if (!(nwio->status & STATUS_TMOUT_R_PRESET) &&
TMOUT_ENABLED(nwio->tmout.r) &&
wait_for_data (nwio, &nwio->tmout.r, 0) <= -1) return -1;
2012-04-29 15:26:44 +00:00
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);
2012-04-29 15:26:44 +00:00
}
2012-04-27 14:33:14 +00:00
}
}
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)
2012-04-30 09:46:58 +00:00
int count;
2012-04-27 14:33:14 +00:00
#elif defined(__OS2__)
2012-04-30 15:15:41 +00:00
int n;
2012-04-27 14:33:14 +00:00
#elif defined(__DOS__)
int n;
#else
qse_ssize_t n;
#endif
#if defined(_WIN32)
2012-04-30 09:46:58 +00:00
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;
2012-04-30 09:46:58 +00:00
count = send (nwio->handle, data, size, 0);
if (count == SOCKET_ERROR) nwio->errnum = skerr_to_errnum (WSAGetLastError());
2012-04-30 09:46:58 +00:00
return count;
2012-04-27 14:33:14 +00:00
#elif defined(__OS2__)
2012-04-30 15:15:41 +00:00
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;
2012-08-01 11:25:53 +00:00
2012-04-30 15:15:41 +00:00
n = send (nwio->handle, data, size, 0);
if (n <= -1) nwio->errnum = skerr_to_errnum (sock_errno());
2012-04-30 15:15:41 +00:00
return n;
2012-04-27 14:33:14 +00:00
#elif defined(USE_TLI)
2012-04-27 14:33:14 +00:00
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;
2012-04-27 14:33:14 +00:00
#else
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
2012-04-27 14:33:14 +00:00
rewrite:
if (!(nwio->status & STATUS_TMOUT_W_PRESET) &&
TMOUT_ENABLED(nwio->tmout.w) &&
wait_for_data (nwio, &nwio->tmout.w, 1) <= -1) return -1;
2012-07-28 14:43:59 +00:00
2012-04-27 14:33:14 +00:00
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);
2012-04-27 14:33:14 +00:00
}
}
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)
2012-07-28 14:43:59 +00:00
{
return nwio_write(nwio, data, size);
2012-07-28 14:43:59 +00:00
}
2012-04-27 14:33:14 +00:00
else
{
qse_ssize_t n;
nwio->errnum = QSE_NWIO_ENOERR;
n = qse_tio_write(nwio->tio, data, size);
2012-04-27 14:33:14 +00:00
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);
}
2012-04-27 14:33:14 +00:00
/* ---------------------------------------------------------- */
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;
}