c++/domain-socket-bridge/domain-socket-bridge.c
author František Kučera <franta-hg@frantovo.cz>
Sat, 19 Nov 2016 19:29:54 +0100
changeset 31 baa90e4359c8
parent 30 efa6fc19b006
child 32 0eaa8735a083
permissions -rw-r--r--
libevent: čtení ze soketu: funkční čtení a odpovídání na zprávy (rot13)
     1 #include <string.h>
     2 #include <errno.h>
     3 #include <stdio.h>
     4 #include <signal.h>
     5 #include <stdlib.h>
     6 
     7 #include <event2/bufferevent.h>
     8 #include <event2/buffer.h>
     9 #include <event2/listener.h>
    10 #include <event2/util.h>
    11 #include <event2/event.h>
    12 #include <sys/un.h>
    13 #include <unistd.h>
    14 
    15 #define MAX_LINE 16384
    16 
    17 static const char MESSAGE[] = "Hello, World!\n";
    18 
    19 static const char PATH[] = "./roura";
    20 
    21 static void listener_cb(evutil_socket_t, short, void *);
    22 static void conn_read_cb(struct bufferevent *, void *);
    23 static void conn_write_cb(struct bufferevent *, void *);
    24 static void conn_event_cb(struct bufferevent *, short, void *);
    25 static void signal_cb(evutil_socket_t, short, void *);
    26 
    27 static char rot13_char(char);
    28 
    29 int main(int argc, char **argv) {
    30 	struct event_base *base;
    31 	evutil_socket_t listener;
    32 	struct event *listener_event;
    33 	struct event *signal_event;
    34 
    35 	struct sockaddr_un sun;
    36 
    37 	setvbuf(stdout, NULL, _IONBF, 0);
    38 
    39 	base = event_base_new();
    40 	if (!base) {
    41 		fprintf(stderr, "Could not initialize libevent!\n");
    42 		return 1;
    43 	}
    44 
    45 	memset(&sun, 0, sizeof (sun));
    46 	sun.sun_family = AF_UNIX;
    47 	strcpy(sun.sun_path, PATH);
    48 
    49 	listener = socket(AF_UNIX, SOCK_STREAM, 0);
    50 	evutil_make_socket_nonblocking(listener);
    51 
    52 	if (bind(listener, (struct sockaddr*) &sun, sizeof (sun)) < 0) {
    53 		fprintf(stderr, "Could not create domain socket: %s!\n", PATH);
    54 		return 1;
    55 	}
    56 
    57 	if (listen(listener, 16) < 0) {
    58 		fprintf(stderr, "Could not listen\n");
    59 		return 1;
    60 	}
    61 
    62 	listener_event = event_new(base, listener, EV_READ | EV_PERSIST, listener_cb, (void*) base);
    63 
    64 	if (!listener_event) {
    65 		fprintf(stderr, "Could not do event_new\n");
    66 		return 1;
    67 	}
    68 
    69 	event_add(listener_event, NULL);
    70 
    71 	signal_event = evsignal_new(base, SIGINT, signal_cb, (void *) base);
    72 
    73 	if (!signal_event || event_add(signal_event, NULL) < 0) {
    74 		fprintf(stderr, "Could not create/add a signal event!\n");
    75 		return 1;
    76 	}
    77 
    78 	event_base_dispatch(base);
    79 
    80 	event_free(listener_event);
    81 	event_free(signal_event);
    82 	event_base_free(base);
    83 
    84 	// smažeme soket na disku / soubor -- jinak by program příště spadl na evconnlistener_new_bind()
    85 	unlink(PATH);
    86 
    87 	printf("done\n");
    88 	return 0;
    89 }
    90 
    91 static void listener_cb(evutil_socket_t listener, short event, void *user_data) {
    92 	struct event_base *base = (event_base *) user_data;
    93 	struct bufferevent *bev;
    94 
    95 	struct sockaddr_storage ss;
    96 	socklen_t slen = sizeof (ss);
    97 	int fd = accept(listener, (struct sockaddr*) &ss, &slen);
    98 	if (fd < 0) {
    99 		fprintf(stderr, "Unable to accept(): %d", fd);
   100 		return;
   101 	} else if (fd > FD_SETSIZE) {
   102 		close(fd);
   103 		return;
   104 	}
   105 
   106 	evutil_make_socket_nonblocking(fd);
   107 
   108 	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
   109 	if (!bev) {
   110 		fprintf(stderr, "Error constructing bufferevent!");
   111 		event_base_loopbreak(base);
   112 		return;
   113 	}
   114 	bufferevent_setcb(bev, conn_read_cb, conn_write_cb, conn_event_cb, NULL);
   115 	bufferevent_setwatermark(bev, EV_READ, 0, MAX_LINE);
   116 	bufferevent_enable(bev, EV_READ | EV_WRITE);
   117 
   118 	printf("někdo se k nám připojil! / %p\n", bev);
   119 
   120 	bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
   121 }
   122 
   123 static void conn_read_cb(struct bufferevent *bev, void *user_data) {
   124 	/* This callback is invoked when there is data to read on bev. */
   125 	struct evbuffer *input = bufferevent_get_input(bev);
   126 	struct evbuffer *output = bufferevent_get_output(bev);
   127 	struct event_base *base = (event_base *) user_data;
   128 
   129 	size_t len = evbuffer_get_length(input);
   130 	char *data;
   131 	/*
   132 	data = (char*) malloc(len);
   133 	evbuffer_copyout(input, data, len);
   134 	 */
   135 
   136 	size_t n;
   137 	int i;
   138 	while ((data = evbuffer_readln(input, &n, EVBUFFER_EOL_LF))) {
   139 		for (i = 0; i < n; ++i)
   140 			data[i] = rot13_char(data[i]);
   141 		evbuffer_add(output, data, n);
   142 		evbuffer_add(output, "\n", 1);
   143 		free(data);
   144 	}
   145 
   146 	printf("we got some data...\n");
   147 
   148 	/*
   149 	if (memcmp(data, "exit\n", len) == 0) {
   150 		struct timeval delay = {2, 123};
   151 		event_base_loopexit(base, &delay);
   152 	}
   153 	 */
   154 
   155 	if (evbuffer_get_length(input) >= MAX_LINE) {
   156 		/* Too long; just process what there is and go on so that the buffer
   157 		 * doesn't grow infinitely long. */
   158 		char buf[1024];
   159 		while (evbuffer_get_length(input)) {
   160 			int n = evbuffer_remove(input, buf, sizeof (buf));
   161 			for (i = 0; i < n; ++i)
   162 				buf[i] = rot13_char(buf[i]);
   163 			evbuffer_add(output, buf, n);
   164 		}
   165 		evbuffer_add(output, "\n", 1);
   166 	}
   167 
   168 	/* Copy all the data from the input buffer to the output buffer. */
   169 	/*
   170 	evbuffer_add_buffer(output, input);
   171 	free(data);
   172 	 */
   173 }
   174 
   175 static void conn_write_cb(struct bufferevent *bev, void *user_data) {
   176 	struct evbuffer *output = bufferevent_get_output(bev);
   177 	if (evbuffer_get_length(output) == 0) {
   178 		printf("flushed answer / %p\n", bev);
   179 		/* nebudeme ukončovat spojení
   180 		bufferevent_free(bev);
   181 		 */
   182 	}
   183 }
   184 
   185 static void conn_event_cb(struct bufferevent *bev, short events, void *user_data) {
   186 	if (events & BEV_EVENT_EOF) {
   187 		printf("Connection closed.\n");
   188 	} else if (events & BEV_EVENT_ERROR) {
   189 		printf("Got an error on the connection: %s\n", strerror(errno));
   190 	}
   191 
   192 	// None of the other events can happen here, since we haven't enabled timeouts
   193 	bufferevent_free(bev);
   194 }
   195 
   196 static void signal_cb(evutil_socket_t sig, short events, void *user_data) {
   197 	struct event_base *base = (event_base *) user_data;
   198 	struct timeval delay = {2, 123};
   199 
   200 	printf("Zachycen SIGINT (Ctrl+C); ukončuji program během %ld sekund a %ld mikrosekund.\n", delay.tv_sec, delay.tv_usec);
   201 
   202 	event_base_loopexit(base, &delay);
   203 }
   204 
   205 static char rot13_char(char c) {
   206 	/* We don't want to use isalpha here; setting the locale would change
   207 	 * which characters are considered alphabetical. */
   208 	if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
   209 		return c + 13;
   210 	else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
   211 		return c - 13;
   212 	else
   213 		return c;
   214 }