back to scratko.xyz
aboutsummaryrefslogtreecommitdiff
path: root/server.c
blob: 57300eb4fd9c400cf6b5c2dc474ecd859ffe4b35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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;
}