-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathservermain.cpp
More file actions
319 lines (263 loc) · 9.5 KB
/
servermain.cpp
File metadata and controls
319 lines (263 loc) · 9.5 KB
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*
** servermain.cpp -- server serving city to state translation to multiple clients
*/
// Header Files
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <sstream>
using namespace std;
namespace patch
{
template < typename T > std::string to_string( const T& n )
{
std::ostringstream stm ;
stm << n ;
return stm.str() ;
}
}
// template<typename Map>
// Definations
// 33 + 504 (last 3 digit of id)
#define PORT "33504"
// connection queue
#define BACKLOG 10
// Max number of bytes we can get at once
#define MAXDATASIZE 1024
// Utility Functions
// Funtion to print map data structure
// void print_map(Map& m)
// {
// cout << "[ ";
// for (auto &item : m) {
// cout << item.first << ":" << item.second << " ";
// }
// cout << "]\n";
// }
// Function to kill zombie processes
void sigchld_handler(int s)
{
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get IPv4 sockaddr
void *get_in_addr(struct sockaddr *sa)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
// Main Function
int main(void)
{
// COMPUTATION
//Reading and storing data in MAP from list.txt
// initalising Maps (Dictionary)
map<string, string> LocationMap;
map<string, bool> CityPresent;
string states = "";
// opening file in read mode
ifstream myfile("list.txt");
if(myfile.is_open())
{
string line,stateName;
int isState = 1;
while(getline(myfile,line))
{
// If state store it in state variable
if(isState == 1){
stateName = line;
cout << stateName << endl;
states = states + stateName;
states = states + ",";
isState = 0;
}
else {
size_t pos = 0;
string city;
while ((pos = line.find(',')) != string::npos) {
city = line.substr(0, pos);
if(!CityPresent[city]) {
CityPresent.erase(city);
cout << city << endl;
}
CityPresent.insert(make_pair(city, true));
LocationMap.insert(make_pair(city, stateName));
line.erase(0, pos + 1);
}
LocationMap.insert(make_pair(line, stateName));
isState = 1;
}
}
myfile.close();
cout << "Main server has read the state list from list.txt" << endl;
}
else {
cout << "Unable to open list.txt file" << endl;
exit(1);
}
// COMMUNICATION
// sockfd: server socket descriptor
// new_fd: connected socket descriptor
int sockfd, new_fd;
// Intializing structs
// hints: to initialize addrinfo struct
// servinfo: complete addrinfo struct
// their_addr: sockaddr_storage struct to store address information of incoming connection
// struct addrinfo {
// int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
// int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
// int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
// int ai_protocol; // use 0 for "any"
// size_t ai_addrlen; // size of ai_addr in bytes
// struct sockaddr *ai_addr; // struct sockaddr_in or _in6
// char *ai_canonname; // full canonical hostname
// struct addrinfo *ai_next; // linked list, next node
// };
// struct sockaddr {
// unsigned short sa_family; // address family, AF_xxx
// char sa_data[14]; // 14 bytes of protocol address
// };
// struct sockaddr_in {
// short int sin_family; // Address family, AF_INET
// unsigned short int sin_port; // Port number
// struct in_addr sin_addr; // Internet address
// unsigned char sin_zero[8]; // Same size as struct sockaddr
// };
// struct in_addr {
// uint32_t s_addr; // that's a 32-bit int (4 bytes)
// };
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
// Helper variables
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET_ADDRSTRLEN];
int rv;
// Populate hints to initial values (TCP)
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// Populate servinfo using hints, ip and port
// servinfo will be pointer to link list
if ((rv = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// Loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
// Create Socket
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("Server: Socket creation failed!");
continue;
}
// For Socket to use given port
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("Server: Couldnt force socket to desired port!");
exit(1);
}
// Bind Socket to given ip address and port number
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("Server: Unable to bind socket to given ip and port!");
continue;
}
break;
}
// Free servinfo struct, its work is done
freeaddrinfo(servinfo);
// None of the results from getaddrinfo could bind a socket
if (p == NULL) {
fprintf(stderr, "Server: failed to create and bind for any results\n");
exit(1);
}
// Listen for connections
if (listen(sockfd, BACKLOG) == -1) {
perror("Server: Couldnt listen for connections");
exit(1);
}
cout << "Main server is up and running." << endl;
// Reap all dead/zombie processes
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
int client_id = 0;
// Wait Loop
while(1) {
client_id += 1;
// Accept incoming connection
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("Server: Couldnt accept incoming connection");
continue;
}
// Converting ip address from binary to presentable format
int client_port;
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
// printf("Server: Got connection from %s, port %d\n", s, ((struct sockaddr_in*)&their_addr)->sin_port);
client_port = ((struct sockaddr_in*)&their_addr)->sin_port;
// Create fork for child process
if (!fork()) {
// Child doesn't need the listener
close(sockfd);
// Child handeling (do chat infinately)
while(1) {
// Input Buffer Sized and Buffer
int numbytes;
char buf[MAXDATASIZE];
// Recieve Query from Client (get city name as response)
if ((numbytes = recv(new_fd, buf, MAXDATASIZE, 0)) != -1) {
buf[numbytes] = '\0';
cout << "Main server has recieved the request on city " << buf << " from client " << client_id << " using TCP over port " << client_port << endl;
}
else {
cout << "Recieve Failed" << endl;
exit(1);
}
string cityName = buf;
string stateName, response;
// Compute answer to query (get state name from dictionary)
if(LocationMap.find(cityName) != LocationMap.end()) {
stateName = LocationMap[cityName];
cout << cityName << " is associated with state " << stateName << endl;
cout << "Main Server has sent searching result to client " << patch::to_string(client_id) << " using TCP over port " << PORT << endl;
response = "Client has recieved results from the Main Server:\n" + cityName + " is associated with state " + stateName;
}
else{
cout << cityName << " does not show up in states " << states << endl;
cout << "The Main server has sent \"" << cityName << ":Not Found\" to client " << patch::to_string(client_id) << " using TCP over port " << patch::to_string(client_port);
response = cityName + " not found";
}
// Send answer as response to client (send state name or not found message to client)
if(send(new_fd, &response[0], response.length(), 0) == -1) {
cout << "Main server response failed!" << endl;
exit(1);
}
}
// Close Child
close(new_fd);
exit(0);
}
// Parent process doesnt need new_fd
close(new_fd);
}
return 0;
}