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:
parent
90a50d999d
commit
068d049a9f
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 \
|
||||
|
|
|
@ -29,6 +29,7 @@ const struct testlist {
|
|||
{testaes},
|
||||
{testsha2},
|
||||
{testnetlib},
|
||||
{testsock},
|
||||
#if USE_USRSCTP != 1
|
||||
{testsctp},
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue