back to scratko.xyz
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/server.c b/server.c
new file mode 100644
index 0000000..57300eb
--- /dev/null
+++ b/server.c
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifndef INBUFSIZE
+#define INBUFSIZE 1024
+#endif
+
+#ifndef LISTEN_QLEN
+#define LISTEN_QLEN 32
+#endif
+
+struct thread_data {
+ int counter;
+ pthread_mutex_t mutex;
+ sem_t semaphore;
+ int fd;
+};
+
+static void change_counter(char *buffer, pthread_mutex_t *mutex, int *counter,
+ int fd)
+{
+ int tmp_counter = 0;
+ char counter_buffer[13];
+
+ if(!strcmp(buffer, "up")) {
+ pthread_mutex_lock(mutex);
+ ++*counter;
+ pthread_mutex_unlock(mutex);
+ write(fd, "Ok\n", strlen("Ok\n"));
+ } else if(!strcmp(buffer, "down")) {
+ pthread_mutex_lock(mutex);
+ --*counter;
+ pthread_mutex_unlock(mutex);
+ write(fd, "Ok\n", strlen("Ok\n"));
+ } else if(!strcmp(buffer, "show")) {
+ pthread_mutex_lock(mutex);
+ tmp_counter = *counter;
+ pthread_mutex_unlock(mutex);
+ sprintf(counter_buffer, "%d\n", tmp_counter);
+ write(fd, counter_buffer, strlen(counter_buffer));
+ } else
+ write(fd, "unknown command\n", strlen("unknown command\n"));
+}
+
+static void *worker_thread(void *data)
+{
+ int data_left, i;
+ char buffer[INBUFSIZE];
+ struct thread_data *local_data = data;
+ pthread_mutex_t *mutex = &local_data->mutex;
+ sem_t *semaphore = &local_data->semaphore;
+ int *counter = &local_data->counter;
+ int fd = local_data->fd;
+ char tmp_symbol;
+
+ sem_post(semaphore);
+ pthread_detach(pthread_self());
+
+ for(;;) {
+ data_left = read(fd, buffer, INBUFSIZE);
+ if(data_left <= 0)
+ break;
+ for(i = 0; i < data_left; ++i) {
+ if(buffer[i] == '\r' || buffer[i] == '\n') {
+ tmp_symbol = buffer[i];
+ buffer[i] = '\0';
+ change_counter(buffer, mutex, counter, fd);
+ if(tmp_symbol == '\r')
+ ++i;
+ if(i + 1 != data_left) {
+ data_left -= i + 1;
+ memmove(buffer, buffer+i+1, data_left);
+ i = -1;
+ } else
+ break;
+ }
+ }
+ }
+ close(fd);
+ return 0;
+}
+
+static void init_data(struct thread_data *data)
+{
+ data->counter = 0;
+ pthread_mutex_init(&data->mutex, NULL);
+ sem_init(&data->semaphore, 0, 0);
+}
+
+int main(int argc, char **argv)
+{
+ int server_socket, opt;
+ unsigned short port;
+ struct sockaddr_in addr;
+ struct thread_data data;
+ pthread_t thr;
+ socklen_t len;
+
+ if(argc != 2) {
+ fprintf(stderr, "usage: ./program <server port> \n");
+ return 1;
+ }
+ port = strtol(argv[1], NULL, 10);
+ server_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if(server_socket == -1) {
+ perror("socket");
+ return 0;
+ }
+ opt = 1;
+ setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(port);
+
+ if(bind(server_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
+ perror("bind");
+ return 1;
+ }
+
+ listen(server_socket, LISTEN_QLEN);
+ len = sizeof(addr);
+ init_data(&data);
+
+ for(;;) {
+ data.fd = accept(server_socket, (struct sockaddr*) &addr, &len);
+ pthread_create(&thr, NULL, worker_thread, &data);
+ sem_wait(&data.semaphore);
+ }
+ return 0;
+}