Skip to content

Instantly share code, notes, and snippets.

@Asmod4n
Created May 23, 2019 14:06
Show Gist options
  • Save Asmod4n/0ebec8e432a92607656afc3a7dbb806a to your computer and use it in GitHub Desktop.
Save Asmod4n/0ebec8e432a92607656afc3a7dbb806a to your computer and use it in GitHub Desktop.
echo tcp server example with libdispatch in c
#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