#include <stdio.h>
#include <stdlib.h> /* EXIT_FAILURE */
#include <stdbool.h> /* bool true false */
#include <inttypes.h> /* intptr_t */
#include <signal.h> /* SIGPIPE SIG_IGN signal(3) */
#include <errno.h> /* EPIPE */
#include <string.h> /* memset(3) */
#include <assert.h> /* assert(3) */
#include <fcntl.h> /* close(2) */
#if _WIN32
#include <winsock2.h>
#else
#include <sys/time.h> /* struct timeval */
#include <sys/socket.h> /* AF_INET socklen_t struct sockaddr
* struct sockaddr_storage */
#include <netinet/in.h> /* struct sockaddr_in */
#endif
#include <unistd.h> /* close(2) */
#include <err.h> /* err(3) errx(3) */
#include <event.h> /* struct event struct event_base event_init(3)
* event_base_loop(3) */
#include <arena/proto.h>
#include "socket.h"
#include "bufio.h"
static const char mesg[] = "one\ntwo\nthree\nbreak ";
static void user_catch_write(struct bufio *eio, void *sent, size_t len, enum bufio_errno err, void *s) {
static int nsent = 0;
assert(err == BUFIO_ESUCCESS);
assert(len == sizeof mesg - 1);
if (++nsent > 21) {
bufio_close(eio);
socket_close(s);
return;
}
bufio_writen(eio, mesg, sizeof mesg - 1, &user_catch_write, s, &(struct timeval){ 2, 0 });
return;
} /* user_catch_write() */
static void serv_catch_line(struct bufio *eio, void *ln, size_t len, enum bufio_errno err, void *arg) {
static char lnbuf[sizeof mesg];
struct socket *s = arg;
assert(err == BUFIO_ESUCCESS || err == BUFIO_EEOF);
if (len > 0)
warnx("read %d bytes: %.*s", (int)len, (int)(len - 1), (char *)ln);
if (err == BUFIO_EEOF) {
bufio_close(eio);
socket_close(s);
return;
}
assert(len > 0);
bufio_gets(eio, lnbuf, sizeof lnbuf, &serv_catch_line, s, &(struct timeval){ 2, 0});
return;
} /* serv_catch_line() */
static void main_catch_accept(struct socket *s, struct socket *p, enum socket_errno so_errno, void *arg) {
static char ln[sizeof mesg];
struct bufio *eio;
enum bufio_errno io_errno;
if (so_errno == SOCKET_ECANCELLED)
return /* void */;
assert(so_errno == SOCKET_ESUCCESS);
socket_close(s);
warnx("caught accept");
assert(eio = bufio_open(0, 0, &io_errno));
bufio_set_source(eio, socket_to_source(p));
bufio_set_sink(eio, socket_to_sink(p));
bufio_gets(eio, ln, sizeof ln, &serv_catch_line, p, &(struct timeval){ 2, 0});
return /* void */;
} /* main_catch_accept() */
static void main_catch_connect(struct socket *s, enum socket_errno err, void *arg) {
struct bufio *eio;
enum bufio_errno io_errno;
assert(err == SOCKET_ESUCCESS);
warnx("caught connect");
assert(eio = bufio_open(0, 0, &io_errno));
bufio_set_source(eio, socket_to_source(s));
bufio_set_sink(eio, socket_to_sink(s));
bufio_writen(eio, mesg, sizeof mesg - 1, &user_catch_write, s, &(struct timeval){ 2, 0 });
return /* void */;
} /* main_catch_connect() */
int main(void) {
struct event_base *ev_base;
struct socket *client, *server;
struct sockaddr_in sin;
struct socket_options opts;
struct socket_name so_name;
enum socket_errno so_errno;
#if _WIN32
WSADATA wsaData;
#endif
#if _WIN32
if (NO_ERROR != WSAStartup(MAKEWORD(2, 2), &wsaData))
err(EXIT_FAILURE, "WSAStartup");
#endif
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
if (!(ev_base = event_init()))
err(EXIT_FAILURE, "event_init");
(void)memset(&sin, '\0', sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(4000);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
(void)socket_name_init_addr(&so_name, (struct sockaddr *)&sin, sizeof sin);
opts = socket_defaults;
opts.sa_reuseaddr = 1;
if (0 == (server = socket_open(&so_name, &opts, ev_base, ARENA_STDLIB, &so_errno)))
err(EXIT_FAILURE, "socket_open");
socket_accept(server, &main_catch_accept, server, 0);
if (0 == (client = socket_open(&so_name, &opts, ev_base, ARENA_STDLIB, &so_errno)))
err(EXIT_FAILURE, "socket_open");
socket_connect(client, &main_catch_connect, client, 0);
event_base_loop(ev_base, 0);
return 0;
} /* main() */
syntax highlighted by Code2HTML, v. 0.9.1