Skip to content

Instantly share code, notes, and snippets.

@rsouth
Created June 5, 2021 09:21
Show Gist options
  • Save rsouth/9d90719da4ffab0cb595e90f62cc81c0 to your computer and use it in GitHub Desktop.
Save rsouth/9d90719da4ffab0cb595e90f62cc81c0 to your computer and use it in GitHub Desktop.
untitled1.dev | timeserver | server.c
#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