Usage: server: ./ex_network_reactor -a [ADDR] -p PORT -n N client: ./ex_network_reactor -s HOST -p PORT -n N
Reactor is Linux/Android only. On other platforms n_reactor_new returns NULL with a LOG_INFO and the example exits 0 (treated as a skip rather than a failure).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <pthread.h>
#define MODE_SERVER 0
#define MODE_CLIENT 1
(void)sig;
}
static void usage(
void) {
fprintf(stderr,
"Usage: ex_network_reactor [options]\n"
" -a ADDR server mode, bind ADDR (use \"\" for all interfaces)\n"
" -s HOST client mode, connect to HOST\n"
" -p PORT port (required)\n"
" -n COUNT server: connections to handle, client: connect attempts (default 5)\n"
" -V LEVEL log level: LOG_DEBUG/LOG_INFO/LOG_NOTICE/LOG_ERR (default LOG_NOTICE)\n"
" -h show this help\n");
}
return 1;
}
n_log(
LOG_NOTICE,
"reactor server listening on %s:%s (target %d connections)",
if (!reactor) {
n_log(
LOG_NOTICE,
"n_reactor unavailable on this platform, skipping (exit 0)");
netw_unload();
return 0;
}
pthread_t reactor_thr;
n_log(
LOG_ERR,
"pthread_create(reactor): %s", strerror(errno));
netw_unload();
return 2;
}
if (!active) {
pthread_join(reactor_thr, NULL);
netw_unload();
return 3;
}
int handled = 0;
int retval = 0;
if (client) {
}
while (node) {
if (msg) {
}
handled++;
}
node = next;
}
}
while (node) {
node = next;
}
"reactor stats: events=%lld registered=%lld unregistered=%lld "
"wake=%lld writes_partial=%lld reads_partial=%lld",
pthread_join(reactor_thr, NULL);
netw_unload();
n_log(
LOG_NOTICE,
"reactor server done (%d connections handled)", handled);
return 0;
}
static int run_client(
const char* host,
const char*
port,
int attempts) {
int rc = 0;
for (
int i = 0;
g_running && i < attempts; i++) {
n_log(
LOG_ERR,
"client connect %d/%d to %s:%s failed", i + 1, attempts, host,
port);
rc = 4;
continue;
}
char payload[64];
snprintf(payload, sizeof(payload), "hello-from-client-%d", i + 1);
}
if (in) {
} else {
rc = 5;
}
}
netw_unload();
return rc;
}
int main(
int argc,
char** argv) {
char* host = NULL;
int count = 5;
int explicit_server = 0;
int opt;
while ((opt = getopt(argc, argv, "ha:s:p:n:V:")) != -1) {
switch (opt) {
case 'a':
explicit_server = 1;
break;
case 's':
host = strdup(optarg);
break;
case 'p':
break;
case 'n':
count = atoi(optarg);
if (count <= 0) count = 1;
break;
case 'V':
if (!strcmp(optarg, "LOG_DEBUG"))
else if (!strcmp(optarg, "LOG_INFO"))
else if (!strcmp(optarg, "LOG_NOTICE"))
else if (!strcmp(optarg, "LOG_ERR"))
break;
case 'h':
default:
return 1;
}
}
(void)explicit_server;
fprintf(stderr, "ex_network_reactor: -p PORT is required\n");
return 1;
}
#ifdef __linux__
signal(SIGPIPE, SIG_IGN);
#endif
int rc;
} else {
}
return rc;
}
static void sighandler(int sig)
static void run_server(char *port, double fake_offset, int nb_rounds)
static void run_client(char *server, char *port, int nb_rounds)
NETWORK * netw
Network for server mode, accepting incomming.
static volatile sig_atomic_t g_running
#define FreeNoLog(__ptr)
Free Handler without log.
void * ptr
void pointer to store
LIST_NODE * start
pointer to the start of the list
size_t nb_items
number of item currently in the list
struct LIST_NODE * next
pointer to the next node
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
int list_destroy(LIST **list)
Empty and Free a list container.
void * remove_list_node_f(LIST *list, LIST_NODE *node)
Internal function called each time we need to get a node out of a list.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Structure of a generic LIST container.
Structure of a generic list node.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_INFO
informational
size_t length
total allocation (in bytes) of the data buffer, padding included
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
A box including a string and his lenght.
void u_sleep(unsigned int usec)
wrapper around usleep for API consistency
N_SOCKET link
networking socket
SOCKET sock
a normal socket
N_STR * netw_get_msg(NETWORK *netw)
Get a message from aimed NETWORK.
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
N_STR * netw_wait_msg(NETWORK *netw, unsigned int refresh, size_t timeout)
Wait a message from aimed NETWORK.
int netw_connect(NETWORK **netw, char *host, char *port, int ip_version)
Use this to connect a NETWORK to any listening one, unrestricted send/recv lists.
Common headers and low-level functions & define.
void * n_reactor_run_thread_entry(void *arg)
pthread_create-compatible entry point that calls n_reactor_run on the reactor passed via arg.
void n_reactor_get_stats(const n_reactor *reactor, n_reactor_stats *out)
Read current stats counters into *out.
n_reactor * n_reactor_new(int max_fds_hint)
Create a new reactor.
NETWORK * netw_accept_into_reactor(NETWORK *listener, size_t send_list_limit, size_t recv_list_limit, int blocking, n_reactor *reactor, int *retval)
Accept a connection on listener and register it with reactor instead of starting per-connection threa...
void n_reactor_stop(n_reactor *reactor)
Signal the run loop to exit at the next iteration.
void n_reactor_destroy(n_reactor **reactor)
Tear down a reactor.
Single-threaded epoll reactor for n_network connections.
long long fds_registered
lifetime register call count
long long writes_partial
EAGAIN on send -> re-armed EPOLLOUT.
long long reads_partial
EAGAIN on recv -> kept accumulator.
long long events_processed
total epoll events dispatched
long long wake_signals
eventfd wake events processed
struct n_reactor n_reactor
Opaque reactor handle.
long long fds_unregistered
lifetime unregister call count
Counters for the dashboard / profile_server.sh.