#include #include /* EXIT_FAILURE */ #include /* bool true false */ #include /* intptr_t */ #include /* SIGPIPE SIG_IGN signal(3) */ #include /* EPIPE */ #include /* memset(3) */ #include /* assert(3) */ #include /* close(2) */ #if _WIN32 #include #else #include /* struct timeval */ #include /* AF_INET socklen_t struct sockaddr * struct sockaddr_storage */ #include /* struct sockaddr_in */ #endif #include /* close(2) */ #include /* err(3) errx(3) */ #include /* struct event struct event_base event_init(3) * event_base_loop(3) */ #include #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() */