franta-hg@28: #include franta-hg@28: #include franta-hg@28: #include franta-hg@28: #include franta-hg@30: #include franta-hg@28: franta-hg@28: #include franta-hg@28: #include franta-hg@28: #include franta-hg@28: #include franta-hg@28: #include franta-hg@38: #include franta-hg@29: #include franta-hg@29: #include franta-hg@28: franta-hg@28: static const char MESSAGE[] = "Hello, World!\n"; franta-hg@28: franta-hg@29: static const char PATH[] = "./roura"; franta-hg@28: franta-hg@31: static void listener_cb(evutil_socket_t, short, void *); franta-hg@30: static void conn_read_cb(struct bufferevent *, void *); franta-hg@28: static void conn_write_cb(struct bufferevent *, void *); franta-hg@28: static void conn_event_cb(struct bufferevent *, short, void *); franta-hg@28: static void signal_cb(evutil_socket_t, short, void *); franta-hg@38: static void print_socket_info(int); franta-hg@31: franta-hg@28: int main(int argc, char **argv) { franta-hg@28: struct event_base *base; franta-hg@31: evutil_socket_t listener; franta-hg@31: struct event *listener_event; franta-hg@28: struct event *signal_event; franta-hg@28: franta-hg@29: struct sockaddr_un sun; franta-hg@28: franta-hg@31: setvbuf(stdout, NULL, _IONBF, 0); franta-hg@31: franta-hg@28: base = event_base_new(); franta-hg@28: if (!base) { franta-hg@28: fprintf(stderr, "Could not initialize libevent!\n"); franta-hg@28: return 1; franta-hg@28: } franta-hg@28: franta-hg@29: memset(&sun, 0, sizeof (sun)); franta-hg@29: sun.sun_family = AF_UNIX; franta-hg@29: strcpy(sun.sun_path, PATH); franta-hg@28: franta-hg@31: listener = socket(AF_UNIX, SOCK_STREAM, 0); franta-hg@31: evutil_make_socket_nonblocking(listener); franta-hg@28: franta-hg@31: if (bind(listener, (struct sockaddr*) &sun, sizeof (sun)) < 0) { franta-hg@29: fprintf(stderr, "Could not create domain socket: %s!\n", PATH); franta-hg@28: return 1; franta-hg@28: } franta-hg@28: franta-hg@31: if (listen(listener, 16) < 0) { franta-hg@31: fprintf(stderr, "Could not listen\n"); franta-hg@31: return 1; franta-hg@31: } franta-hg@31: franta-hg@39: // identifikátor serverového soketu (v současnosti číslo FD) franta-hg@39: printf("Nasloucháme: sun_path = %s → socketId = %d\n", sun.sun_path, listener); franta-hg@39: franta-hg@31: listener_event = event_new(base, listener, EV_READ | EV_PERSIST, listener_cb, (void*) base); franta-hg@31: franta-hg@31: if (!listener_event) { franta-hg@31: fprintf(stderr, "Could not do event_new\n"); franta-hg@31: return 1; franta-hg@31: } franta-hg@31: franta-hg@31: event_add(listener_event, NULL); franta-hg@31: franta-hg@28: signal_event = evsignal_new(base, SIGINT, signal_cb, (void *) base); franta-hg@28: franta-hg@28: if (!signal_event || event_add(signal_event, NULL) < 0) { franta-hg@28: fprintf(stderr, "Could not create/add a signal event!\n"); franta-hg@28: return 1; franta-hg@28: } franta-hg@28: franta-hg@28: event_base_dispatch(base); franta-hg@28: franta-hg@31: event_free(listener_event); franta-hg@28: event_free(signal_event); franta-hg@28: event_base_free(base); franta-hg@30: franta-hg@32: // smažeme soket na disku / soubor -- jinak by program příště spadl na bind() franta-hg@39: // TODO: co když soket někdo přesune a místo něj dá jiný soubor? franta-hg@29: unlink(PATH); franta-hg@28: franta-hg@28: printf("done\n"); franta-hg@28: return 0; franta-hg@28: } franta-hg@28: franta-hg@31: static void listener_cb(evutil_socket_t listener, short event, void *user_data) { franta-hg@28: struct event_base *base = (event_base *) user_data; franta-hg@28: struct bufferevent *bev; franta-hg@28: franta-hg@31: struct sockaddr_storage ss; franta-hg@31: socklen_t slen = sizeof (ss); franta-hg@31: int fd = accept(listener, (struct sockaddr*) &ss, &slen); franta-hg@31: if (fd < 0) { franta-hg@31: fprintf(stderr, "Unable to accept(): %d", fd); franta-hg@31: return; franta-hg@31: } else if (fd > FD_SETSIZE) { franta-hg@38: // FD_SETSIZE = 1024 -- Proč? Co když bude spojení víc? franta-hg@39: fprintf(stderr, "fd (%d) > FD_SETSIZE (%d)", fd, FD_SETSIZE); franta-hg@31: close(fd); franta-hg@31: return; franta-hg@31: } franta-hg@31: franta-hg@31: evutil_make_socket_nonblocking(fd); franta-hg@39: franta-hg@38: print_socket_info(fd); franta-hg@31: franta-hg@31: bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); franta-hg@28: if (!bev) { franta-hg@28: fprintf(stderr, "Error constructing bufferevent!"); franta-hg@28: event_base_loopbreak(base); franta-hg@28: return; franta-hg@28: } franta-hg@39: franta-hg@39: // identifikátor navázaného spojení (v současnosti číslo FD) franta-hg@39: int * connectionId = (int*) malloc(sizeof (fd)); franta-hg@39: *connectionId = fd; franta-hg@39: franta-hg@39: franta-hg@39: bufferevent_setcb(bev, conn_read_cb, conn_write_cb, conn_event_cb, (void*) connectionId); franta-hg@30: bufferevent_enable(bev, EV_READ | EV_WRITE); franta-hg@28: franta-hg@39: printf("někdo se k nám připojil! socketId = %d → connectionId = %d / bev = %p\n", listener, *connectionId, bev); franta-hg@28: franta-hg@28: bufferevent_write(bev, MESSAGE, strlen(MESSAGE)); franta-hg@28: } franta-hg@28: franta-hg@30: static void conn_read_cb(struct bufferevent *bev, void *user_data) { franta-hg@39: printf("conn_read_cb: connectionId = %d\n", *((int*) user_data)); franta-hg@34: franta-hg@30: /* This callback is invoked when there is data to read on bev. */ franta-hg@30: struct evbuffer *input = bufferevent_get_input(bev); franta-hg@30: struct evbuffer *output = bufferevent_get_output(bev); franta-hg@33: struct event_base *base = bufferevent_get_base(bev); franta-hg@30: franta-hg@30: size_t len = evbuffer_get_length(input); franta-hg@32: char *data = (char*) malloc(len); franta-hg@30: evbuffer_copyout(input, data, len); franta-hg@32: printf("we got some data: %s\n", data); franta-hg@31: franta-hg@30: if (memcmp(data, "exit\n", len) == 0) { franta-hg@30: struct timeval delay = {2, 123}; franta-hg@33: printf("Klient říká, že máme končit; ukončuji program během %ld sekund a %ld mikrosekund.\n", delay.tv_sec, delay.tv_usec); franta-hg@30: event_base_loopexit(base, &delay); franta-hg@30: } franta-hg@31: franta-hg@32: evbuffer_add(output, "echo: ", 6); franta-hg@30: /* Copy all the data from the input buffer to the output buffer. */ franta-hg@30: evbuffer_add_buffer(output, input); franta-hg@30: free(data); franta-hg@30: } franta-hg@30: franta-hg@28: static void conn_write_cb(struct bufferevent *bev, void *user_data) { franta-hg@39: printf("conn_write_cb: connectionId = %d\n", *((int*) user_data)); franta-hg@34: franta-hg@28: struct evbuffer *output = bufferevent_get_output(bev); franta-hg@28: if (evbuffer_get_length(output) == 0) { franta-hg@28: printf("flushed answer / %p\n", bev); franta-hg@31: /* nebudeme ukončovat spojení franta-hg@28: bufferevent_free(bev); franta-hg@31: */ franta-hg@28: } franta-hg@28: } franta-hg@28: franta-hg@28: static void conn_event_cb(struct bufferevent *bev, short events, void *user_data) { franta-hg@39: int connectionId = *((int*) user_data); franta-hg@39: printf("conn_event_cb: connectionId = %d\n", connectionId); franta-hg@38: franta-hg@28: if (events & BEV_EVENT_EOF) { franta-hg@39: printf("Connection closed: connectionId = %d\n", connectionId); franta-hg@28: } else if (events & BEV_EVENT_ERROR) { franta-hg@39: printf("Got an error on the connectionId = %d: %s\n", connectionId, strerror(errno)); franta-hg@28: } franta-hg@29: franta-hg@28: // None of the other events can happen here, since we haven't enabled timeouts franta-hg@28: bufferevent_free(bev); franta-hg@39: free(user_data); franta-hg@28: } franta-hg@28: franta-hg@28: static void signal_cb(evutil_socket_t sig, short events, void *user_data) { franta-hg@28: struct event_base *base = (event_base *) user_data; franta-hg@28: struct timeval delay = {2, 123}; franta-hg@28: franta-hg@28: printf("Zachycen SIGINT (Ctrl+C); ukončuji program během %ld sekund a %ld mikrosekund.\n", delay.tv_sec, delay.tv_usec); franta-hg@28: franta-hg@28: event_base_loopexit(base, &delay); franta-hg@28: } franta-hg@38: franta-hg@38: static void print_socket_info(int fd) { franta-hg@38: struct ucred cr; franta-hg@38: unsigned int cl = sizeof (cr); franta-hg@38: franta-hg@38: if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) == 0) { franta-hg@38: printf("připojený klient: pid=%d, uid=%d, gid=%d\n", cr.pid, cr.uid, cr.gid); franta-hg@38: } franta-hg@38: }