1*657871a7Schristos /* $NetBSD: hello-world.c,v 1.1.1.3 2021/04/07 02:43:15 christos Exp $ */
26ecf6635Schristos /*
3805a1ce9Schristos This example program provides a trivial server program that listens for TCP
46ecf6635Schristos connections on port 9995. When they arrive, it writes a short message to
56ecf6635Schristos each client connection, and closes each connection once it is flushed.
66ecf6635Schristos
76ecf6635Schristos Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
86ecf6635Schristos */
96ecf6635Schristos
106ecf6635Schristos
116ecf6635Schristos #include <string.h>
126ecf6635Schristos #include <errno.h>
136ecf6635Schristos #include <stdio.h>
146ecf6635Schristos #include <signal.h>
15805a1ce9Schristos #ifndef _WIN32
166ecf6635Schristos #include <netinet/in.h>
176ecf6635Schristos # ifdef _XOPEN_SOURCE_EXTENDED
186ecf6635Schristos # include <arpa/inet.h>
196ecf6635Schristos # endif
206ecf6635Schristos #include <sys/socket.h>
216ecf6635Schristos #endif
226ecf6635Schristos
236ecf6635Schristos #include <event2/bufferevent.h>
246ecf6635Schristos #include <event2/buffer.h>
256ecf6635Schristos #include <event2/listener.h>
266ecf6635Schristos #include <event2/util.h>
276ecf6635Schristos #include <event2/event.h>
286ecf6635Schristos
296ecf6635Schristos static const char MESSAGE[] = "Hello, World!\n";
306ecf6635Schristos
316ecf6635Schristos static const int PORT = 9995;
326ecf6635Schristos
336ecf6635Schristos static void listener_cb(struct evconnlistener *, evutil_socket_t,
346ecf6635Schristos struct sockaddr *, int socklen, void *);
356ecf6635Schristos static void conn_writecb(struct bufferevent *, void *);
366ecf6635Schristos static void conn_eventcb(struct bufferevent *, short, void *);
376ecf6635Schristos static void signal_cb(evutil_socket_t, short, void *);
386ecf6635Schristos
396ecf6635Schristos int
main(int argc,char ** argv)406ecf6635Schristos main(int argc, char **argv)
416ecf6635Schristos {
426ecf6635Schristos struct event_base *base;
436ecf6635Schristos struct evconnlistener *listener;
446ecf6635Schristos struct event *signal_event;
456ecf6635Schristos
46*657871a7Schristos struct sockaddr_in sin = {0};
47805a1ce9Schristos #ifdef _WIN32
486ecf6635Schristos WSADATA wsa_data;
496ecf6635Schristos WSAStartup(0x0201, &wsa_data);
506ecf6635Schristos #endif
516ecf6635Schristos
526ecf6635Schristos base = event_base_new();
536ecf6635Schristos if (!base) {
546ecf6635Schristos fprintf(stderr, "Could not initialize libevent!\n");
556ecf6635Schristos return 1;
566ecf6635Schristos }
576ecf6635Schristos
586ecf6635Schristos sin.sin_family = AF_INET;
596ecf6635Schristos sin.sin_port = htons(PORT);
606ecf6635Schristos
616ecf6635Schristos listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
626ecf6635Schristos LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
636ecf6635Schristos (struct sockaddr*)&sin,
646ecf6635Schristos sizeof(sin));
656ecf6635Schristos
666ecf6635Schristos if (!listener) {
676ecf6635Schristos fprintf(stderr, "Could not create a listener!\n");
686ecf6635Schristos return 1;
696ecf6635Schristos }
706ecf6635Schristos
716ecf6635Schristos signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
726ecf6635Schristos
736ecf6635Schristos if (!signal_event || event_add(signal_event, NULL)<0) {
746ecf6635Schristos fprintf(stderr, "Could not create/add a signal event!\n");
756ecf6635Schristos return 1;
766ecf6635Schristos }
776ecf6635Schristos
786ecf6635Schristos event_base_dispatch(base);
796ecf6635Schristos
806ecf6635Schristos evconnlistener_free(listener);
816ecf6635Schristos event_free(signal_event);
826ecf6635Schristos event_base_free(base);
836ecf6635Schristos
846ecf6635Schristos printf("done\n");
856ecf6635Schristos return 0;
866ecf6635Schristos }
876ecf6635Schristos
886ecf6635Schristos static void
listener_cb(struct evconnlistener * listener,evutil_socket_t fd,struct sockaddr * sa,int socklen,void * user_data)896ecf6635Schristos listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
906ecf6635Schristos struct sockaddr *sa, int socklen, void *user_data)
916ecf6635Schristos {
926ecf6635Schristos struct event_base *base = user_data;
936ecf6635Schristos struct bufferevent *bev;
946ecf6635Schristos
956ecf6635Schristos bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
966ecf6635Schristos if (!bev) {
976ecf6635Schristos fprintf(stderr, "Error constructing bufferevent!");
986ecf6635Schristos event_base_loopbreak(base);
996ecf6635Schristos return;
1006ecf6635Schristos }
1016ecf6635Schristos bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
1026ecf6635Schristos bufferevent_enable(bev, EV_WRITE);
1036ecf6635Schristos bufferevent_disable(bev, EV_READ);
1046ecf6635Schristos
1056ecf6635Schristos bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
1066ecf6635Schristos }
1076ecf6635Schristos
1086ecf6635Schristos static void
conn_writecb(struct bufferevent * bev,void * user_data)1096ecf6635Schristos conn_writecb(struct bufferevent *bev, void *user_data)
1106ecf6635Schristos {
1116ecf6635Schristos struct evbuffer *output = bufferevent_get_output(bev);
1126ecf6635Schristos if (evbuffer_get_length(output) == 0) {
1136ecf6635Schristos printf("flushed answer\n");
1146ecf6635Schristos bufferevent_free(bev);
1156ecf6635Schristos }
1166ecf6635Schristos }
1176ecf6635Schristos
1186ecf6635Schristos static void
conn_eventcb(struct bufferevent * bev,short events,void * user_data)1196ecf6635Schristos conn_eventcb(struct bufferevent *bev, short events, void *user_data)
1206ecf6635Schristos {
1216ecf6635Schristos if (events & BEV_EVENT_EOF) {
1226ecf6635Schristos printf("Connection closed.\n");
1236ecf6635Schristos } else if (events & BEV_EVENT_ERROR) {
1246ecf6635Schristos printf("Got an error on the connection: %s\n",
1256ecf6635Schristos strerror(errno));/*XXX win32*/
1266ecf6635Schristos }
1276ecf6635Schristos /* None of the other events can happen here, since we haven't enabled
1286ecf6635Schristos * timeouts */
1296ecf6635Schristos bufferevent_free(bev);
1306ecf6635Schristos }
1316ecf6635Schristos
1326ecf6635Schristos static void
signal_cb(evutil_socket_t sig,short events,void * user_data)1336ecf6635Schristos signal_cb(evutil_socket_t sig, short events, void *user_data)
1346ecf6635Schristos {
1356ecf6635Schristos struct event_base *base = user_data;
1366ecf6635Schristos struct timeval delay = { 2, 0 };
1376ecf6635Schristos
1386ecf6635Schristos printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
1396ecf6635Schristos
1406ecf6635Schristos event_base_loopexit(base, &delay);
1416ecf6635Schristos }
142