1 1.1 christos /* $NetBSD: hello-world.c,v 1.1.1.3 2021/04/07 02:43:15 christos Exp $ */ 2 1.1 christos /* 3 1.1.1.2 christos This example program provides a trivial server program that listens for TCP 4 1.1 christos connections on port 9995. When they arrive, it writes a short message to 5 1.1 christos each client connection, and closes each connection once it is flushed. 6 1.1 christos 7 1.1 christos Where possible, it exits cleanly in response to a SIGINT (ctrl-c). 8 1.1 christos */ 9 1.1 christos 10 1.1 christos 11 1.1 christos #include <string.h> 12 1.1 christos #include <errno.h> 13 1.1 christos #include <stdio.h> 14 1.1 christos #include <signal.h> 15 1.1.1.2 christos #ifndef _WIN32 16 1.1 christos #include <netinet/in.h> 17 1.1 christos # ifdef _XOPEN_SOURCE_EXTENDED 18 1.1 christos # include <arpa/inet.h> 19 1.1 christos # endif 20 1.1 christos #include <sys/socket.h> 21 1.1 christos #endif 22 1.1 christos 23 1.1 christos #include <event2/bufferevent.h> 24 1.1 christos #include <event2/buffer.h> 25 1.1 christos #include <event2/listener.h> 26 1.1 christos #include <event2/util.h> 27 1.1 christos #include <event2/event.h> 28 1.1 christos 29 1.1 christos static const char MESSAGE[] = "Hello, World!\n"; 30 1.1 christos 31 1.1 christos static const int PORT = 9995; 32 1.1 christos 33 1.1 christos static void listener_cb(struct evconnlistener *, evutil_socket_t, 34 1.1 christos struct sockaddr *, int socklen, void *); 35 1.1 christos static void conn_writecb(struct bufferevent *, void *); 36 1.1 christos static void conn_eventcb(struct bufferevent *, short, void *); 37 1.1 christos static void signal_cb(evutil_socket_t, short, void *); 38 1.1 christos 39 1.1 christos int 40 1.1 christos main(int argc, char **argv) 41 1.1 christos { 42 1.1 christos struct event_base *base; 43 1.1 christos struct evconnlistener *listener; 44 1.1 christos struct event *signal_event; 45 1.1 christos 46 1.1.1.3 christos struct sockaddr_in sin = {0}; 47 1.1.1.2 christos #ifdef _WIN32 48 1.1 christos WSADATA wsa_data; 49 1.1 christos WSAStartup(0x0201, &wsa_data); 50 1.1 christos #endif 51 1.1 christos 52 1.1 christos base = event_base_new(); 53 1.1 christos if (!base) { 54 1.1 christos fprintf(stderr, "Could not initialize libevent!\n"); 55 1.1 christos return 1; 56 1.1 christos } 57 1.1 christos 58 1.1 christos sin.sin_family = AF_INET; 59 1.1 christos sin.sin_port = htons(PORT); 60 1.1 christos 61 1.1 christos listener = evconnlistener_new_bind(base, listener_cb, (void *)base, 62 1.1 christos LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, 63 1.1 christos (struct sockaddr*)&sin, 64 1.1 christos sizeof(sin)); 65 1.1 christos 66 1.1 christos if (!listener) { 67 1.1 christos fprintf(stderr, "Could not create a listener!\n"); 68 1.1 christos return 1; 69 1.1 christos } 70 1.1 christos 71 1.1 christos signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); 72 1.1 christos 73 1.1 christos if (!signal_event || event_add(signal_event, NULL)<0) { 74 1.1 christos fprintf(stderr, "Could not create/add a signal event!\n"); 75 1.1 christos return 1; 76 1.1 christos } 77 1.1 christos 78 1.1 christos event_base_dispatch(base); 79 1.1 christos 80 1.1 christos evconnlistener_free(listener); 81 1.1 christos event_free(signal_event); 82 1.1 christos event_base_free(base); 83 1.1 christos 84 1.1 christos printf("done\n"); 85 1.1 christos return 0; 86 1.1 christos } 87 1.1 christos 88 1.1 christos static void 89 1.1 christos listener_cb(struct evconnlistener *listener, evutil_socket_t fd, 90 1.1 christos struct sockaddr *sa, int socklen, void *user_data) 91 1.1 christos { 92 1.1 christos struct event_base *base = user_data; 93 1.1 christos struct bufferevent *bev; 94 1.1 christos 95 1.1 christos bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); 96 1.1 christos if (!bev) { 97 1.1 christos fprintf(stderr, "Error constructing bufferevent!"); 98 1.1 christos event_base_loopbreak(base); 99 1.1 christos return; 100 1.1 christos } 101 1.1 christos bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL); 102 1.1 christos bufferevent_enable(bev, EV_WRITE); 103 1.1 christos bufferevent_disable(bev, EV_READ); 104 1.1 christos 105 1.1 christos bufferevent_write(bev, MESSAGE, strlen(MESSAGE)); 106 1.1 christos } 107 1.1 christos 108 1.1 christos static void 109 1.1 christos conn_writecb(struct bufferevent *bev, void *user_data) 110 1.1 christos { 111 1.1 christos struct evbuffer *output = bufferevent_get_output(bev); 112 1.1 christos if (evbuffer_get_length(output) == 0) { 113 1.1 christos printf("flushed answer\n"); 114 1.1 christos bufferevent_free(bev); 115 1.1 christos } 116 1.1 christos } 117 1.1 christos 118 1.1 christos static void 119 1.1 christos conn_eventcb(struct bufferevent *bev, short events, void *user_data) 120 1.1 christos { 121 1.1 christos if (events & BEV_EVENT_EOF) { 122 1.1 christos printf("Connection closed.\n"); 123 1.1 christos } else if (events & BEV_EVENT_ERROR) { 124 1.1 christos printf("Got an error on the connection: %s\n", 125 1.1 christos strerror(errno));/*XXX win32*/ 126 1.1 christos } 127 1.1 christos /* None of the other events can happen here, since we haven't enabled 128 1.1 christos * timeouts */ 129 1.1 christos bufferevent_free(bev); 130 1.1 christos } 131 1.1 christos 132 1.1 christos static void 133 1.1 christos signal_cb(evutil_socket_t sig, short events, void *user_data) 134 1.1 christos { 135 1.1 christos struct event_base *base = user_data; 136 1.1 christos struct timeval delay = { 2, 0 }; 137 1.1 christos 138 1.1 christos printf("Caught an interrupt signal; exiting cleanly in two seconds.\n"); 139 1.1 christos 140 1.1 christos event_base_loopexit(base, &delay); 141 1.1 christos } 142