mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
17 changed files with 1136 additions and 1029 deletions
@ -0,0 +1,232 @@ |
|||
/* Copyright (c) 2008,2009 Ryan Dahl
|
|||
* |
|||
* evnet_queue comes from Nginx, ngx_queue.h |
|||
* Copyright (C) 2002-2009 Igor Sysoev |
|||
* |
|||
* Redistribution and use in source and binary forms, with or without |
|||
* modification, are permitted provided that the following conditions |
|||
* are met: |
|||
* 1. Redistributions of source code must retain the above copyright |
|||
* notice, this list of conditions and the following disclaimer. |
|||
* 2. Redistributions in binary form must reproduce the above copyright |
|||
* notice, this list of conditions and the following disclaimer in the |
|||
* documentation and/or other materials provided with the distribution. |
|||
* |
|||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS BE LIABLE |
|||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|||
* SUCH DAMAGE. |
|||
*/ |
|||
#include <netdb.h> |
|||
#include <ev.h> |
|||
#include <stddef.h> /* offsetof() */ |
|||
|
|||
#ifndef evnet_h |
|||
#define evnet_h |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
#ifndef EVNET_HAVE_GNUTLS |
|||
# define EVNET_HAVE_GNUTLS 0 |
|||
#endif |
|||
#if EVNET_HAVE_GNUTLS |
|||
# include <gnutls/gnutls.h> |
|||
#endif |
|||
|
|||
typedef struct evnet_queue evnet_queue; |
|||
typedef struct evnet_buf evnet_buf; |
|||
typedef struct evnet_server evnet_server; |
|||
typedef struct evnet_socket evnet_socket; |
|||
|
|||
void evnet_server_init (evnet_server *); |
|||
int evnet_server_listen (evnet_server *, struct addrinfo *addrinfo, int backlog); |
|||
void evnet_server_attach (EV_P_ evnet_server *); |
|||
void evnet_server_detach (evnet_server *); |
|||
void evnet_server_close (evnet_server *); // synchronous
|
|||
|
|||
void evnet_socket_init (evnet_socket *, float timeout); |
|||
int evnet_socket_connect (evnet_socket *, struct addrinfo *addrinfo); |
|||
void evnet_socket_attach (EV_P_ evnet_socket *); |
|||
void evnet_socket_detach (evnet_socket *); |
|||
void evnet_socket_read_start (evnet_socket *); |
|||
void evnet_socket_read_stop (evnet_socket *); |
|||
|
|||
/* Resets the timeout to stay alive for another socket->timeout seconds
|
|||
*/ |
|||
void evnet_socket_reset_timeout (evnet_socket *); |
|||
|
|||
/* Writes a buffer to the socket.
|
|||
* (Do not send a NULL evnet_buf or a buffer with evnet_buf->base == NULL.) |
|||
*/ |
|||
void evnet_socket_write (evnet_socket *, evnet_buf *); |
|||
|
|||
void evnet_socket_write_simple (evnet_socket *, const char *str, size_t len); |
|||
|
|||
/* Once the write buffer is drained, evnet_socket_close will shutdown the
|
|||
* writing end of the socket and will close the read end once the server |
|||
* replies with an EOF. |
|||
*/ |
|||
void evnet_socket_close (evnet_socket *); |
|||
|
|||
/* Do not wait for the server to reply with EOF. This will only be called
|
|||
* once the write buffer is drained. |
|||
* Warning: For TCP socket, the OS kernel may (should) reply with RST |
|||
* packets if this is called when data is still being received from the |
|||
* server. |
|||
*/ |
|||
void evnet_socket_full_close (evnet_socket *); |
|||
|
|||
/* The most extreme measure.
|
|||
* Will not wait for the write queue to complete. |
|||
*/ |
|||
void evnet_socket_force_close (evnet_socket *); |
|||
|
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
/* Tells the socket to use transport layer security (SSL). evnet_socket does
|
|||
* not want to make any decisions about security requirements, so the |
|||
* majoirty of GnuTLS configuration is left to the user. Only the transport |
|||
* layer of GnuTLS is controlled by evnet_socket. That is, do not use |
|||
* gnutls_transport_* functions. Do use the rest of GnuTLS's API. |
|||
*/ |
|||
void evnet_socket_set_secure_session (evnet_socket *, gnutls_session_t); |
|||
#endif |
|||
|
|||
evnet_buf * evnet_buf_new (const char* base, size_t len); |
|||
evnet_buf * evnet_buf_new2 (size_t len); |
|||
void evnet_buf_destroy (evnet_buf *); |
|||
|
|||
|
|||
struct evnet_queue { |
|||
evnet_queue *prev; |
|||
evnet_queue *next; |
|||
}; |
|||
|
|||
struct evnet_buf { |
|||
/* public */ |
|||
char *base; |
|||
size_t len; |
|||
void (*release) (evnet_buf *); /* called when oi is done with the object */ |
|||
void *data; |
|||
|
|||
/* private */ |
|||
size_t written; |
|||
evnet_queue queue; |
|||
}; |
|||
|
|||
struct evnet_server { |
|||
/* read only */ |
|||
int fd; |
|||
#if EV_MULTIPLICITY |
|||
struct ev_loop *loop; |
|||
#endif |
|||
unsigned attached:1; |
|||
unsigned listening:1; |
|||
|
|||
/* PRIVATE */ |
|||
ev_io connection_watcher; |
|||
|
|||
/* PUBLIC */ |
|||
|
|||
evnet_socket* (*on_connection) (evnet_server *, struct sockaddr *remote_addr); |
|||
|
|||
/* Executed when a server is closed.
|
|||
* If evnet_server_close() was called errorno will be 0. |
|||
* An libev error is indicated with errorno == 1 |
|||
* Otherwise errorno is a stdlib errno from a system call, e.g. accept() |
|||
*/ |
|||
void (*on_close) (evnet_server *, int errorno); |
|||
|
|||
void *data; |
|||
}; |
|||
|
|||
struct evnet_socket { |
|||
/* read only */ |
|||
int fd; |
|||
#if EV_MULTIPLICITY |
|||
struct ev_loop *loop; |
|||
#endif |
|||
evnet_server *server; |
|||
evnet_queue out_stream; |
|||
size_t written; |
|||
unsigned attached:1; |
|||
unsigned connected:1; |
|||
unsigned secure:1; |
|||
unsigned got_full_close:1; |
|||
unsigned got_half_close:1; |
|||
|
|||
/* NULL = that end of the socket is closed. */ |
|||
int (*read_action) (evnet_socket *); |
|||
int (*write_action) (evnet_socket *); |
|||
|
|||
/* ERROR CODES. 0 = no error. Check on_close. */ |
|||
int errorno; |
|||
#if EVNET_HAVE_GNUTLS |
|||
int gnutls_errorno; |
|||
#endif |
|||
|
|||
/* private */ |
|||
ev_io write_watcher; |
|||
ev_io read_watcher; |
|||
ev_timer timeout_watcher; |
|||
#if EVNET_HAVE_GNUTLS |
|||
gnutls_session_t session; |
|||
#endif |
|||
|
|||
/* public */ |
|||
size_t chunksize; /* the maximum chunk that on_read() will return */ |
|||
void (*on_connect) (evnet_socket *); |
|||
void (*on_read) (evnet_socket *, const void *buf, size_t count); |
|||
void (*on_drain) (evnet_socket *); |
|||
void (*on_close) (evnet_socket *); |
|||
void (*on_timeout) (evnet_socket *); |
|||
void *data; |
|||
}; |
|||
|
|||
EV_INLINE void |
|||
evnet_queue_init (evnet_queue *q) |
|||
{ |
|||
q->prev = q; |
|||
q->next = q; |
|||
} |
|||
|
|||
EV_INLINE void |
|||
evnet_queue_insert_head (evnet_queue *h, evnet_queue *x) |
|||
{ |
|||
(x)->next = (h)->next; |
|||
(x)->next->prev = x; |
|||
(x)->prev = h; |
|||
(h)->next = x; |
|||
} |
|||
|
|||
EV_INLINE void |
|||
evnet_queue_remove (evnet_queue *x) |
|||
{ |
|||
(x)->next->prev = (x)->prev; |
|||
(x)->prev->next = (x)->next; |
|||
#ifndef NDEBUG |
|||
(x)->prev = NULL; |
|||
(x)->next = NULL; |
|||
#endif |
|||
} |
|||
|
|||
#define evnet_queue_empty(h) (h == (h)->prev) |
|||
#define evnet_queue_head(h) (h)->next |
|||
#define evnet_queue_last(h) (h)->prev |
|||
#define evnet_queue_data(q, type, link) \ |
|||
(type *) ((unsigned char *) q - offsetof(type, link)) |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
#endif /* evnet_h */ |
@ -0,0 +1,102 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <assert.h> |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <netinet/in.h> |
|||
|
|||
|
|||
#include <ev.h> |
|||
#include <evnet.h> |
|||
#include <gnutls/gnutls.h> |
|||
|
|||
#define HOST "127.0.0.1" |
|||
#define SOCKFILE "/tmp/oi.sock" |
|||
#define PORT "5000" |
|||
|
|||
static int nconnections; |
|||
|
|||
static void |
|||
on_peer_close (evnet_socket *socket) |
|||
{ |
|||
assert(socket->errorno == 0); |
|||
//printf("server connection closed\n");
|
|||
free(socket); |
|||
} |
|||
|
|||
static void |
|||
on_peer_timeout (evnet_socket *socket) |
|||
{ |
|||
assert(socket); |
|||
fprintf(stderr, "peer connection timeout\n"); |
|||
assert(0); |
|||
} |
|||
|
|||
|
|||
|
|||
// timeout must match the timeout in timeout.rb
|
|||
#define TIMEOUT 5.0 |
|||
|
|||
static void |
|||
on_peer_read (evnet_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if(len == 0) return; |
|||
|
|||
evnet_socket_write_simple(socket, base, len); |
|||
} |
|||
|
|||
static evnet_socket* |
|||
on_server_connection (evnet_server *server, struct sockaddr *addr) |
|||
{ |
|||
assert(server); |
|||
assert(addr); |
|||
|
|||
evnet_socket *socket = malloc(sizeof(evnet_socket)); |
|||
evnet_socket_init(socket, TIMEOUT); |
|||
socket->on_read = on_peer_read; |
|||
socket->on_close = on_peer_close; |
|||
socket->on_timeout = on_peer_timeout; |
|||
|
|||
nconnections++; |
|||
|
|||
|
|||
//printf("on server connection\n");
|
|||
|
|||
return socket; |
|||
} |
|||
|
|||
int |
|||
main (void) |
|||
{ |
|||
int r; |
|||
evnet_server server; |
|||
|
|||
//printf("sizeof(evnet_server): %d\n", sizeof(evnet_server));
|
|||
//printf("sizeof(evnet_socket): %d\n", sizeof(evnet_socket));
|
|||
|
|||
evnet_server_init(&server); |
|||
server.on_connection = on_server_connection; |
|||
|
|||
struct addrinfo *servinfo; |
|||
struct addrinfo hints; |
|||
memset(&hints, 0, sizeof hints); |
|||
hints.ai_family = AF_UNSPEC; |
|||
hints.ai_socktype = SOCK_STREAM; |
|||
hints.ai_flags = AI_PASSIVE; |
|||
r = getaddrinfo(NULL, PORT, &hints, &servinfo); |
|||
assert(r == 0); |
|||
|
|||
r = evnet_server_listen(&server, servinfo, 10); |
|||
assert(r == 0); |
|||
evnet_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
freeaddrinfo(servinfo); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,478 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <assert.h> |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <netinet/in.h> |
|||
|
|||
#include <ev.h> |
|||
#include <evnet.h> |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
# include <gnutls/gnutls.h> |
|||
#endif |
|||
|
|||
static const struct addrinfo tcp_hints = |
|||
/* ai_flags */ { .ai_flags = 0 |
|||
/* ai_family */ , .ai_family = AF_UNSPEC |
|||
/* ai_socktype */ , .ai_socktype = SOCK_STREAM |
|||
, 0 |
|||
}; |
|||
|
|||
#define MARK_PROGRESS write(STDERR_FILENO, ".", 1) |
|||
|
|||
#define HOST "127.0.0.1" |
|||
#define SOCKFILE "/tmp/oi.sock" |
|||
#define PORT "5000" |
|||
|
|||
static evnet_server server; |
|||
static int nconnections; |
|||
static int use_tls; |
|||
static int got_server_close; |
|||
|
|||
static void |
|||
common_on_server_close (evnet_server *server, int errorno) |
|||
{ |
|||
assert(server); |
|||
assert(errorno == 0); |
|||
got_server_close = 1; |
|||
} |
|||
|
|||
static void |
|||
common_on_peer_close (evnet_socket *socket) |
|||
{ |
|||
assert(socket->errorno == 0); |
|||
printf("server connection closed\n"); |
|||
#if EVNET_HAVE_GNUTLS |
|||
assert(socket->gnutls_errorno == 0); |
|||
if (use_tls) gnutls_deinit(socket->session); |
|||
#endif |
|||
free(socket); |
|||
} |
|||
|
|||
static void |
|||
common_on_client_timeout (evnet_socket *socket) |
|||
{ |
|||
assert(socket); |
|||
printf("client connection timeout\n"); |
|||
} |
|||
|
|||
static void |
|||
common_on_peer_timeout (evnet_socket *socket) |
|||
{ |
|||
assert(socket); |
|||
fprintf(stderr, "peer connection timeout\n"); |
|||
assert(0); |
|||
} |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
#define DH_BITS 768 |
|||
static gnutls_anon_server_credentials_t server_credentials; |
|||
const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; |
|||
static gnutls_dh_params_t dh_params; |
|||
|
|||
void anon_tls_server (evnet_socket *socket) |
|||
{ |
|||
gnutls_session_t session; |
|||
socket->data = session; |
|||
|
|||
int r = gnutls_init(&session, GNUTLS_SERVER); |
|||
assert(r == 0); |
|||
gnutls_set_default_priority(session); |
|||
gnutls_kx_set_priority (session, kx_prio); |
|||
gnutls_credentials_set(session, GNUTLS_CRD_ANON, server_credentials); |
|||
gnutls_dh_set_prime_bits(session, DH_BITS); |
|||
|
|||
evnet_socket_set_secure_session(socket, session); |
|||
} |
|||
|
|||
void anon_tls_client (evnet_socket *socket) |
|||
{ |
|||
gnutls_session_t client_session; |
|||
gnutls_anon_client_credentials_t client_credentials; |
|||
|
|||
gnutls_anon_allocate_client_credentials (&client_credentials); |
|||
gnutls_init(&client_session, GNUTLS_CLIENT); |
|||
gnutls_set_default_priority(client_session); |
|||
gnutls_kx_set_priority(client_session, kx_prio); |
|||
/* Need to enable anonymous KX specifically. */ |
|||
gnutls_credentials_set(client_session, GNUTLS_CRD_ANON, client_credentials); |
|||
|
|||
evnet_socket_set_secure_session(socket, client_session); |
|||
assert(socket->secure); |
|||
} |
|||
|
|||
#endif // EVNET_HAVE_GNUTLS
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
#define PING "PING" |
|||
#define PONG "PONG" |
|||
#define EXCHANGES 5000 |
|||
#define PINGPONG_TIMEOUT 5.0 |
|||
|
|||
static int successful_ping_count; |
|||
|
|||
static void |
|||
pingpong_on_peer_read (evnet_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if (len == 0) { |
|||
evnet_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
char buf[2000]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
printf("server got message: %s\n", buf); |
|||
|
|||
evnet_socket_write_simple(socket, PONG, sizeof PONG); |
|||
} |
|||
|
|||
static void |
|||
pingpong_on_client_close (evnet_socket *socket) |
|||
{ |
|||
assert(socket); |
|||
printf("client connection closed\n"); |
|||
evnet_server_close(&server); |
|||
} |
|||
|
|||
static evnet_socket* |
|||
pingpong_on_server_connection (evnet_server *_server, struct sockaddr *addr) |
|||
{ |
|||
assert(_server == &server); |
|||
assert(addr); |
|||
|
|||
evnet_socket *socket = malloc(sizeof(evnet_socket)); |
|||
evnet_socket_init(socket, PINGPONG_TIMEOUT); |
|||
socket->on_read = pingpong_on_peer_read; |
|||
socket->on_close = common_on_peer_close; |
|||
socket->on_timeout = common_on_peer_timeout; |
|||
|
|||
nconnections++; |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
if (use_tls) anon_tls_server(socket); |
|||
#endif |
|||
|
|||
printf("on server connection\n"); |
|||
|
|||
return socket; |
|||
} |
|||
|
|||
static void |
|||
pingpong_on_client_connect (evnet_socket *socket) |
|||
{ |
|||
printf("client connected. sending ping\n"); |
|||
evnet_socket_write_simple(socket, PING, sizeof PING); |
|||
} |
|||
|
|||
static void |
|||
pingpong_on_client_read (evnet_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if(len == 0) { |
|||
evnet_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
assert(len = strlen(PONG)); |
|||
|
|||
char buf[len+1]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
printf("client got message: %s\n", buf); |
|||
|
|||
assert(strcmp(buf, PONG) == 0); |
|||
|
|||
if (++successful_ping_count > EXCHANGES) { |
|||
evnet_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
if (successful_ping_count % (EXCHANGES/20) == 0) MARK_PROGRESS; |
|||
|
|||
evnet_socket_write_simple(socket, PING, sizeof PING); |
|||
} |
|||
|
|||
int |
|||
pingpong (struct addrinfo *servinfo) |
|||
{ |
|||
int r; |
|||
evnet_socket client; |
|||
|
|||
successful_ping_count = 0; |
|||
nconnections = 0; |
|||
got_server_close = 0; |
|||
|
|||
printf("sizeof(evnet_server): %d\n", sizeof(evnet_server)); |
|||
printf("sizeof(evnet_socket): %d\n", sizeof(evnet_socket)); |
|||
|
|||
evnet_server_init(&server); |
|||
server.on_connection = pingpong_on_server_connection; |
|||
server.on_close = common_on_server_close; |
|||
|
|||
r = evnet_server_listen(&server, servinfo, 10); |
|||
assert(r == 0); |
|||
evnet_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
evnet_socket_init(&client, PINGPONG_TIMEOUT); |
|||
client.on_read = pingpong_on_client_read; |
|||
client.on_connect = pingpong_on_client_connect; |
|||
client.on_close = pingpong_on_client_close; |
|||
client.on_timeout = common_on_client_timeout; |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
if (use_tls) anon_tls_client(&client); |
|||
#endif |
|||
|
|||
r = evnet_socket_connect(&client, servinfo); |
|||
assert(r == 0 && "problem connecting"); |
|||
evnet_socket_attach(EV_DEFAULT_ &client); |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
printf("successful_ping_count = %d\n", successful_ping_count); |
|||
assert(successful_ping_count == EXCHANGES + 1); |
|||
assert(nconnections == 1); |
|||
assert(got_server_close); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
#define NCONN 100 |
|||
#define CONNINT_TIMEOUT 1000.0 |
|||
|
|||
static void |
|||
connint_on_peer_read(evnet_socket *socket, const void *base, size_t len) |
|||
{ |
|||
assert(base); |
|||
assert(len == 0); |
|||
evnet_socket_write_simple(socket, "BYE", 3); |
|||
printf("server wrote bye\n"); |
|||
} |
|||
|
|||
static void |
|||
connint_on_peer_drain(evnet_socket *socket) |
|||
{ |
|||
evnet_socket_close(socket); |
|||
} |
|||
|
|||
static evnet_socket* |
|||
connint_on_server_connection(evnet_server *_server, struct sockaddr *addr) |
|||
{ |
|||
assert(_server == &server); |
|||
assert(addr); |
|||
|
|||
evnet_socket *socket = malloc(sizeof(evnet_socket)); |
|||
evnet_socket_init(socket, CONNINT_TIMEOUT); |
|||
socket->on_read = connint_on_peer_read; |
|||
socket->on_drain = connint_on_peer_drain; |
|||
socket->on_close = common_on_peer_close; |
|||
socket->on_timeout = common_on_peer_timeout; |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
if (use_tls) anon_tls_server(socket); |
|||
#endif |
|||
|
|||
printf("on server connection\n"); |
|||
|
|||
return socket; |
|||
} |
|||
|
|||
static void |
|||
connint_on_client_connect (evnet_socket *socket) |
|||
{ |
|||
printf("on client connection\n"); |
|||
evnet_socket_close(socket); |
|||
} |
|||
|
|||
static void |
|||
connint_on_client_close (evnet_socket *socket) |
|||
{ |
|||
evnet_socket_close(socket); // already closed, but it shouldn't crash if we try to do it again
|
|||
|
|||
printf("client connection closed\n"); |
|||
|
|||
if (nconnections % (NCONN/20) == 0) MARK_PROGRESS; |
|||
|
|||
if(++nconnections == NCONN) { |
|||
evnet_server_close(&server); |
|||
printf("closing server\n"); |
|||
} |
|||
} |
|||
|
|||
static void |
|||
connint_on_client_read (evnet_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if (len == 0) { |
|||
evnet_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
char buf[200000]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
|
|||
printf("client got message: %s\n", buf); |
|||
|
|||
assert(strcmp(buf, "BYE") == 0); |
|||
evnet_socket_close(socket); |
|||
} |
|||
|
|||
int |
|||
connint (struct addrinfo *servinfo) |
|||
{ |
|||
int r; |
|||
|
|||
nconnections = 0; |
|||
got_server_close = 0; |
|||
|
|||
evnet_server_init(&server); |
|||
server.on_connection = connint_on_server_connection; |
|||
server.on_close = common_on_server_close; |
|||
|
|||
|
|||
evnet_server_listen(&server, servinfo, 1000); |
|||
evnet_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
evnet_socket clients[NCONN]; |
|||
int i; |
|||
for (i = 0; i < NCONN; i++) { |
|||
evnet_socket *client = &clients[i]; |
|||
evnet_socket_init(client, CONNINT_TIMEOUT); |
|||
client->on_read = connint_on_client_read; |
|||
client->on_connect = connint_on_client_connect; |
|||
client->on_close = connint_on_client_close; |
|||
client->on_timeout = common_on_client_timeout; |
|||
#if EVNET_HAVE_GNUTLS |
|||
if (use_tls) anon_tls_client(client); |
|||
#endif |
|||
r = evnet_socket_connect(client, servinfo); |
|||
assert(r == 0 && "problem connecting"); |
|||
evnet_socket_attach(EV_DEFAULT_ client); |
|||
} |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
assert(nconnections == NCONN); |
|||
assert(got_server_close); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
struct addrinfo * |
|||
create_tcp_address (void) |
|||
{ |
|||
struct addrinfo *servinfo; |
|||
int r = getaddrinfo(NULL, PORT, &tcp_hints, &servinfo); |
|||
assert(r == 0); |
|||
return servinfo; |
|||
} |
|||
|
|||
void |
|||
free_tcp_address (struct addrinfo *servinfo) |
|||
{ |
|||
freeaddrinfo(servinfo); |
|||
} |
|||
|
|||
|
|||
struct addrinfo * |
|||
create_unix_address (void) |
|||
{ |
|||
struct addrinfo *servinfo; |
|||
struct stat tstat; |
|||
if (lstat(SOCKFILE, &tstat) == 0) { |
|||
assert(S_ISSOCK(tstat.st_mode)); |
|||
unlink(SOCKFILE); |
|||
} |
|||
|
|||
servinfo = malloc(sizeof(struct addrinfo)); |
|||
servinfo->ai_family = AF_UNIX; |
|||
servinfo->ai_socktype = SOCK_STREAM; |
|||
servinfo->ai_protocol = 0; |
|||
|
|||
struct sockaddr_un *sockaddr = calloc(sizeof(struct sockaddr_un), 1); |
|||
sockaddr->sun_family = AF_UNIX; |
|||
strcpy(sockaddr->sun_path, SOCKFILE); |
|||
|
|||
servinfo->ai_addr = (struct sockaddr*)sockaddr; |
|||
servinfo->ai_addrlen = sizeof(struct sockaddr_un); |
|||
|
|||
return servinfo; |
|||
} |
|||
|
|||
void |
|||
free_unix_address (struct addrinfo *servinfo) |
|||
{ |
|||
free(servinfo->ai_addr); |
|||
free(servinfo); |
|||
} |
|||
|
|||
|
|||
int |
|||
main (void) |
|||
{ |
|||
#if EVNET_HAVE_GNUTLS |
|||
gnutls_global_init(); |
|||
|
|||
gnutls_dh_params_init (&dh_params); |
|||
|
|||
fsync((int)stderr); |
|||
gnutls_dh_params_generate2 (dh_params, DH_BITS); |
|||
|
|||
gnutls_anon_allocate_server_credentials (&server_credentials); |
|||
gnutls_anon_set_server_dh_params (server_credentials, dh_params); |
|||
#endif |
|||
|
|||
struct addrinfo *tcp_address = create_tcp_address(); |
|||
struct addrinfo *unix_address; |
|||
|
|||
|
|||
use_tls = 0; |
|||
assert(pingpong(tcp_address) == 0); |
|||
assert(connint(tcp_address) == 0); |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
use_tls = 1; |
|||
assert(pingpong(tcp_address) == 0); |
|||
assert(connint(tcp_address) == 0); |
|||
#endif |
|||
|
|||
|
|||
|
|||
use_tls = 0; |
|||
|
|||
unix_address = create_unix_address(); |
|||
assert(pingpong(unix_address) == 0); |
|||
free_unix_address(unix_address); |
|||
|
|||
unix_address = create_unix_address(); |
|||
assert(connint(unix_address) == 0); |
|||
free_unix_address(unix_address); |
|||
|
|||
#if EVNET_HAVE_GNUTLS |
|||
use_tls = 1; |
|||
|
|||
unix_address = create_unix_address(); |
|||
assert(pingpong(unix_address) == 0); |
|||
free_unix_address(unix_address); |
|||
|
|||
unix_address = create_unix_address(); |
|||
assert(connint(unix_address) == 0); |
|||
free_unix_address(unix_address); |
|||
#endif |
|||
|
|||
|
|||
free_tcp_address(tcp_address); |
|||
return 0; |
|||
} |
@ -1,20 +1,22 @@ |
|||
#!/usr/bin/env ruby |
|||
require 'socket' |
|||
|
|||
def test(description) |
|||
pid = fork do |
|||
exec(File.dirname(__FILE__) + "/echo") |
|||
end |
|||
|
|||
puts "#{description}: " |
|||
begin |
|||
sleep 0.5 # give time for the server to start |
|||
yield(pid) |
|||
rescue |
|||
puts "\033[1;31mFAIL\033[m: #{description}" |
|||
puts "\033[1;31mFAIL\033[m" |
|||
raise $! |
|||
ensure |
|||
`kill -9 #{pid}` |
|||
end |
|||
puts "\033[1;32mPASS\033[m: #{description}" |
|||
puts "\033[1;32mPASS\033[m" |
|||
end |
|||
|
|||
test("make sure echo server works") do |
@ -1,216 +0,0 @@ |
|||
/* Copyright (c) 2008,2009 Ryan Dahl
|
|||
* |
|||
* oi_queue comes from ngx_queue.h |
|||
* Copyright (C) 2002-2009 Igor Sysoev |
|||
* |
|||
* Redistribution and use in source and binary forms, with or without |
|||
* modification, are permitted provided that the following conditions |
|||
* are met: |
|||
* 1. Redistributions of source code must retain the above copyright |
|||
* notice, this list of conditions and the following disclaimer. |
|||
* 2. Redistributions in binary form must reproduce the above copyright |
|||
* notice, this list of conditions and the following disclaimer in the |
|||
* documentation and/or other materials provided with the distribution. |
|||
* |
|||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS BE LIABLE |
|||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|||
* SUCH DAMAGE. |
|||
*/ |
|||
#include <netdb.h> |
|||
#include <ev.h> |
|||
#include <stddef.h> /* offsetof() */ |
|||
|
|||
#ifndef oi_socket_h |
|||
#define oi_socket_h |
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
#ifndef HAVE_GNUTLS |
|||
# define HAVE_GNUTLS 0 |
|||
#endif |
|||
#if HAVE_GNUTLS |
|||
# include <gnutls/gnutls.h> |
|||
#endif |
|||
typedef struct oi_queue oi_queue; |
|||
struct oi_queue { |
|||
oi_queue *prev; |
|||
oi_queue *next; |
|||
}; |
|||
|
|||
#define oi_queue_init(q) \ |
|||
(q)->prev = q; \ |
|||
(q)->next = q |
|||
|
|||
#define oi_queue_empty(h) \ |
|||
(h == (h)->prev) |
|||
|
|||
#define oi_queue_insert_head(h, x) \ |
|||
(x)->next = (h)->next; \ |
|||
(x)->next->prev = x; \ |
|||
(x)->prev = h; \ |
|||
(h)->next = x |
|||
|
|||
#define oi_queue_head(h) \ |
|||
(h)->next |
|||
|
|||
#define oi_queue_last(h) \ |
|||
(h)->prev |
|||
|
|||
#define oi_queue_remove(x) \ |
|||
(x)->next->prev = (x)->prev; \ |
|||
(x)->prev->next = (x)->next; \ |
|||
(x)->prev = NULL; \ |
|||
(x)->next = NULL |
|||
|
|||
#define oi_queue_data(q, type, link) \ |
|||
(type *) ((unsigned char *) q - offsetof(type, link)) |
|||
|
|||
typedef struct oi_buf oi_buf; |
|||
typedef struct oi_server oi_server; |
|||
typedef struct oi_socket oi_socket; |
|||
|
|||
oi_buf * oi_buf_new (const char* base, size_t len); |
|||
oi_buf * oi_buf_new2 (size_t len); |
|||
void oi_buf_destroy (oi_buf *); |
|||
|
|||
void oi_server_init (oi_server *, int backlog); |
|||
int oi_server_listen (oi_server *, struct addrinfo *addrinfo); |
|||
void oi_server_attach (EV_P_ oi_server *); |
|||
void oi_server_detach (oi_server *); |
|||
void oi_server_close (oi_server *); |
|||
|
|||
void oi_socket_init (oi_socket *, float timeout); |
|||
int oi_socket_connect (oi_socket *, struct addrinfo *addrinfo); |
|||
void oi_socket_attach (EV_P_ oi_socket *); |
|||
void oi_socket_detach (oi_socket *); |
|||
void oi_socket_read_start (oi_socket *); |
|||
void oi_socket_read_stop (oi_socket *); |
|||
|
|||
/* Resets the timeout to stay alive for another socket->timeout seconds
|
|||
*/ |
|||
void oi_socket_reset_timeout (oi_socket *); |
|||
|
|||
/* Writes a buffer to the socket.
|
|||
* (Do not send a NULL oi_buf or a buffer with oi_buf->base == NULL.) |
|||
*/ |
|||
void oi_socket_write (oi_socket *, oi_buf *); |
|||
|
|||
void oi_socket_write_simple (oi_socket *, const char *str, size_t len); |
|||
|
|||
/* Once the write buffer is drained, oi_socket_close will shutdown the
|
|||
* writing end of the socket and will close the read end once the server |
|||
* replies with an EOF. |
|||
*/ |
|||
void oi_socket_close (oi_socket *); |
|||
|
|||
/* Do not wait for the server to reply with EOF. This will only be called
|
|||
* once the write buffer is drained. |
|||
* Warning: For TCP socket, the OS kernel may (should) reply with RST |
|||
* packets if this is called when data is still being received from the |
|||
* server. |
|||
*/ |
|||
void oi_socket_full_close (oi_socket *); |
|||
|
|||
/* The most extreme measure.
|
|||
* Will not wait for the write queue to complete. |
|||
*/ |
|||
void oi_socket_force_close (oi_socket *); |
|||
|
|||
|
|||
#if HAVE_GNUTLS |
|||
/* Tells the socket to use transport layer security (SSL). oi_socket does
|
|||
* not want to make any decisions about security requirements, so the |
|||
* majoirty of GnuTLS configuration is left to the user. Only the transport |
|||
* layer of GnuTLS is controlled by oi_socket. That is, do not use |
|||
* gnutls_transport_* functions. Do use the rest of GnuTLS's API. |
|||
*/ |
|||
void oi_socket_set_secure_session (oi_socket *, gnutls_session_t); |
|||
#endif |
|||
|
|||
struct oi_buf { |
|||
/* public */ |
|||
char *base; |
|||
size_t len; |
|||
void (*release) (oi_buf *); /* called when oi is done with the object */ |
|||
void *data; |
|||
|
|||
/* private */ |
|||
size_t written; |
|||
oi_queue queue; |
|||
}; |
|||
|
|||
struct oi_server { |
|||
/* read only */ |
|||
int fd; |
|||
int backlog; |
|||
#if EV_MULTIPLICITY |
|||
struct ev_loop *loop; |
|||
#endif |
|||
unsigned attached:1; |
|||
unsigned listening:1; |
|||
|
|||
/* private */ |
|||
ev_io connection_watcher; |
|||
|
|||
/* public */ |
|||
oi_socket* (*on_connection) (oi_server *, struct sockaddr *remote_addr, socklen_t remove_addr_len); |
|||
void (*on_error) (oi_server *); |
|||
void *data; |
|||
}; |
|||
|
|||
struct oi_socket { |
|||
/* read only */ |
|||
int fd; |
|||
#if EV_MULTIPLICITY |
|||
struct ev_loop *loop; |
|||
#endif |
|||
oi_server *server; |
|||
oi_queue out_stream; |
|||
size_t written; |
|||
unsigned attached:1; |
|||
unsigned connected:1; |
|||
unsigned secure:1; |
|||
unsigned got_full_close:1; |
|||
unsigned got_half_close:1; |
|||
|
|||
/* NULL = that end of the socket is closed. */ |
|||
int (*read_action) (oi_socket *); |
|||
int (*write_action) (oi_socket *); |
|||
|
|||
/* ERROR CODES. 0 = no error. Check on_close. */ |
|||
int errorno; |
|||
#if HAVE_GNUTLS |
|||
int gnutls_errorno; |
|||
#endif |
|||
|
|||
/* private */ |
|||
ev_io write_watcher; |
|||
ev_io read_watcher; |
|||
ev_timer timeout_watcher; |
|||
#if HAVE_GNUTLS |
|||
gnutls_session_t session; |
|||
#endif |
|||
|
|||
/* public */ |
|||
size_t chunksize; /* the maximum chunk that on_read() will return */ |
|||
void (*on_connect) (oi_socket *); |
|||
void (*on_read) (oi_socket *, const void *buf, size_t count); |
|||
void (*on_drain) (oi_socket *); |
|||
void (*on_close) (oi_socket *); |
|||
void (*on_timeout) (oi_socket *); |
|||
void *data; |
|||
}; |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
#endif /* oi_socket_h */ |
@ -1,106 +0,0 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <assert.h> |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <netinet/in.h> |
|||
|
|||
|
|||
#include <ev.h> |
|||
#include <oi_socket.h> |
|||
#include <gnutls/gnutls.h> |
|||
|
|||
#define HOST "127.0.0.1" |
|||
#define SOCKFILE "/tmp/oi.sock" |
|||
#define PORT "5000" |
|||
|
|||
int nconnections; |
|||
|
|||
static void |
|||
on_peer_close(oi_socket *socket) |
|||
{ |
|||
assert(socket->errorno == 0); |
|||
//printf("server connection closed\n");
|
|||
#if HAVE_GNUTLS |
|||
assert(socket->gnutls_errorno == 0); |
|||
#if SECURE |
|||
gnutls_deinit(socket->session); |
|||
#endif |
|||
#endif |
|||
free(socket); |
|||
} |
|||
|
|||
static void |
|||
on_client_timeout(oi_socket *socket) |
|||
{ |
|||
printf("client connection timeout\n"); |
|||
assert(0); |
|||
} |
|||
|
|||
static void |
|||
on_peer_timeout(oi_socket *socket) |
|||
{ |
|||
fprintf(stderr, "peer connection timeout\n"); |
|||
assert(0); |
|||
} |
|||
|
|||
|
|||
#if HAVE_GNUTLS |
|||
#if SECURE |
|||
#define DH_BITS 768 |
|||
gnutls_anon_server_credentials_t server_credentials; |
|||
const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; |
|||
static gnutls_dh_params_t dh_params; |
|||
|
|||
void anon_tls_init() |
|||
{ |
|||
gnutls_global_init(); |
|||
|
|||
gnutls_dh_params_init (&dh_params); |
|||
|
|||
fprintf(stderr, ".."); |
|||
fsync((int)stderr); |
|||
gnutls_dh_params_generate2 (dh_params, DH_BITS); |
|||
fprintf(stderr, "."); |
|||
|
|||
gnutls_anon_allocate_server_credentials (&server_credentials); |
|||
gnutls_anon_set_server_dh_params (server_credentials, dh_params); |
|||
} |
|||
|
|||
void anon_tls_server(oi_socket *socket) |
|||
{ |
|||
gnutls_session_t session; |
|||
socket->data = session; |
|||
|
|||
int r = gnutls_init(&session, GNUTLS_SERVER); |
|||
assert(r == 0); |
|||
gnutls_set_default_priority(session); |
|||
gnutls_kx_set_priority (session, kx_prio); |
|||
gnutls_credentials_set(session, GNUTLS_CRD_ANON, server_credentials); |
|||
gnutls_dh_set_prime_bits(session, DH_BITS); |
|||
|
|||
oi_socket_set_secure_session(socket, session); |
|||
} |
|||
|
|||
void anon_tls_client(oi_socket *socket) |
|||
{ |
|||
gnutls_session_t client_session; |
|||
gnutls_anon_client_credentials_t client_credentials; |
|||
|
|||
gnutls_anon_allocate_client_credentials (&client_credentials); |
|||
gnutls_init (&client_session, GNUTLS_CLIENT); |
|||
gnutls_set_default_priority(client_session); |
|||
gnutls_kx_set_priority(client_session, kx_prio); |
|||
/* Need to enable anonymous KX specifically. */ |
|||
gnutls_credentials_set (client_session, GNUTLS_CRD_ANON, client_credentials); |
|||
|
|||
oi_socket_set_secure_session(socket, client_session); |
|||
assert(socket->secure); |
|||
} |
|||
|
|||
#endif // SECURE
|
|||
#endif // HAVE_GNUTLS
|
@ -1,154 +0,0 @@ |
|||
#include "test/common.c" |
|||
#define NCONN 100 |
|||
#define TIMEOUT 1000.0 |
|||
|
|||
static oi_server server; |
|||
|
|||
static void |
|||
on_peer_read(oi_socket *socket, const void *base, size_t len) |
|||
{ |
|||
assert(len == 0); |
|||
oi_socket_write_simple(socket, "BYE", 3); |
|||
//printf("server wrote bye\n");
|
|||
} |
|||
|
|||
static void |
|||
on_peer_drain(oi_socket *socket) |
|||
{ |
|||
oi_socket_close(socket); |
|||
} |
|||
|
|||
static oi_socket* |
|||
on_server_connection(oi_server *server, struct sockaddr *addr, socklen_t len) |
|||
{ |
|||
oi_socket *socket = malloc(sizeof(oi_socket)); |
|||
oi_socket_init(socket, TIMEOUT); |
|||
socket->on_read = on_peer_read; |
|||
socket->on_drain = on_peer_drain; |
|||
socket->on_close = on_peer_close; |
|||
socket->on_timeout = on_peer_timeout; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_server(socket); |
|||
# endif |
|||
#endif |
|||
|
|||
//printf("on server connection\n");
|
|||
|
|||
return socket; |
|||
} |
|||
|
|||
static void |
|||
on_client_connect(oi_socket *socket) |
|||
{ |
|||
//printf("on client connection\n");
|
|||
oi_socket_close(socket); |
|||
} |
|||
|
|||
static void |
|||
on_client_close(oi_socket *socket) |
|||
{ |
|||
oi_socket_close(socket); // already closed, but it shouldn't crash if we try to do it again
|
|||
|
|||
//printf("client connection closed\n");
|
|||
if(++nconnections == NCONN) { |
|||
oi_server_detach(&server); |
|||
//printf("detaching server\n");
|
|||
} |
|||
} |
|||
|
|||
static void |
|||
on_client_read(oi_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if (len == 0) { |
|||
oi_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
char buf[200000]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
|
|||
//printf("client got message: %s\n", buf);
|
|||
|
|||
if (strcmp(buf, "BYE") == 0) { |
|||
oi_socket_close(socket); |
|||
} else { |
|||
assert(0); |
|||
} |
|||
} |
|||
|
|||
int |
|||
main(int argc, const char *argv[]) |
|||
{ |
|||
int r; |
|||
|
|||
oi_server_init(&server, 1000); |
|||
server.on_connection = on_server_connection; |
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_init(); |
|||
# endif |
|||
#endif |
|||
|
|||
struct addrinfo *servinfo; |
|||
struct addrinfo hints; |
|||
memset(&hints, 0, sizeof hints); |
|||
#if TCP |
|||
hints.ai_family = AF_UNSPEC; |
|||
hints.ai_socktype = SOCK_STREAM; |
|||
hints.ai_flags = AI_PASSIVE; |
|||
r = getaddrinfo(NULL, PORT, &hints, &servinfo); |
|||
assert(r == 0); |
|||
#else |
|||
struct stat tstat; |
|||
if (lstat(SOCKFILE, &tstat) == 0) { |
|||
if (S_ISSOCK(tstat.st_mode)) |
|||
unlink(SOCKFILE); |
|||
} |
|||
|
|||
servinfo = malloc(sizeof(struct addrinfo)); |
|||
servinfo->ai_family = AF_UNIX; |
|||
servinfo->ai_socktype = SOCK_STREAM; |
|||
servinfo->ai_protocol = 0; |
|||
|
|||
struct sockaddr_un *sockaddr = calloc(sizeof(struct sockaddr_un), 1); |
|||
sockaddr->sun_family = AF_UNIX; |
|||
strcpy(sockaddr->sun_path, SOCKFILE); |
|||
|
|||
servinfo->ai_addr = (struct sockaddr*)sockaddr; |
|||
servinfo->ai_addrlen = sizeof(struct sockaddr_un); |
|||
#endif |
|||
|
|||
oi_server_listen(&server, servinfo); |
|||
oi_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
int i; |
|||
for(i = 0; i < NCONN; i++) { |
|||
oi_socket *client = malloc(sizeof(oi_socket)); |
|||
oi_socket_init(client, TIMEOUT); |
|||
client->on_read = on_client_read; |
|||
client->on_connect = on_client_connect; |
|||
client->on_close = on_client_close; |
|||
client->on_timeout = on_client_timeout; |
|||
#if HAVE_GNUTLS |
|||
#if SECURE |
|||
anon_tls_client(client); |
|||
#endif |
|||
#endif |
|||
r = oi_socket_connect(client, servinfo); |
|||
assert(r == 0 && "problem connecting"); |
|||
oi_socket_attach(EV_DEFAULT_ client); |
|||
} |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
assert(nconnections == NCONN); |
|||
|
|||
#if TCP |
|||
freeaddrinfo(servinfo); |
|||
#endif |
|||
|
|||
return 0; |
|||
} |
@ -1,97 +0,0 @@ |
|||
#include "test/common.c" |
|||
|
|||
// timeout must match the timeout in timeout.rb
|
|||
#define TIMEOUT 5.0 |
|||
|
|||
int successful_ping_count; |
|||
|
|||
static void |
|||
on_peer_read(oi_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if(len == 0) |
|||
return; |
|||
|
|||
oi_socket_write_simple(socket, base, len); |
|||
} |
|||
|
|||
static oi_socket* |
|||
on_server_connection(oi_server *server, struct sockaddr *addr, socklen_t len) |
|||
{ |
|||
oi_socket *socket = malloc(sizeof(oi_socket)); |
|||
oi_socket_init(socket, TIMEOUT); |
|||
socket->on_read = on_peer_read; |
|||
socket->on_close = on_peer_close; |
|||
socket->on_timeout = on_peer_timeout; |
|||
|
|||
nconnections++; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_server(socket); |
|||
# endif |
|||
#endif |
|||
|
|||
//printf("on server connection\n");
|
|||
|
|||
return socket; |
|||
} |
|||
|
|||
int |
|||
main(int argc, const char *argv[]) |
|||
{ |
|||
int r; |
|||
oi_server server; |
|||
oi_socket client; |
|||
|
|||
//printf("sizeof(oi_server): %d\n", sizeof(oi_server));
|
|||
//printf("sizeof(oi_socket): %d\n", sizeof(oi_socket));
|
|||
|
|||
oi_server_init(&server, 10); |
|||
server.on_connection = on_server_connection; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_init(); |
|||
# endif |
|||
#endif |
|||
|
|||
struct addrinfo *servinfo; |
|||
struct addrinfo hints; |
|||
memset(&hints, 0, sizeof hints); |
|||
#if TCP |
|||
hints.ai_family = AF_UNSPEC; |
|||
hints.ai_socktype = SOCK_STREAM; |
|||
hints.ai_flags = AI_PASSIVE; |
|||
r = getaddrinfo(NULL, PORT, &hints, &servinfo); |
|||
assert(r == 0); |
|||
#else |
|||
struct stat tstat; |
|||
if (lstat(SOCKFILE, &tstat) == 0) { |
|||
if (S_ISSOCK(tstat.st_mode)) |
|||
unlink(SOCKFILE); |
|||
} |
|||
|
|||
servinfo = malloc(sizeof(struct addrinfo)); |
|||
servinfo->ai_family = AF_UNIX; |
|||
servinfo->ai_socktype = SOCK_STREAM; |
|||
servinfo->ai_protocol = 0; |
|||
|
|||
struct sockaddr_un *sockaddr = calloc(sizeof(struct sockaddr_un), 1); |
|||
sockaddr->sun_family = AF_UNIX; |
|||
strcpy(sockaddr->sun_path, SOCKFILE); |
|||
|
|||
servinfo->ai_addr = (struct sockaddr*)sockaddr; |
|||
servinfo->ai_addrlen = sizeof(struct sockaddr_un); |
|||
#endif |
|||
r = oi_server_listen(&server, servinfo); |
|||
assert(r == 0); |
|||
oi_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
#if TCP |
|||
freeaddrinfo(servinfo); |
|||
#endif |
|||
|
|||
return 0; |
|||
} |
@ -1,164 +0,0 @@ |
|||
#include "test/common.c" |
|||
|
|||
#define PING "PING" |
|||
#define PONG "PONG" |
|||
#define EXCHANGES 500 |
|||
#define TIMEOUT 5.0 |
|||
|
|||
int successful_ping_count; |
|||
|
|||
static void |
|||
on_peer_read(oi_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if (len == 0) { |
|||
oi_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
char buf[2000]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
//printf("server got message: %s\n", buf);
|
|||
|
|||
oi_socket_write_simple(socket, PONG, sizeof PONG); |
|||
} |
|||
|
|||
static void |
|||
on_client_close(oi_socket *socket) |
|||
{ |
|||
//printf("client connection closed\n");
|
|||
ev_unloop(EV_DEFAULT_ EVUNLOOP_ALL); |
|||
} |
|||
|
|||
static oi_socket* |
|||
on_server_connection(oi_server *server, struct sockaddr *addr, socklen_t len) |
|||
{ |
|||
oi_socket *socket = malloc(sizeof(oi_socket)); |
|||
oi_socket_init(socket, TIMEOUT); |
|||
socket->on_read = on_peer_read; |
|||
socket->on_close = on_peer_close; |
|||
socket->on_timeout = on_peer_timeout; |
|||
|
|||
nconnections++; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_server(socket); |
|||
# endif |
|||
#endif |
|||
|
|||
//printf("on server connection\n");
|
|||
|
|||
return socket; |
|||
} |
|||
|
|||
static void |
|||
on_client_connect (oi_socket *socket) |
|||
{ |
|||
//printf("client connected. sending ping\n");
|
|||
oi_socket_write_simple(socket, PING, sizeof PING); |
|||
} |
|||
|
|||
static void |
|||
on_client_read (oi_socket *socket, const void *base, size_t len) |
|||
{ |
|||
if(len == 0) { |
|||
oi_socket_close(socket); |
|||
return; |
|||
} |
|||
|
|||
char buf[200000]; |
|||
strncpy(buf, base, len); |
|||
buf[len] = 0; |
|||
//printf("client got message: %s\n", buf);
|
|||
|
|||
if(strcmp(buf, PONG) == 0) { |
|||
|
|||
if(++successful_ping_count > EXCHANGES) { |
|||
oi_socket_close(socket); |
|||
return; |
|||
} |
|||
oi_socket_write_simple(socket, PING, sizeof PING); |
|||
} else { |
|||
assert(0); |
|||
} |
|||
} |
|||
|
|||
int |
|||
main(int argc, const char *argv[]) |
|||
{ |
|||
int r; |
|||
oi_server server; |
|||
oi_socket client; |
|||
|
|||
//printf("sizeof(oi_server): %d\n", sizeof(oi_server));
|
|||
//printf("sizeof(oi_socket): %d\n", sizeof(oi_socket));
|
|||
|
|||
oi_server_init(&server, 10); |
|||
server.on_connection = on_server_connection; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_init(); |
|||
# endif |
|||
#endif |
|||
|
|||
struct addrinfo *servinfo; |
|||
struct addrinfo hints; |
|||
memset(&hints, 0, sizeof hints); |
|||
#if TCP |
|||
hints.ai_family = AF_UNSPEC; |
|||
hints.ai_socktype = SOCK_STREAM; |
|||
hints.ai_flags = AI_PASSIVE; |
|||
r = getaddrinfo(NULL, PORT, &hints, &servinfo); |
|||
assert(r == 0); |
|||
#else |
|||
struct stat tstat; |
|||
if (lstat(SOCKFILE, &tstat) == 0) { |
|||
if (S_ISSOCK(tstat.st_mode)) |
|||
unlink(SOCKFILE); |
|||
} |
|||
|
|||
servinfo = malloc(sizeof(struct addrinfo)); |
|||
servinfo->ai_family = AF_UNIX; |
|||
servinfo->ai_socktype = SOCK_STREAM; |
|||
servinfo->ai_protocol = 0; |
|||
|
|||
struct sockaddr_un *sockaddr = calloc(sizeof(struct sockaddr_un), 1); |
|||
sockaddr->sun_family = AF_UNIX; |
|||
strcpy(sockaddr->sun_path, SOCKFILE); |
|||
|
|||
servinfo->ai_addr = (struct sockaddr*)sockaddr; |
|||
servinfo->ai_addrlen = sizeof(struct sockaddr_un); |
|||
#endif |
|||
r = oi_server_listen(&server, servinfo); |
|||
assert(r == 0); |
|||
oi_server_attach(EV_DEFAULT_ &server); |
|||
|
|||
oi_socket_init(&client, TIMEOUT); |
|||
client.on_read = on_client_read; |
|||
client.on_connect = on_client_connect; |
|||
client.on_close = on_client_close; |
|||
client.on_timeout = on_client_timeout; |
|||
|
|||
#if HAVE_GNUTLS |
|||
# if SECURE |
|||
anon_tls_client(&client); |
|||
# endif |
|||
#endif |
|||
|
|||
r = oi_socket_connect(&client, servinfo); |
|||
assert(r == 0 && "problem connecting"); |
|||
oi_socket_attach(EV_DEFAULT_ &client); |
|||
|
|||
ev_loop(EV_DEFAULT_ 0); |
|||
|
|||
assert(successful_ping_count == EXCHANGES + 1); |
|||
assert(nconnections == 1); |
|||
|
|||
#if TCP |
|||
freeaddrinfo(servinfo); |
|||
#endif |
|||
|
|||
return 0; |
|||
} |
Loading…
Reference in new issue