IPv6 project is started.

1. Remove thread lock in select loop.
2. Nonblocking will be used in select loop for good performance.
3. Connection mode for UDP socket & SCTP(SEQPACKET)

More test is needed.
This commit is contained in:
Sukchan Lee 2017-11-15 22:59:30 +09:00
parent 90a50d999d
commit 068d049a9f
14 changed files with 1004 additions and 5 deletions

View File

@ -0,0 +1,44 @@
#ifndef __CORE_ARCH_SOCK_H__
#define __CORE_ARCH_SOCK_H__
#include "core_list.h"
#include "core_index.h"
#include "core_sock.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct _sock_t {
lnode_t node;
index_t index;
int family;
int type;
int protocol;
int flags;
int fd;
sock_handler handler;
void *data;
c_int32_t options;
} sock_t;
#define sock_is_option_set(skt, option) \
(((skt)->options & (option)) == (option))
#define sock_set_option(skt, option, on) \
do { \
if (on) \
(skt)->options |= (option); \
else \
(skt)->options &= ~(option); \
} while (0)
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -22,6 +22,7 @@
#define __CORE_PORTABLE_H__
#include "core_thread.h"
#include "core_sock.h"
#ifdef __cplusplus
extern "C" {
@ -30,6 +31,7 @@ extern "C" {
typedef int os_file_t; /**< native file */
typedef pthread_t os_thread_t; /**< native thread */
typedef pid_t os_proc_t; /**< native pid */
typedef int os_sock_t; /**< native socket */
/**
* convert the thread to os specific type from core type.
@ -43,6 +45,14 @@ CORE_DECLARE(status_t) os_thread_get(os_thread_t **thethd, thread_id id);
*/
CORE_DECLARE(os_thread_t) os_thread_current(void);
/**
* Convert the socket from an core type to an OS specific socket
* @param thesock The socket to convert.
* @param sock The os specific equivalent of the core socket..
*/
CORE_DECLARE(status_t) os_sock_get(os_sock_t *thesock, sock_id id);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,115 @@
#ifndef __CORE_SOCK_H__
#define __CORE_SOCK_H__
#include "core_errno.h"
#include "core_time.h"
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define SOCK_F_BIND (1 << 0)
#define SOCK_F_CONNECT (1 << 1)
#define SOCK_NTOP(__aDDR, __bUF) \
__aDDR ? \
((struct sockaddr_in *)__aDDR)->sin_family == AF_INET ? \
inet_ntop(AF_INET, &(((struct sockaddr_in *)__aDDR)->sin_addr), \
__bUF, INET_ADDRSTRLEN) : \
((struct sockaddr_in6 *)__aDDR)->sin6_family == AF_INET6 ? \
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)__aDDR)->sin6_addr), \
__bUF, INET6_ADDRSTRLEN) : "Unknown Family" : \
"Null Address"
/**
* @defgroup core_sockopt Socket option definitions
* @{
*/
#define CORE_SO_LINGER 1 /**< Linger */
#define CORE_SO_KEEPALIVE 2 /**< Keepalive */
#define CORE_SO_DEBUG 4 /**< Debug */
#define CORE_SO_NONBLOCK 8 /**< Non-blocking IO */
#define CORE_SO_REUSEADDR 16 /**< Reuse addresses */
#define CORE_SO_SNDBUF 64 /**< Send buffer */
#define CORE_SO_RCVBUF 128 /**< Receive buffer */
#define CORE_SO_DISCONNECTED 256 /**< Disconnected */
#define CORE_TCP_NODELAY 512 /**< For SCTP sockets, this is mapped
* to STCP_NODELAY internally.
*/
#define CORE_TCP_NOPUSH 1024 /**< No push */
#define CORE_RESET_NODELAY 2048 /**< This flag is ONLY set internally
* when we set CORE_TCP_NOPUSH with
* CORE_TCP_NODELAY set to tell us that
* CORE_TCP_NODELAY should be turned on
* again when NOPUSH is turned off
*/
#define CORE_INCOMPLETE_READ 4096 /**< Set on non-blocking sockets
* (timeout != 0) on which the
* previous read() did not fill a buffer
* completely. the next apr_socket_recv()
* will first call select()/poll() rather than
* going straight into read(). (Can also
* be set by an application to force a
* select()/poll() call before the next
* read, in cases where the app expects
* that an immediate read would fail.)
*/
#define CORE_INCOMPLETE_WRITE 8192 /**< like CORE_INCOMPLETE_READ, but for write
* @see CORE_INCOMPLETE_READ
*/
#define CORE_IPV6_V6ONLY 16384 /**< Don't accept IPv4 connections on an
* IPv6 listening socket.
*/
#define CORE_TCP_DEFER_ACCEPT 32768 /**< Delay accepting of new connections
* until data is available.
* @see apr_socket_accept_filter
*/
#define CORE_SO_BROADCAST 65536 /**< Allow broadcast
*/
#define CORE_SO_FREEBIND 131072 /**< Allow binding to addresses not owned
* by any interface
*/
typedef c_uintptr_t sock_id;
typedef int (*sock_handler)(sock_id sock, void *data);
CORE_DECLARE(status_t) sock_init(void);
CORE_DECLARE(status_t) sock_final(void);
CORE_DECLARE(status_t) sock_create(
sock_id *id, int family, int type, int protocol, int flags);
CORE_DECLARE(status_t) sock_delete(sock_id id);
CORE_DECLARE(status_t) sock_opt_set(sock_id id, c_int32_t opt, c_int32_t on);
CORE_DECLARE(status_t) sock_bind(sock_id id,
const char *host, c_uint16_t port);
CORE_DECLARE(status_t) sock_connect(sock_id id,
const char *host, c_uint16_t port);
CORE_DECLARE(status_t) sock_listen(sock_id id);
CORE_DECLARE(status_t) sock_accept(sock_id *new, sock_id id);
CORE_DECLARE(ssize_t) sock_send(sock_id id,
const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
CORE_DECLARE(ssize_t) sock_recv(sock_id id,
void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
CORE_DECLARE(status_t) sock_register(sock_id id,
sock_handler handler, void *data);
CORE_DECLARE(status_t) sock_unregister(sock_id id);
CORE_DECLARE(int) sock_is_registered(sock_id id);
CORE_DECLARE(int) sock_select_loop(c_time_t timeout);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -0,0 +1,20 @@
#ifndef __CORE_TCP_H__
#define __CORE_TCP_H__
#include "core_sock.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
CORE_DECLARE(status_t) tcp_create(sock_id *new,
int family,
const char *local_host, c_uint16_t local_port,
const char *remote_host, c_uint16_t remote_port,
int flags);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -0,0 +1,20 @@
#ifndef __CORE_UDP_H__
#define __CORE_UDP_H__
#include "core_sock.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
CORE_DECLARE(status_t) udp_create(sock_id *new,
int family,
const char *local_host, c_uint16_t local_port,
const char *remote_host, c_uint16_t remote_port,
int flags);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -16,6 +16,7 @@ libcore_la_SOURCES = \
../include/core_timer.h ../include/core_tlv.h ../include/core_tlv_msg.h \
../include/core_atomic.h ../include/core_portable.h \
../include/core_version.h ../include/core_event.h ../include/core_hash.h \
../include/core_sock.h ../include/core_udp.h ../include/core_tcp.h \
\
debug.c version.c fsm.c msgq.c ringbuf.c timer.c tlv.c tlv_msg.c hash.c \
aes.c aes_cmac.c sha1.c sha1_hmac.c sha2.c sha2_hmac.c misc.c event.c \
@ -28,17 +29,23 @@ libcore_la_SOURCES = \
unix/start.c unix/errorcodes.c unix/pkbuf.c \
unix/rand.c unix/time.c unix/file.c unix/net_lib.c \
unix/thread.c unix/signal.c \
unix/atomic.c unix/cond.c unix/mutex.c unix/rwlock.c unix/semaphore.c
unix/atomic.c unix/cond.c unix/mutex.c unix/rwlock.c unix/semaphore.c \
unix/sock.c unix/udp.c unix/tcp.c \
$(NULL)
AM_LDFLAGS = \
-version-info @LIBVERSION@
-version-info @LIBVERSION@ \
$(NULL)
AM_CPPFLAGS = \
-I$(top_srcdir)/lib/core/include/arch/@OSDIR@ \
-I$(top_srcdir)/lib/core/include
-I$(top_srcdir)/lib/core/include \
$(NULL)
AM_CFLAGS = \
-Wall -Werror @OSCPPFLAGS@
-Wall -Werror \
@OSCPPFLAGS@ \
$(NULL)
MAINTAINERCLEANFILES = Makefile.in
MOSTLYCLEANFILES = core *.stackdump

550
lib/core/src/unix/sock.c Normal file
View File

@ -0,0 +1,550 @@
#define TRACE_MODULE _sock
#include "core_debug.h"
#include "core_arch_sock.h"
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#define MAX_SOCK_POOL_SIZE 512
static int max_fd;
static list_t fd_list;
static fd_set read_fds;
index_declare(sock_pool, sock_t, MAX_SOCK_POOL_SIZE);
static status_t sononblock(int sd);
static status_t soblock(int sd);
static struct addrinfo *resolver(
int family, int type, int protocol,
const char *host, c_uint16_t port, int flags);
static void set_fds(fd_set *fds);
static void fd_dispatch(fd_set *fds);
status_t sock_init(void)
{
index_init(&sock_pool, MAX_SOCK_POOL_SIZE);
max_fd = 0;
list_init(&fd_list);
memset(&read_fds, 0, sizeof(struct fd_set));
return CORE_OK;
}
status_t sock_final(void)
{
index_final(&sock_pool);
return CORE_OK;
}
status_t sock_create(sock_id *new,
int family, int type, int protocol, int flags)
{
sock_t *sock = NULL;
index_alloc(&sock_pool, &sock);
d_assert(sock, return CORE_ENOMEM,);
memset(sock, 0, sizeof(sock_t));
sock->family = family;
sock->type = type;
sock->protocol = protocol;
sock->flags = flags;
sock->fd = -1;
if (!flags)
{
sock->fd = socket(sock->family, sock->type, sock->protocol);
if (sock->fd < 0)
{
d_error("socket create(%d:%d:%d) failed(%d:%s)",
sock->family, sock->type, sock->protocol,
errno, strerror(errno));
return CORE_ERROR;
}
d_trace(1, "socket create(%d:%d:%d)\n",
sock->family, sock->type, sock->protocol);
}
*new = (sock_id)sock;
return CORE_OK;
}
status_t sock_delete(sock_id id)
{
sock_t *sock = (sock_t *)id;
d_assert(id, return CORE_ERROR,);
if (sock_is_registered(id))
sock_unregister(id);
if (sock->fd >= 0)
close(sock->fd);
sock->fd = -1;
index_free(&sock_pool, sock);
return CORE_OK;
}
status_t sock_opt_set(sock_id id, c_int32_t opt, c_int32_t on)
{
sock_t *sock = (sock_t *)id;
int one;
status_t rv;
d_assert(sock, return CORE_ERROR,);
if (on)
one = 1;
else
one = 0;
switch(opt)
{
case CORE_SO_REUSEADDR:
if (on != sock_is_option_set(sock, CORE_SO_REUSEADDR))
{
if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR,
(void *)&one, sizeof(int)) == -1)
{
return errno;
}
sock_set_option(sock, CORE_SO_REUSEADDR, on);
}
break;
case CORE_SO_NONBLOCK:
if (sock_is_option_set(sock, CORE_SO_NONBLOCK) != on)
{
if (on)
{
if ((rv = sononblock(sock->fd)) != CORE_OK)
return rv;
}
else
{
if ((rv = soblock(sock->fd)) != CORE_OK)
return rv;
}
sock_set_option(sock, CORE_SO_NONBLOCK, on);
}
break;
default:
d_error("Not implemented(%d)", opt);
return CORE_EINVAL;
}
return CORE_OK;
}
status_t sock_bind(sock_id id, const char *host, c_uint16_t port)
{
sock_t *sock = (sock_t *)id;
struct addrinfo *result, *rp;
char buf[INET6_ADDRSTRLEN];
d_assert(sock, return CORE_ERROR,);
d_assert(sock->flags & SOCK_F_BIND, return CORE_ERROR,);
result = resolver(
sock->family, sock->type, sock->protocol, host, port, AI_PASSIVE);
d_assert(result, return CORE_ERROR,);
for (rp = result; rp != NULL; rp = rp->ai_next)
{
sock->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock->fd < 0)
continue;
if (sock_opt_set(id, CORE_SO_REUSEADDR, 1) == CORE_ERROR)
{
d_error("setsockopt(%s:%d) failed(%d:%s)",
host, port, errno, strerror(errno));
break;
}
if (bind(sock->fd, rp->ai_addr, rp->ai_addrlen) == 0)
{
d_trace(1, "socket bind %s:%d\n",
SOCK_NTOP(rp->ai_addr, buf), port);
break;
}
close(sock->fd);
sock->fd = -1;
}
freeaddrinfo(result);
if (rp == NULL)
{
d_error("socket bind(%d:%d) failed(%d:%s)",
host, port, errno, strerror(errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t sock_connect(sock_id id, const char *host, c_uint16_t port)
{
sock_t *sock = (sock_t *)id;
int rc;
struct addrinfo *result, *rp;
char buf[INET6_ADDRSTRLEN];
d_assert(id, return CORE_ERROR,);
d_assert(sock->flags & SOCK_F_CONNECT, return CORE_ERROR,);
result = resolver(
sock->family, sock->type, sock->protocol, host, port, 0);
d_assert(result, return CORE_ERROR,);
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if (sock->fd < 0)
{
sock->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock->fd < 0)
continue;
}
rc = connect(sock->fd, rp->ai_addr, rp->ai_addrlen);
if (rc == 0 || (rc != 0 && errno == EINPROGRESS))
{
d_trace(1, "socket connect %s:%d\n",
SOCK_NTOP(rp->ai_addr, buf), port);
break;
}
close(sock->fd);
sock->fd = -1;
}
freeaddrinfo(result);
if (rp == NULL)
{
d_error("connect(%d:%d) failed(%d:%s)",
host, port, errno, strerror(errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t sock_listen(sock_id id)
{
int rc;
sock_t *sock = (sock_t *)id;
d_assert(sock, return CORE_ERROR,);
rc = listen(sock->fd, 5);
if (rc < 0)
{
d_error("listen failed(%d:%s)", errno, strerror(errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t sock_accept(sock_id *new, sock_id id)
{
sock_t *sock = (sock_t *)id;
status_t rv;
sock_t *remote_sock = NULL;
int remote_fd = -1;
d_assert(id, return CORE_ERROR,);
d_assert(sock->flags & SOCK_F_BIND, return CORE_ERROR,);
remote_fd = accept(sock->fd, NULL, NULL);
if (remote_fd < 0)
{
d_error("accept failed(%d:%s)", errno, strerror(errno));
return CORE_ERROR;
}
rv = sock_create(new,
sock->family, sock->type, sock->protocol, sock->flags);
d_assert(rv == CORE_OK && (*new), return CORE_ERROR,);
remote_sock = (sock_t *)(*new);
remote_sock->fd = remote_fd;
remote_sock->flags = SOCK_F_CONNECT;
return CORE_OK;
}
ssize_t sock_send(sock_id id, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
sock_t *sock = (sock_t *)id;
ssize_t size;
d_assert(id, return -1, );
if (sock->flags & SOCK_F_CONNECT)
{
size = send(sock->fd, buf, len, flags);
}
else
{
d_assert(dest_addr, return -1,);
d_assert(addrlen, return -1,);
size = sendto(sock->fd, buf, len, flags, dest_addr, addrlen);
}
if (size < 0)
{
d_error("send(len:%ld) failed(%d:%s)", len, errno, strerror(errno));
}
return size;
}
ssize_t sock_recv(sock_id id, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
sock_t *sock = (sock_t *)id;
ssize_t size;
d_assert(id, return -1,);
if (sock->flags & SOCK_F_CONNECT)
{
size = recv(sock->fd, buf, len, flags);
}
else
{
size = recvfrom(sock->fd, buf, len, flags, src_addr, addrlen);
}
if (size < 0)
{
d_error("recv(len:%ld) failed(%d:%s)", len, errno, strerror(errno));
}
return size;
}
status_t sock_register(sock_id id, sock_handler handler, void *data)
{
sock_t *sock = (sock_t *)id;
d_assert(id, return CORE_ERROR,);
if (sock_is_registered(id))
{
d_error("socket has already been registered");
return CORE_ERROR;
}
if (sock_opt_set(id, CORE_SO_NONBLOCK, 1) == CORE_ERROR)
{
d_error("cannot set socket to non-block");
return CORE_ERROR;
}
if (sock->fd > max_fd)
{
max_fd = sock->fd;
}
sock->handler = handler;
sock->data = data;
list_append(&fd_list, sock);
return CORE_OK;
}
status_t sock_unregister(sock_id id)
{
d_assert(id, return CORE_ERROR,);
list_remove(&fd_list, id);
return CORE_OK;
}
int sock_is_registered(sock_id id)
{
sock_t *sock = (sock_t *)id;
sock_t *iter = NULL;
d_assert(id, return CORE_ERROR,);
for (iter = list_first(&fd_list); iter != NULL; iter = list_next(iter))
{
if (iter->index == sock->index)
{
return 1;
}
}
return 0;
}
int sock_select_loop(c_time_t timeout)
{
struct timeval tv;
int rc;
if (timeout > 0)
{
tv.tv_sec = time_sec(timeout);
tv.tv_usec = time_usec(timeout);
}
set_fds(&read_fds);
rc = select(max_fd + 1, &read_fds, NULL, NULL, timeout > 0 ? &tv : NULL);
if (rc < 0)
{
if (errno != EINTR && errno != 0)
{
if (errno == EBADF)
{
d_error("[FIXME] socket should be closed here(%d:%s)",
errno, strerror(errno));
}
else
{
d_error("select failed(%d:%s)", errno, strerror(errno));
}
}
return rc;
}
/* Timeout */
if (rc == 0)
{
return rc;
}
/* Dispatch Handler */
fd_dispatch(&read_fds);
return 0;
}
static status_t soblock(int sd)
{
/* BeOS uses setsockopt at present for non blocking... */
#ifndef BEOS
int fd_flags;
fd_flags = fcntl(sd, F_GETFL, 0);
#if defined(O_NONBLOCK)
fd_flags &= ~O_NONBLOCK;
#elif defined(O_NDELAY)
fd_flags &= ~O_NDELAY;
#elif defined(FNDELAY)
fd_flags &= ~FNDELAY;
#else
#error Please teach CORE how to make sockets blocking on your platform.
#endif
if (fcntl(sd, F_SETFL, fd_flags) == -1)
{
return errno;
}
#else
int on = 0;
if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
return errno;
#endif /* BEOS */
return CORE_OK;
}
static status_t sononblock(int sd)
{
#ifndef BEOS
int fd_flags;
fd_flags = fcntl(sd, F_GETFL, 0);
#if defined(O_NONBLOCK)
fd_flags |= O_NONBLOCK;
#elif defined(O_NDELAY)
fd_flags |= O_NDELAY;
#elif defined(FNDELAY)
fd_flags |= FNDELAY;
#else
#error Please teach CORE how to make sockets non-blocking on your platform.
#endif
if (fcntl(sd, F_SETFL, fd_flags) == -1)
{
return errno;
}
#else
int on = 1;
if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
return errno;
#endif /* BEOS */
return CORE_OK;
}
static struct addrinfo *resolver(int family, int type, int protocol,
const char *host, c_uint16_t port, int flags)
{
int rc;
char service[16];
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
if (type == SOCK_RAW)
{
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
}
else
{
hints.ai_socktype = type;
hints.ai_protocol = protocol;
}
hints.ai_flags = flags;
snprintf(service, sizeof(service), "%u", port);
rc = getaddrinfo(host, service, &hints, &res);
if (rc != 0)
{
d_error("getaddrinfo(%s:%d) failed(%d:%s)",
host, port, errno, strerror(errno));
return NULL;
}
return res;
}
static void set_fds(fd_set *fds)
{
sock_t *sock = NULL;
FD_ZERO(fds);
for (sock = list_first(&fd_list); sock != NULL; sock = list_next(sock))
{
FD_SET(sock->fd, fds);
}
}
static void fd_dispatch(fd_set *fds)
{
sock_t *sock = NULL;
for (sock = list_first(&fd_list); sock != NULL; sock = list_next(sock))
{
if (FD_ISSET(sock->fd, fds))
{
if (sock->handler)
{
sock->handler((sock_id)sock, sock->data);
}
}
}
}

View File

@ -12,6 +12,7 @@
#include "core_semaphore.h"
#include "core_thread.h"
#include "core_net.h"
#include "core_sock.h"
#include "core_file.h"
#include "core_pkbuf.h"
#include "core_signal.h"
@ -46,6 +47,7 @@ status_t core_initialize(void)
atomic_init();
thread_init();
net_init();
sock_init();
file_init();
pkbuf_init();
tlv_init();
@ -69,6 +71,7 @@ void core_terminate(void)
tlv_final();
pkbuf_final();
file_final();
sock_final();
net_final();
thread_final();
atomic_final();

38
lib/core/src/unix/tcp.c Normal file
View File

@ -0,0 +1,38 @@
#define TRACE_MODULE _tcp
#include "core_debug.h"
#include "core_udp.h"
status_t tcp_create(sock_id *new,
int family,
const char *local_host, c_uint16_t local_port,
const char *remote_host, c_uint16_t remote_port,
int flags)
{
status_t rv;
sock_id id;
rv = sock_create(new, family, SOCK_STREAM, IPPROTO_TCP, flags);
d_assert(new, return CORE_ERROR,);
id = *new;
if (flags & SOCK_F_BIND)
{
rv = sock_bind(id, local_host, local_port);
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
if (flags & SOCK_F_CONNECT)
{
rv = sock_connect(id, remote_host, remote_port);
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
if (flags & SOCK_F_BIND)
{
rv = sock_listen(id);
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
return CORE_OK;
}

32
lib/core/src/unix/udp.c Normal file
View File

@ -0,0 +1,32 @@
#define TRACE_MODULE _udp
#include "core_debug.h"
#include "core_udp.h"
status_t udp_create(sock_id *new,
int family,
const char *local_host, c_uint16_t local_port,
const char *remote_host, c_uint16_t remote_port,
int flags)
{
status_t rv;
sock_id id;
rv = sock_create(new, family, SOCK_DGRAM, IPPROTO_UDP, flags);
d_assert(new, return CORE_ERROR,);
id = *new;
if (flags & SOCK_F_BIND)
{
rv = sock_bind(id, local_host, local_port);
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
if (flags & SOCK_F_CONNECT)
{
rv = sock_connect(id, remote_host, remote_port);
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
return CORE_OK;
}

View File

@ -3,7 +3,7 @@
bin_PROGRAMS = testcore
testcore_SOURCES = \
abts.c testds.c testfsm.c testnetlib.c testthread.c testtlv.c \
abts.c testds.c testfsm.c testnetlib.c testsock.c testthread.c testtlv.c \
testaes.c testfile.c testlock.c testatomic.c testsha.c testtime.c \
testdir.c testfilecopy.c testmsgq.c testsleep.c testtimer.c \
testpkbuf.c testmisc.c testhash.c \

View File

@ -29,6 +29,7 @@ const struct testlist {
{testaes},
{testsha2},
{testnetlib},
{testsock},
#if USE_USRSCTP != 1
{testsctp},
#endif

158
lib/core/test/testsock.c Normal file
View File

@ -0,0 +1,158 @@
#include "core_debug.h"
#include "core_thread.h"
#include "core_udp.h"
#include "core_tcp.h"
#include "testutil.h"
#define DATASTR "This is a test"
#define STRLEN 8092
#define SRV_PORT 7777
#define CLI_PORT 7778
static void sock_test1(abts_case *tc, void *data)
{
sock_id udp;
status_t rv;
rv = udp_create(&udp, AF_UNSPEC, 0, SRV_PORT, NULL, 0, SOCK_F_BIND);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = sock_delete(udp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = udp_create(&udp, AF_UNSPEC,
"127.0.0.1", SRV_PORT, NULL, 0, SOCK_F_BIND);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = sock_delete(udp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = udp_create(&udp, AF_UNSPEC, "::1", SRV_PORT, NULL, 0, SOCK_F_BIND);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = sock_delete(udp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
}
static thread_id recv_thread;
static void *THREAD_FUNC recv_main(thread_id id, void *data)
{
abts_case *tc = data;
status_t rv;
sock_id tcp;
char buf[STRLEN];
ssize_t size;
rv = tcp_create(&tcp, AF_UNSPEC, NULL, 0, "::1", SRV_PORT, SOCK_F_CONNECT);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
size = sock_recv(tcp, buf, STRLEN, 0, NULL, NULL);
ABTS_INT_EQUAL(tc, strlen(DATASTR), size);
rv = sock_delete(tcp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
thread_exit(id, size);
return NULL;
}
static void sock_test2(abts_case *tc, void *data)
{
sock_id tcp, tcp2;
status_t rv;
ssize_t size;
rv = tcp_create(&tcp, AF_INET6, NULL, SRV_PORT, NULL, 0, SOCK_F_BIND);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = thread_create(&recv_thread, NULL, recv_main, NULL);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = sock_accept(&tcp2, tcp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
size = sock_send(tcp2, DATASTR, strlen(DATASTR), 0, NULL, 0);
ABTS_INT_EQUAL(tc, strlen(DATASTR), size);
thread_join(&rv, recv_thread);
ABTS_INT_EQUAL(tc, strlen(DATASTR), rv);
rv = sock_delete(tcp2);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = sock_delete(tcp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
}
static thread_id send_thread;
static void *THREAD_FUNC send_main(thread_id id, void *data)
{
abts_case *tc = data;
status_t rv;
sock_id udp;
struct sockaddr src_addr;
socklen_t addrlen;
char buf[STRLEN];
ssize_t size;
char temp[INET6_ADDRSTRLEN];
rv = udp_create(&udp, AF_INET,
NULL, 0, "127.0.0.1", SRV_PORT, SOCK_F_CONNECT);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
size = sock_send(udp, DATASTR, strlen(DATASTR), 0, NULL, 0);
ABTS_INT_EQUAL(tc, strlen(DATASTR), size);
rv = sock_delete(udp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
thread_exit(id, size);
return NULL;
}
static void sock_test3(abts_case *tc, void *data)
{
sock_id udp;
status_t rv;
ssize_t size;
struct sockaddr src_addr;
socklen_t addrlen;
char buf[STRLEN];
char temp[INET6_ADDRSTRLEN];
rv = udp_create(&udp, AF_INET, NULL, SRV_PORT, NULL, 0, SOCK_F_BIND);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = thread_create(&send_thread, NULL, send_main, NULL);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
size = sock_recv(udp, buf, STRLEN, 0, &src_addr, &addrlen);
ABTS_INT_EQUAL(tc, strlen(DATASTR), size);
#if 0
printf("%s, %d\n", SOCK_NTOP(&src_addr, temp), addrlen);
#endif
thread_join(&rv, send_thread);
ABTS_INT_EQUAL(tc, strlen(DATASTR), rv);
rv = sock_delete(udp);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
}
abts_suite *testsock(abts_suite *suite)
{
suite = ADD_SUITE(suite)
#if 0
extern int _sock;
d_trace_level(&_sock, 1);
#endif
abts_run_test(suite, sock_test1, NULL);
abts_run_test(suite, sock_test2, NULL);
abts_run_test(suite, sock_test3, NULL);
return suite;
}

View File

@ -63,6 +63,7 @@ abts_suite *testtlv(abts_suite *suite);
abts_suite *testaes(abts_suite *suite);
abts_suite *testsha2(abts_suite *suite);
abts_suite *testnetlib(abts_suite *suite);
abts_suite *testsock(abts_suite *suite);
abts_suite *testsctp(abts_suite *suite);
abts_suite *testtime(abts_suite *suite);
abts_suite *testtimer(abts_suite *suite);