qse/lib/si/sck.c

488 lines
10 KiB
C
Raw Normal View History

2014-08-25 16:18:17 +00:00
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
2014-08-25 16:18:17 +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.
2014-08-25 16:18:17 +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.
2014-08-25 16:18:17 +00:00
*/
2016-04-28 15:57:20 +00:00
#include <qse/si/sck.h>
2014-08-25 16:18:17 +00:00
#if defined(_WIN32)
# include <winsock2.h>
# include <ws2tcpip.h> /* sockaddr_in6 */
# include <windows.h>
#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__)
2014-10-20 04:58:15 +00:00
# include <tcp.h> /* watt-32 */
#elif defined(HAVE_T_CONNECT) && !defined(HAVE_CONNECT) && defined(HAVE_TIUSER_H)
2016-04-28 15:57:20 +00:00
# include "../cmn/syscall.h"
# include <tiuser.h>
# define USE_TLI
2014-08-25 16:18:17 +00:00
#else
2016-04-28 15:57:20 +00:00
# include "../cmn/syscall.h"
2014-08-25 16:18:17 +00:00
# include <sys/socket.h>
# include <netinet/in.h>
# if defined(HAVE_NETINET_TCP_H)
# include <netinet/tcp.h>
# endif
2014-08-25 16:18:17 +00:00
# if defined(HAVE_NETINET_SCTP_H)
# include <netinet/sctp.h>
# endif
#endif
#if !defined(SHUT_RD)
# define SHUT_RD 0
#endif
#if !defined(SHUT_WR)
# define SHUT_WR 1
#endif
2014-09-02 15:41:12 +00:00
#if !defined(SHUT_RDWR)
# define SHUT_RDWR 2
#endif
QSE_INLINE int qse_is_sck_valid (qse_sck_hnd_t handle)
2014-08-25 16:18:17 +00:00
{
#if defined(_WIN32)
return handle != QSE_INVALID_SCKHND;
#elif defined(__OS2__)
return handle >= 0;
#elif defined(__DOS__)
return handle >= 0;
2014-10-20 04:58:15 +00:00
#elif defined(USE_TLI)
2014-10-20 04:58:15 +00:00
return handle >= 0;
2014-08-25 16:18:17 +00:00
#else
return handle >= 0;
#endif
}
qse_sck_hnd_t qse_open_sck (int family, int type, int protocol, int traits)
{
int x;
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
if (traits & QSE_SCK_TRAIT_NONBLOCK) type |= SOCK_NONBLOCK;
if (traits & QSE_SCK_TRAIT_CLOEXEC) type |= SOCK_CLOEXEC;
open_socket:
#endif
x = socket(family, type, protocol);
if (x == -1)
{
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
if (errno == EINVAL && (type & (SOCK_NONBLOCK | SOCK_CLOEXEC)))
{
type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
goto open_socket;
}
#endif
return -1;
}
else
{
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
if (type & (SOCK_NONBLOCK | SOCK_CLOEXEC)) goto done;
#endif
}
if (traits)
{
if (((traits & QSE_SCK_TRAIT_CLOEXEC) && qse_set_sck_cloexec(x, 1) <= -1) ||
((traits & QSE_SCK_TRAIT_NONBLOCK) && qse_set_sck_nonblock(x, 1) <= -1))
{
close (x);
return -1;
}
}
done:
return x;
}
QSE_INLINE void qse_close_sck (qse_sck_hnd_t handle)
2014-08-25 16:18:17 +00:00
{
#if defined(_WIN32)
closesocket (handle);
2014-08-25 16:18:17 +00:00
#elif defined(__OS2__)
soclose (handle);
2014-08-25 16:18:17 +00:00
#elif defined(__DOS__)
2014-10-20 04:58:15 +00:00
close_s (handle);
#elif defined(USE_TLI)
t_close (handle);
2014-08-25 16:18:17 +00:00
#else
close (handle);
2014-08-25 16:18:17 +00:00
#endif
}
QSE_INLINE void qse_shut_sck (qse_sck_hnd_t handle, qse_shut_sck_how_t how)
2014-09-02 15:41:12 +00:00
{
static int how_v[] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
#if defined(_WIN32)
shutdown (handle, how_v[how]);
2014-09-02 15:41:12 +00:00
#elif defined(__OS2__)
shutdown (handle, how_v[how]);
2014-09-02 15:41:12 +00:00
#elif defined(__DOS__)
2014-10-20 04:58:15 +00:00
shutdown (handle, how_v[how]);
#elif defined(USE_TLI)
/* Is this correct? */
switch (how)
{
case QSE_SHUT_SCK_R:
t_rcvrel (handle);
break;
case QSE_SHUT_SCK_W:
t_sndrel (handle);
break;
case QSE_SHUT_SCK_RW:
t_rcvrel (handle);
t_sndrel (handle);
break;
}
2014-09-02 15:41:12 +00:00
#else
shutdown (handle, how_v[how]);
#endif
}
int qse_set_sck_nonblock (qse_sck_hnd_t handle, int enabled)
{
#if defined(_WIN32)
if (ioctlsocket (handle, FIONBIO, &enabled) == SOCKET_ERROR) return -1;
return 0;
#elif defined(__OS2__)
if (ioctl (handle, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1) return -1;
return 0;
#elif defined(__DOS__)
if (ioctlsocket (handle, FIONBIO, (char*)&enabled) == SOCKET_ERROR) return -1;
return 0;
#elif defined(O_NONBLOCK)
int flag = fcntl(handle, F_GETFL);
if (flag >= 0) flag = fcntl(handle, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK)));
if (flag <= -1) return -1;
return 0;
#else
return -1;
#endif
}
int qse_set_sck_cloexec (qse_sck_hnd_t handle, int enabled)
{
#if defined(_WIN32)
return -1;
#elif defined(__OS2__)
return -1;
#elif defined(__DOS__)
return -1;
#elif defined(FD_CLOEXEC)
int flag = fcntl(handle, F_GETFD);
if (flag >= 0) flag = fcntl(handle, F_SETFD, (enabled? (flag | FD_CLOEXEC): (flag & ~FD_CLOEXEC)));
if (flag <= -1) return -1;
return 0;
#else
return -1;
#endif
}
int qse_init_sck_conn (qse_sck_hnd_t handle, const qse_skad_t* skad)
{
int n;
#if defined(_WIN32)
unsigned long cmd;
2016-04-28 14:33:10 +00:00
#elif defined(__OS2__)
int enabled;
#else
int saved = 0;
#endif
#if defined(_WIN32)
/* switch to the non-blocking mode */
cmd = 1;
if (ioctlsocket(handle, FIONBIO, &cmd) == SOCKET_ERROR)
{
/* error code in WSAGetLastError() */
return -1;
}
/* attempt to connet */
n = connect(handle, (struct sockaddr*)skad, qse_skadsize(skad));
if (n == -1 && WSAGetLastError() != WSAEWOULDBLOCK)
{
2016-04-28 14:33:10 +00:00
/* attempt to restore to the blocking mode upon failure.
* there is no guarantee that this was the previous mode. */
cmd = 0;
ioctlsocket (handle, FIONBIO, &cmd);
return -1;
}
2016-04-28 14:33:10 +00:00
#elif defined(__OS2__)
enabled = 1;
if (ioctl(handle, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1) return -1;
2016-04-28 14:33:10 +00:00
/* attempt to connet */
n = connect (handle, (struct sockaddr*)skad, qse_skadsize(skad));
2016-04-28 14:33:10 +00:00
if (n == -1 && sock_errno() != EINPROGRESS)
{
/* attempt to restore to the blocking mode upon failure.
* there is no guarantee that this was the previous mode. */
enabled = 0;
ioctl (handle, FIONBIO, (char*)&enabled, sizeof(enabled));
return -1;
}
#else
2016-04-28 14:33:10 +00:00
/* switch to the non-blocking mode if necessary */
saved = fcntl (handle, F_GETFL, 0);
if (saved == -1) return -1;
if (!(saved & O_NONBLOCK) && fcntl(handle, F_SETFL, saved | O_NONBLOCK) == -1) return -1;
/* attempt to connet */
do
{
n = connect(handle, (struct sockaddr*)skad, qse_skadsize(skad));
}
while (n == -1 && errno == EINTR);
if (n == -1 && errno != EINPROGRESS)
{
if (!(saved & O_NONBLOCK)) fcntl (handle, F_SETFL, saved); /* restore the flags upon failure */
return -1;
}
#endif
/* the socket still remains in the non-blocking mode */
return (n == 0)? 1: 0; /* 1: connected, 0: in progress */
}
int qse_fini_sck_conn (qse_sck_hnd_t handle)
{
int ret;
qse_sck_len_t len;
len = (qse_sck_len_t)QSE_SIZEOF (ret);
if (getsockopt (handle, SOL_SOCKET, SO_ERROR, (char*)&ret, &len) == -1) return -1;
2016-04-28 14:33:10 +00:00
#if defined(_WIN32)
if (ret == WSAETIMEDOUT)
#else
if (ret == ETIMEDOUT)
#endif
{
return -1; /* failure - timed out */
}
2016-04-28 14:33:10 +00:00
#if defined(_WIN32)
else if (ret == WSAEWOULDBLOCK)
#else
else if (ret == EINPROGRESS)
#endif
{
return 0; /* in progress */
}
else if (ret != 0)
{
2020-09-06 18:17:32 +00:00
errno = ret;
return -1; /* failure */
}
return 1; /* connected */
}
2014-09-02 15:41:12 +00:00
2022-01-31 12:50:52 +00:00
int qse_set_sck_keepalive (qse_sck_hnd_t handle, int enabled, int tcp_keepidle, int tcp_keepintvl, int tcp_keepcnt)
{
if (setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&enabled, QSE_SIZEOF(enabled)) <= -1) return -1;
// the following values are just hints.
// i don't care about success and failure
#if defined(TCP_KEEPIDLE) && defined(SOL_TCP)
if (tcp_keepidle > 0) setsockopt (handle, SOL_TCP, TCP_KEEPIDLE, (char*)&tcp_keepidle, QSE_SIZEOF(tcp_keepidle));
#endif
#if defined(TCP_KEEPINTVL) && defined(SOL_TCP)
if (tcp_keepintvl > 0) setsockopt (handle, SOL_TCP, TCP_KEEPINTVL, (char*)&tcp_keepintvl, QSE_SIZEOF(tcp_keepintvl));
#endif
#if defined(TCP_KEEPCNT) && defined(SOL_TCP)
if (tcp_keepcnt > 0) setsockopt (handle, SOL_TCP, TCP_KEEPCNT, (char*)&tcp_keepcnt, QSE_SIZEOF(tcp_keepcnt));
#endif
return 0;
}
2014-08-25 16:18:17 +00:00
#if 0
qse_sck_hnd_t
int qse_sck_open (qse_mmgr_t* mmgr, qse_sck_type_t type)
{
}
void qse_sck_close (qse_sck_t* sck)
{
}
int qse_sck_init (qse_sck_t* sck, qse_mmgr_t* mmgr, qse_sck_type_t type)
{
int domain, type, proto = 0;
switch (type)
{
case QSE_SCK_TCP4:
domain = AF_INET;
type = SOCK_STREAM;
break;
case QSE_SCK_TCP6:
domain = AF_INET6;
type = SOCK_STREAM;
break;
case QSE_SCK_UDP4:
domain = AF_INET;
type = SOCK_DGRAM;
break;
case QSE_SCK_UDP6:
domain = AF_INET6;
type = SOCK_DGRAM;
break;
case QSE_SCK_SCTP4:
domain = AF_INET;
type = SCOK_SEQPACKET;
proto = IPPROTO_SCTP;
break;
case QSE_SCK_SCTP6:
domain = AF_INET6;
type = SCOK_SEQPACKET;
proto = IPPROTO_SCTP;
break;
case QSE_SCK_SCTP4:
domain = AF_INET;
type = SCOK_STREAM;
proto = IPPROTO_SCTP;
break;
case QSE_SCK_SCTP6:
domain = AF_INET6;
type = SCOK_STREAM;
proto = IPPROTO_SCTP;
break;
#if 0
case QSE_SCK_RAW4:
domain = AF_INET;
type = SOCK_RAW;
break;
case QSE_SCK_RAW6:
domain = AF_INET6;
type = SOCK_RAW;
break;
case QSE_SCK_PACKET:
domain = AF_PACKET;
type = SOCK_RAW;
proto = qse_hton16(ETH_P_ALL);
break;
case QSE_SCK_PACKET:
domain = AF_PACKET;
type = SOCK_DGRAM; /* cooked packet with the link level header removed */
proto = qse_hton16(ETH_P_ALL);
break;
case QSE_SCK_ARP:
domain = AF_PACKET;
type = SOCK_RAW;
proto = qse_hton16(ETH_P_ARP);
proto =
#endif
}
sck->handle = socket (domain, type, proto);
}
void qse_sck_fini (qse_sck_t* sck)
{
#if defined(_WIN32)
closesocket (sck->handle);
#elif defined(__OS2__)
soclose (sck->handle);
#elif defined(__DOS__)
2014-10-20 04:58:15 +00:00
close_s (sck->handle)
2014-08-25 16:18:17 +00:00
#else
close (sck->handle);
2014-08-25 16:18:17 +00:00
#endif
}
qse_ssize_t qse_recvsocket ()
qse_ssize_t recvfromsocket ()
qse_ssize_t sendsocket ()
qse_ssize_t sendtosocket ()
#endif