int main(int argc, char **argv) {
struct sockaddr_in sockaddr_in;
struct sockaddr_un sockaddr_un;
int kq;
// compile regex
if (!compile_regex()) {
printf("Regex compilation failed!");
}
init_vars();
if (parse_cmdline_params(argc, argv)) {
return 1;
}
signal(SIGINT, signal_handler);
start_conv_threads();
// Create TCP socket
if (unix_socket[0] != '\0') {
listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
} else {
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
// Set socket options to reuse address and port
int optval = 1;
struct linger timeout;
timeout.l_onoff = 1;
timeout.l_linger = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, &timeout, sizeof(timeout));
setsockopt(listen_sock, SOL_SOCKET, SO_KEEPALIVE, &timeout, sizeof(timeout));
}
if (listen_sock < 0) {
perror("socket");
exit(1);
}
if (unix_socket[0] != '\0') {
// Bind Unix Socket
memset(&sockaddr_un, 0, sizeof(sockaddr_un));
sockaddr_un.sun_family = AF_UNIX;
strncpy(sockaddr_un.sun_path, unix_socket, sizeof(sockaddr_un.sun_path) - 1);
} else {
// Bind socket to port
memset(&sockaddr_in, 0, sizeof(sockaddr_in));
sockaddr_in.sin_family = AF_INET;
sockaddr_in.sin_port = htons(port);
sockaddr_in.sin_addr.s_addr = inet_addr(ip);
}
if (unix_socket[0] != '\0') {
if (bind(listen_sock, (struct sockaddr *)&sockaddr_un, strlen(sockaddr_un.sun_path) +
sizeof(sockaddr_un.sun_len) + sizeof (sockaddr_un.sun_family)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
mode_t socket_permissions = 0666;
if (chmod(unix_socket, socket_permissions) == -1) {
perror("chmod");
exit(EXIT_FAILURE);
}
} else {
if (bind(listen_sock, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
}
// Listen for incoming connections
if (listen(listen_sock, BACKLOG) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// Create kqueue
kq = kqueue();
if (kq < 0) {
perror("kqueue");
exit(EXIT_FAILURE);
}
// Register server socket with kqueue for read events
struct kevent ev;
EV_SET(&ev, listen_sock, EVFILT_READ, EV_ADD, 0, 0, NULL);
if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) {
perror("kevent");
exit(1);
}
// Loop for handling events
while (1) {
struct kevent event;
int n = kevent(kq, NULL, 0, &event, 1, NULL);
if (n < 0) {
perror("kevent");
exit(0);
}
int *arg;
if (event.ident == listen_sock) {
int client_socket = accept(listen_sock, NULL, NULL);
if (client_socket < 0) {
perror("accept");
exit(1);
}
arg = malloc(sizeof(*arg));
*arg = client_socket;
pthread_t tid;
if (pthread_create(&tid, NULL, handle_client, arg) != 0) {
perror("pthread_create");
free(arg);
continue;
}
pthread_detach(tid);
} else if (event.filter == EVFILT_READ) {
pthread_join(*(pthread_t*)event.udata, NULL);
}
}
}