mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
17 changed files with 1136 additions and 1029 deletions
File diff suppressed because it is too large
@ -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 |
#!/usr/bin/env ruby |
||||
|
require 'socket' |
||||
|
|
||||
def test(description) |
def test(description) |
||||
pid = fork do |
pid = fork do |
||||
exec(File.dirname(__FILE__) + "/echo") |
exec(File.dirname(__FILE__) + "/echo") |
||||
end |
end |
||||
|
|
||||
|
puts "#{description}: " |
||||
begin |
begin |
||||
sleep 0.5 # give time for the server to start |
sleep 0.5 # give time for the server to start |
||||
yield(pid) |
yield(pid) |
||||
rescue |
rescue |
||||
puts "\033[1;31mFAIL\033[m: #{description}" |
puts "\033[1;31mFAIL\033[m" |
||||
raise $! |
raise $! |
||||
ensure |
ensure |
||||
`kill -9 #{pid}` |
`kill -9 #{pid}` |
||||
end |
end |
||||
puts "\033[1;32mPASS\033[m: #{description}" |
puts "\033[1;32mPASS\033[m" |
||||
end |
end |
||||
|
|
||||
test("make sure echo server works") do |
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