-
Notifications
You must be signed in to change notification settings - Fork 0
/
launch-server.c
165 lines (121 loc) · 5.38 KB
/
launch-server.c
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* @file pps-launch-server.c
* @brief A server in the DHT
*
*/
// standard includes (printf, exit, ...)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // for itoa
// for basic socket communication
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "config.h" // for PPS_DEFAULT_IP and PPS_DEFAULT_PORT
#include "system.h" // for get_socket, get_server_addr & bind_server
#include "hashtable.h" // for add_Htable_value & get_Htable_value
#define MAX_IP_SIZE 15
#define PORT_SIZE 1
void serve_get_request(Htable_t table, char *in_msg, int s, struct sockaddr_in cli_addr, socklen_t addr_len) {
//Get value corresponding to key
pps_value_t value = get_Htable_value(table, in_msg);
if (value != NULL) {
sendto(s, value, strlen(value), 0, (struct sockaddr *) &cli_addr, addr_len);
} else {
//No value found
sendto(s, '\0', 1, 0, (struct sockaddr *) &cli_addr, addr_len);
}
}
void serve_write_request(Htable_t table, char *in_msg, int s, struct sockaddr_in cli_addr, socklen_t addr_len) {
//in_msg is initialized with zeros, only overwritten by the key and the value
if (add_Htable_value(table, in_msg, in_msg + strlen(in_msg) + 1) == ERR_NONE) {
// Send response back to sender (an empty datagram)
sendto(s, NULL, 0, 0, (struct sockaddr *) &cli_addr, addr_len);
}
}
error_code serve_dump_node(Htable_t table, int s, struct sockaddr_in cli_addr, socklen_t addr_len) {
kv_list_t* list = get_Htable_content(table);
M_REQUIRE_NON_NULL_CUSTOM_ERR(list, ERR_NOMEM);
char msg[MAX_MSG_SIZE];
(void) memset(msg, '\0', MAX_MSG_SIZE);
sprintf(msg, "%zu", list->size);
size_t index = strlen(msg) + 1;
size_t index_list = 0;
size_t next_len = 0;
while (index_list < list->size) {
do {
kv_pair_t current = list->elems[index_list];
size_t key_len = strlen(current.key);
strncpy(msg + index, current.key, key_len);
index += key_len + 1;
size_t value_len = strlen(current.value);
strncpy(msg + index, current.value, value_len);
index += value_len + 1;
index_list += 1;
if (index_list < list->size) {
next_len = strlen(list->elems[index_list].key) + strlen(list->elems[index_list].value) + 2;
}
} while (index_list < list->size && next_len < MAX_MSG_SIZE - index);
sendto(s, msg, index, 0, (struct sockaddr *) &cli_addr, addr_len);
(void) memset(msg, '\0', MAX_MSG_SIZE);
index = 0;
}
kv_list_free(list);
return ERR_NONE;
}
int main(void) {
char ip_addr[MAX_IP_SIZE + 1];
int port = 0;
printf("IP port?");
fflush(stdout);
M_EXIT_IF((scanf("%s %u", ip_addr, &port) != 2), ERR_NOT_FOUND, "scanf", "%s", "error on reading IP address");
M_EXIT_IF(port < 0 || port > UINT16_MAX, ERR_BAD_PARAMETER, "port", "%s", "wrong size");
// Set up socket (without timeout, for servers).
int s = get_socket(0);
M_EXIT_IF(s == -1, ERR_NETWORK, "get socket", "%s", "problem with socket");
// Load server address.
/** sockadrr is a generic descriptor for any kind of socket operation, whereas sockaddr_in is specific
* for IP-based communication
*/
struct sockaddr_in srv_addr;
error_code error = get_server_addr(ip_addr, (uint16_t) port, &srv_addr);
M_EXIT_IF_ERR(error, "failed to get server address");
// Bind server to the address:port
error = bind_server(s, ip_addr, (uint16_t) port);
M_EXIT_IF_ERR(error, "failed to bind server address");
// Create and initialize new empty Htable
Htable_t table = construct_Htable(HTABLE_SIZE);
M_REQUIRE_NON_NULL_CUSTOM_ERR(table, ERR_NOMEM);
char in_msg[MAX_MSG_SIZE];
// Receive messages forever.
while (1) {
(void) memset(in_msg, '\0', MAX_MSG_SIZE);
// Receive message and get return address.
struct sockaddr_in cli_addr;
socklen_t addr_len = sizeof(cli_addr);
// Create appropriate buffer to receive message
ssize_t in_msg_len = recvfrom(s, in_msg, MAX_MSG_SIZE, 0, (struct sockaddr *) &cli_addr, &addr_len);
if (in_msg_len != -1) {
char *nul = memchr(in_msg, '\0', (size_t) in_msg_len);
/** Here, we check if the message is empty -> it's a message to check if the server is responsive (pps-list-nodes) */
if (in_msg_len == 0) {
sendto(s, NULL, 0, 0, (struct sockaddr *) &cli_addr, addr_len);
/** Here, we check if the message is of length 1 -> print all key-value pairs associated to the node (pps-dump-node) */
} else if (in_msg_len == 1 && strncmp("\0", in_msg, 1) == 0) {
serve_dump_node(table, s, cli_addr, addr_len);
} else {
/** Here, we check if the message contains a nul character.
* If it does, it's a write request -> add the value associated with the key to the Htable.
* If it doesn't, it's a read request -> send the value associated with the key received.
*/
if (nul != NULL) {
serve_write_request(table, in_msg, s, cli_addr, addr_len);
} else {
serve_get_request(table, in_msg, s, cli_addr, addr_len);
}
}
}
}
return 0;
}