Created
June 5, 2021 09:21
-
-
Save rsouth/9d90719da4ffab0cb595e90f62cc81c0 to your computer and use it in GitHub Desktop.
untitled1.dev | timeserver | server.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 <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
#include <time.h> | |
#include <unistd.h> | |
/* child process, connection handler */ | |
int handle_connection(int remote_sock_fd); | |
/* child process, command handler */ | |
int handle_command(int sock_fd, char* command); | |
/* parent process, handling new connection */ | |
void handle_client(int remote_sock_fd); | |
/* utility for checking which command was received */ | |
int is_command(char* input, char* cmd); | |
int nanosleep(const struct timespec* rqtp, struct timespec* rmtp); | |
struct timespec timespec_ms(int ms); | |
char* dt_str(); | |
int main(void) { | |
char* SOCK_PATH = "test.socket\n"; | |
struct sockaddr_un local, remote; | |
int sock_fd = socket(AF_UNIX, // specify `domain socket` | |
SOCK_STREAM, // TCP (SOCK_DGRAM for UDP) | |
0); // automatic protocol resolution | |
if (!sock_fd) { | |
perror("socket"); | |
return EXIT_FAILURE; | |
} | |
// set up the local socket and unlink the local path if it exists already | |
local.sun_family = AF_UNIX; | |
strcpy(local.sun_path, SOCK_PATH); | |
unlink(local.sun_path); | |
// attempt to bind on the socket | |
int len = strlen(local.sun_path) + sizeof(local.sun_family); | |
if (bind(sock_fd, (struct sockaddr*)&local, len) == -1) { | |
perror("bind"); | |
return EXIT_FAILURE; | |
} | |
// after MAX_QUEUED_CONNECTIONS are queued, connections will be refused | |
const int MAX_QUEUED_CONNECTIONS = 5; | |
if (listen(sock_fd, MAX_QUEUED_CONNECTIONS) == -1) { | |
perror("listen"); | |
return EXIT_FAILURE; | |
} | |
while (1) { | |
unsigned int t = sizeof(remote); | |
int remote_sock_fd; | |
if ((remote_sock_fd = accept(sock_fd, (struct sockaddr*)&remote, &t)) == -1) { | |
perror("accept"); | |
return EXIT_FAILURE; | |
} | |
int cpid = fork(); | |
if (cpid < 0) { | |
// failed to fork() | |
perror("fork"); | |
return EXIT_FAILURE; | |
} else if (cpid == 0) { | |
// inside the child proc | |
handle_connection(remote_sock_fd); | |
} else { | |
// inside the parent process | |
handle_client(remote_sock_fd); | |
} | |
} | |
return EXIT_SUCCESS; | |
} | |
/* child process; handling connections */ | |
int handle_connection(int remote_sock_fd) { | |
int is_error = 0, read_count; | |
char str[100]; | |
do { | |
read_count = recv(remote_sock_fd, str, 100, 0); | |
if (read_count <= 0) { | |
perror("recv"); | |
is_error = 1; | |
} | |
// parse and handle the message | |
if (!is_error) { | |
printf("Got Command: %s\n", str); | |
handle_command(remote_sock_fd, str); | |
} | |
} while (!is_error); | |
printf("Exiting child for remote_sock_fd %d\n", remote_sock_fd); | |
close(remote_sock_fd); | |
return EXIT_SUCCESS; | |
} | |
/* child process - handling commmands */ | |
int handle_command(int sock_fd, char* command) { | |
printf("Got command from %d -> %s\n", sock_fd, command); | |
int is_error = 0; | |
if (is_command(command, "publish-time\n")) { | |
struct timespec ts_ms = timespec_ms(2000); | |
while (is_error == 0) { | |
// sleep | |
nanosleep(&ts_ms, &ts_ms); | |
// create message TIME|<timestamp> | |
char* time = dt_str(); | |
char msg[strlen(time) + 5]; | |
strcpy(msg, "TIME|"); | |
strcat(msg, time); | |
if (send(sock_fd, msg, strlen(msg), 0) == -1) { | |
perror("send"); | |
is_error = 1; | |
} | |
} | |
} | |
return EXIT_SUCCESS; | |
} | |
/* parent process; track new connections */ | |
void handle_client(int client_fd) { | |
printf("Added new client fd %d\n", client_fd); | |
} | |
int is_command(char* input, char* cmd) { | |
printf("Comparing %lu [%s] vs %lu [%s]\n", strlen(input), input, strlen(cmd), cmd); | |
return strlen(input) == strlen(cmd) && strcmp(input, cmd) == 0; | |
} | |
char* dt_str() { | |
time_t t; | |
time_t x_t = time(&t); | |
struct tm* tm = gmtime(&x_t); | |
return asctime(tm); | |
} | |
struct timespec timespec_ms(int ms) { | |
struct timespec ts; | |
ts.tv_sec = ms / 1000; | |
ts.tv_nsec = (ms % 1000) * 1000000; | |
return ts; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment