159 lines
3.6 KiB
C
159 lines
3.6 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/eventfd.h>
|
|
#include <sys/types.h>
|
|
#include <pthread.h>
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
|
|
#define SOCKET_PATH "/tmp/socket"
|
|
#define MAX_CLIENTS 10
|
|
|
|
#define CMD_ECHO 1
|
|
#define CMD_TIMER 2
|
|
|
|
struct request {
|
|
int priority;
|
|
int command;
|
|
int value;
|
|
};
|
|
|
|
typedef struct client_request {
|
|
int client_fd;
|
|
int event_fd;
|
|
struct request req;
|
|
struct client_request *next;
|
|
} client_request_t;
|
|
|
|
client_request_t *queue_head = NULL;
|
|
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
void log_msg(const char *msg) {
|
|
printf("[SERVER] %s\n", msg);
|
|
}
|
|
|
|
void enqueue(client_request_t *node) {
|
|
pthread_mutex_lock(&queue_mutex);
|
|
|
|
if (!queue_head || node->req.priority > queue_head->req.priority) {
|
|
node->next = queue_head;
|
|
queue_head = node;
|
|
} else {
|
|
client_request_t *cur = queue_head;
|
|
while (cur->next && cur->next->req.priority >= node->req.priority)
|
|
cur = cur->next;
|
|
node->next = cur->next;
|
|
cur->next = node;
|
|
}
|
|
|
|
pthread_mutex_unlock(&queue_mutex);
|
|
}
|
|
|
|
client_request_t* dequeue() {
|
|
pthread_mutex_lock(&queue_mutex);
|
|
client_request_t *node = queue_head;
|
|
if (queue_head)
|
|
queue_head = queue_head->next;
|
|
pthread_mutex_unlock(&queue_mutex);
|
|
return node;
|
|
}
|
|
|
|
void* worker_thread(void *arg) {
|
|
while (1) {
|
|
client_request_t *node = dequeue();
|
|
if (!node) {
|
|
usleep(100000);
|
|
continue;
|
|
}
|
|
|
|
struct request *req = &(node->req);
|
|
|
|
char buffer[128];
|
|
sprintf(buffer, "Processing (p: %d, c: %d, v: %d)", req->priority, req->command, req->value);
|
|
log_msg(buffer);
|
|
|
|
int response = 0;
|
|
|
|
if (req->command == CMD_ECHO) {
|
|
response = req->value;
|
|
write(node->client_fd, &response, sizeof(response));
|
|
}
|
|
else if (req->command == CMD_TIMER) {
|
|
sleep(req->value);
|
|
uint64_t val = 1;
|
|
write(node->event_fd, &val, sizeof(val));
|
|
response = 0;
|
|
write(node->client_fd, &response, sizeof(response));
|
|
}
|
|
|
|
free(node);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int recv_fd(int socket) {
|
|
struct msghdr msg = {0};
|
|
char buf[CMSG_SPACE(sizeof(int))];
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
struct iovec io = { .iov_base = "F", .iov_len = 1 };
|
|
|
|
msg.msg_iov = &io;
|
|
msg.msg_iovlen = 1;
|
|
msg.msg_control = buf;
|
|
msg.msg_controllen = sizeof(buf);
|
|
|
|
recvmsg(socket, &msg, 0);
|
|
|
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
|
int fd;
|
|
memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
|
|
return fd;
|
|
}
|
|
|
|
int main() {
|
|
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
struct sockaddr_un addr;
|
|
unlink(SOCKET_PATH);
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sun_family = AF_UNIX;
|
|
strcpy(addr.sun_path, SOCKET_PATH);
|
|
|
|
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
|
|
listen(server_fd, MAX_CLIENTS);
|
|
|
|
log_msg("Server started");
|
|
|
|
pthread_t worker;
|
|
pthread_create(&worker, NULL, worker_thread, NULL);
|
|
|
|
while (1) {
|
|
int client_fd = accept(server_fd, NULL, NULL);
|
|
log_msg("Client connected");
|
|
|
|
int event_fd = recv_fd(client_fd);
|
|
|
|
struct request req = {0, 0, 0};
|
|
read(client_fd, &req, sizeof(struct request));
|
|
|
|
client_request_t *node = malloc(sizeof(client_request_t));
|
|
node->client_fd = client_fd;
|
|
node->event_fd = event_fd;
|
|
node->req = req;
|
|
node->next = NULL;
|
|
|
|
enqueue(node);
|
|
}
|
|
|
|
close(server_fd);
|
|
unlink(SOCKET_PATH);
|
|
return 0;
|
|
}
|