Created
May 23, 2019 14:06
-
-
Save Asmod4n/0ebec8e432a92607656afc3a7dbb806a to your computer and use it in GitHub Desktop.
echo tcp server example with libdispatch in c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <dispatch/dispatch.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <string.h> | |
#include <signal.h> | |
#include <netinet/tcp.h> | |
#include <sys/types.h> | |
#include <sys/time.h> | |
#include <sys/resource.h> | |
#include <limits.h> | |
static void set_limit(void) { | |
struct rlimit limit; | |
if (getrlimit(RLIMIT_NOFILE, &limit) < 0) { | |
perror("getrlimit"); | |
exit(EXIT_FAILURE); | |
} | |
limit.rlim_cur = (OPEN_MAX < limit.rlim_max ? OPEN_MAX : limit.rlim_max); | |
if (setrlimit(RLIMIT_NOFILE, &limit) < 0) { | |
perror("setrlimit"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static dispatch_fd_t | |
make_server(void) | |
{ | |
dispatch_fd_t sock = socket(PF_INET, SOCK_STREAM, 0); | |
if (sock < 0) { | |
perror("socket"); | |
exit(EXIT_FAILURE); | |
} | |
int reuseaddr = 1; | |
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) < 0) { | |
perror("setsockopt"); | |
exit(EXIT_FAILURE); | |
} | |
int nodelay = 1; | |
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) { | |
perror("setsockopt"); | |
exit(EXIT_FAILURE); | |
} | |
int flags = fcntl(sock, F_GETFL, 0); | |
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { | |
perror("fcntl"); | |
exit(EXIT_FAILURE); | |
} | |
struct sockaddr_in name; | |
name.sin_family = AF_INET; | |
name.sin_port = 0; | |
name.sin_addr.s_addr = htonl(INADDR_ANY); | |
if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { | |
perror("bind"); | |
exit(EXIT_FAILURE); | |
} | |
if (listen(sock, OPEN_MAX) < 0) { | |
perror("listen"); | |
exit(EXIT_FAILURE); | |
} | |
socklen_t len = sizeof(name); | |
if (getsockname(sock, (struct sockaddr *)&name, &len) < 0) { | |
perror("getsockname"); | |
exit(EXIT_FAILURE); | |
} | |
printf("port number %d\n", ntohs(name.sin_port)); | |
return sock; | |
} | |
int main(void) { | |
set_limit(); | |
dispatch_queue_t server_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); | |
dispatch_queue_t signal_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); | |
dispatch_fd_t server = make_server(); | |
dispatch_source_t server_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, server, 0, server_q); | |
dispatch_source_set_cancel_handler(server_source, ^() { | |
close(server); | |
}); | |
dispatch_source_set_event_handler(server_source, ^{ | |
dispatch_fd_t client = accept(server, NULL, NULL); | |
if (client < 0) { | |
perror("accept"); | |
return; | |
} | |
dispatch_io_t channel = dispatch_io_create(DISPATCH_IO_STREAM, client, server_q, ^(int error) { | |
if (error) { | |
fputs(strerror(error), stderr); | |
} | |
close(client); | |
}); | |
dispatch_io_set_low_water(channel, SIZE_MAX); | |
dispatch_io_read(channel, 0, 11, server_q, ^(bool done, dispatch_data_t data, int error) { | |
if (done) { | |
dispatch_io_close(channel, 0); | |
dispatch_release(channel); | |
} | |
if (data && data != dispatch_data_empty) { | |
dispatch_retain(data); | |
dispatch_io_write(channel, 0, data, server_q, ^(bool _done, dispatch_data_t _data, int _error) { | |
if (_done) { | |
dispatch_release(data); | |
} | |
}); | |
} | |
}); | |
}); | |
dispatch_group_t bye = dispatch_group_create(); | |
dispatch_source_t term_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, signal_q); | |
dispatch_source_t int_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGINT, 0, signal_q); | |
dispatch_group_enter(bye); | |
dispatch_source_set_event_handler(term_source, ^() { | |
dispatch_source_cancel(server_source); | |
dispatch_source_cancel(int_source); | |
dispatch_source_cancel(term_source); | |
dispatch_group_leave(bye); | |
}); | |
dispatch_source_set_event_handler(int_source, ^() { | |
dispatch_source_cancel(server_source); | |
dispatch_source_cancel(term_source); | |
dispatch_source_cancel(int_source); | |
dispatch_group_leave(bye); | |
}); | |
dispatch_resume(server_source); | |
dispatch_resume(term_source); | |
dispatch_resume(int_source); | |
signal(SIGTERM, SIG_IGN); | |
signal(SIGINT, SIG_IGN); | |
dispatch_group_wait(bye, DISPATCH_TIME_FOREVER); | |
dispatch_release(server_source); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment