-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.c
286 lines (255 loc) · 9.29 KB
/
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
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
/*
* server.c
*
* Created on: Oct 15, 2010
* Author: kaduparag
*/
//-----------------------------------------------------------------------------------
#include "server.h"
//---------------------------GLOBAL----------------------------------------------------
int interfaceCount = 0;
int socketDescriptors[MAX_INTERFACE];//TODO Make MAX_INTERFACE dynamic by using getInterfaceInfo().
int server_port, max_win_size;
int TIMEOUT_SEC=1;
int TIMEOUT_USEC=0;
struct client_info *clientListHead=NULL;
struct interface_info *ifihead=NULL;
//----------------------------------------------------------------------------------
int mydg_echo(int ,const char *);
//-------------------------------------------------------------------------------
struct interface_info * getInterfaceInfo() {
/*
struct interface_info *ifi;
ifi = calloc(1, sizeof(struct interface_info));
if (ifi == NULL) {
err_sys_p("calloc error");
}
char str[INET_ADDRSTRLEN];
strcpy(ifi->ifi_name, "localhost");
strcpy(str, "127.0.0.1");
ifi->ifi_addr = calloc(1, sizeof(struct sockaddr));
if (inet_pton(AF_INET, str, ifi->ifi_addr) != 1) {
err_sys_p("Cannot convert string IP to binary IP.");
}
return ifi;
*/
}
//--------------------------------------------------------------------------------
int main(int argc, char **argv) {
int i;
const int on = 1;
pid_t pid;
int child_pid;
struct interface_info *ifi,*node;
struct sockaddr_in *sa;
//I/O Multiplexing Select options
int maxfdp1,j;
fd_set rset;
int maxSocketDescriptor = -999;
char serverIP[INET_ADDRSTRLEN];
printf("<start>\n");
// if (argc != 2) //TODO Uncomment
// err_sys_p("usage: server <server.in file>");
//Read input configuration from server.in
char line[MAX_LINE];
FILE* fp = fopen("server.in", "r"); //TODO read from argv[1]
if (fgets(line, sizeof(line), fp)) {//Line 1 server port
server_port = atoi(line);
if (server_port == 0) {
err_sys_p(
"Invalid or missing server port number in the configuration file.");
}
printf("[INFO] Server port:%d\n", server_port);
} else {
err_sys_p("Invalid or missing input configuration.");
}
if (fgets(line, sizeof(line), fp)) {//Line 2 maximum sliding window size.
max_win_size = atoi(line);
if (max_win_size == 0) {
err_sys_p(
"Invalid or missing Max win size in the configuration file.");
}
printf("[INFO] Max win size port:%d\n", max_win_size);
} else {
err_sys_p("Invalid or missing input configuration.");
}
fclose(fp);
generate_ifi_list(&ifihead);
ifi=ifihead;
for (; ifi != NULL; ifi = ifi->ifi_next) {
/*bind unicast address */
socketDescriptors[interfaceCount] = socket(AF_INET, SOCK_DGRAM, 0);
if (socketDescriptors[interfaceCount] < 0) {
err_sys_p("socket error.");
}
if (setsockopt(socketDescriptors[interfaceCount], SOL_SOCKET,
SO_REUSEADDR, &on, sizeof(on)))
err_sys_p("Couldnt set Echo socket option");
sa = &ifi->ifi_addr;
sa->sin_family = AF_INET;
sa->sin_port = htons(server_port);
if (bind(socketDescriptors[interfaceCount], (struct sockaddr *) sa, sizeof(*sa)))
err_sys_p("Coudlnt bind socket.");
printf("[INFO] Bounded to %s\n", Sock_ntop((struct sockaddr *) sa,sizeof(*sa)));
interfaceCount++;
}
printf("[INFO] Total number of interfaces: %d\n", interfaceCount);
//interfaceCount =1; //ugly hack
//Using select monitor different sockets bounded to available unicast interfaces.
for (;;) {
//printf("[INFO] Parent server waiting for incoming requests...\n"); //TODO Uncomment info
FD_ZERO(&rset);
for (i = 0; i < interfaceCount; i++) {
FD_SET(socketDescriptors[i], &rset);
maxSocketDescriptor = max(maxSocketDescriptor,socketDescriptors[i]);
}
maxfdp1 = maxSocketDescriptor + 1;
select(maxfdp1, &rset, NULL, NULL, NULL);
for (i = 0; i < interfaceCount; i++) {
if (FD_ISSET(socketDescriptors[i], &rset)) { // one of the socket descriptor is ready
//fork a child
if ((pid = fork()) == 0) { // child
j=0;
node=ifihead;
while(j<i) node= node->ifi_next;
child_pid = mydg_echo(socketDescriptors[i],inet_ntoa(node->ifi_addr.sin_addr));
printf("[INFO] Child server %d closed.\n", child_pid);
exit(0);
} else if (pid == -1) {
err_sys_p("Couldnt fork a child.");
} else {
//parent. DO nothing
}
// child_pid = mydg_echo(socketDescriptors[i],"127.0.0.1");
}
}
}
return 0;
}
//----------------------------------------------------------------------------------
int mydg_echo(int sockfd,const char * myaddr) {
int n, i, connection_sockfd,success_flag,attempt_count,ret,on=1;
char *filename, con_sock_port[8];//TODO con_sock_port size? FILE_NAME_LEN?
char *sendline, *recvline;
struct in_addr closest;
socklen_t addrlen,clilen;
struct sockaddr_in localaddr,cliaddr;
sendline = malloc(MAXLINE);
recvline = malloc(MAXLINE);
filename = malloc(MAXLINE);
//Close all other socket descriptor
for (i = 0; i < interfaceCount; i++) {
if (socketDescriptors[i] != sockfd)
close(socketDescriptors[i]);
}
//Read filename from client
clilen=sizeof(cliaddr);
n = recvfrom(sockfd, filename, MAXLINE, 0, (struct sockaddr *) &cliaddr, &clilen);
if (n < 0) {
err_sys_p("Data receive error.");
}
filename[n] = 0; //null terminate
//Get the ipaddr, port number from the client
struct sockaddr_in *sin = (struct sockaddr_in *) &cliaddr;
ret= closest_match_to_interface(ifihead, inet_ntoa(sin->sin_addr),&closest);
if(ret==1)
{
//localhost
}
else if(ret==2)
{
//Dont route
if(setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, (void *) &on, sizeof(on)) < 0)
err_sys_p("Can't set SO_DONTROUTE on main socket");
}
else
{
//Dont care
}
//Check for already active client
if(isNewClient(clientListHead,sin->sin_addr.s_addr,ntohs(sin->sin_port))){
printf("[DEBUG] New client...inserting\n");
//insert into the client list
insertClient(&clientListHead,sin->sin_addr.s_addr,ntohs(sin->sin_port));
printf("Client inserted:%d %d\n",clientListHead->ipaddr,clientListHead->port);
}else{ // End this child process.Client already handled by other child process.
printf("[DEBUG] Client already present...\n");
exit(0);
}
printf("[INFO] Child server %d datagram from %s", getpid(), Sock_ntop(
(struct sockaddr *) &cliaddr, clilen));
printf(", to %s\n", myaddr);
printf("[INFO] File requested %s\n", filename);
//Start a new connection socket at ephemeral port.
connection_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(connection_sockfd < 0){
err_sys_p("Connection socket error.Cannot open the socket.");
}
bzero(&localaddr, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(0);
if (inet_pton(AF_INET, myaddr, &localaddr.sin_addr) != 1) //Using the same IP as the parent listening socket
err_sys_p("Cannot convert string IP to binary IP.");
if (bind(connection_sockfd, (struct sockaddr *) &localaddr,
sizeof(localaddr)))
err_sys_p("Coudlnt bind socket.");
//
// printf("[INFO] Bounded to %s\n", Sock_ntop((struct sockaddr *) &localaddr,
// sizeof(localaddr)));
addrlen=sizeof(localaddr);
//Get the ephemeral port number.
getsockname(connection_sockfd, (struct sockaddr *) &localaddr, &addrlen);
sprintf(con_sock_port, "%d", ntohs(localaddr.sin_port));
//Print connection socket information
printf("[INFO] Connection socket IP %s", myaddr);
printf(", ephemeral port %s\n", con_sock_port);
// getchar();
//Send the new connection socket ephemeral port.
if ((n = sendto(sockfd, con_sock_port, strlen(con_sock_port), 0, (struct sockaddr *) &cliaddr,
clilen)) != strlen(con_sock_port)) { //using the parent listening socket
err_sys_p("Data send error.");
}
success_flag=0;
for(attempt_count=0;attempt_count<MAX_ATTEMPT;attempt_count++){
if(readable_timeout(connection_sockfd,TIMEOUT_SEC,TIMEOUT_USEC)==0){
printf("Socket timeout...attempt %d failed.\n",attempt_count);
//Send the new connection socket ephemeral port.
if ((n = sendto(sockfd, con_sock_port, strlen(con_sock_port), 0, (struct sockaddr *) &cliaddr,
clilen)) != strlen(con_sock_port)) { //using the parent listening socket
err_sys_p("Data send error.");
}
}else{
success_flag=1;
break;
}
}
if(success_flag==0){//TODO what to do if MAX_ATTEMT fail? report and end prgm?
err_sys_p("Socket timeout...max no. of attempt failed.\n");
}
//Wait for connected ack
n = recvfrom(connection_sockfd, recvline, MAXLINE, 0, (struct sockaddr *) &cliaddr, &clilen);
if (n < 0) {
err_sys_p("Data receive error.");
}
recvline[n] = 0; //null terminate
printf("%s\n",recvline);
fflush(NULL);
//Send the file on connection socket and close the parent listening socket
close(sockfd);
if (sendto(connection_sockfd, filename, strlen(filename), 0, (struct sockaddr *) &cliaddr, clilen)
!= strlen(filename)) { //using the parent listening socket
err_sys_p("Data send error.");
}
if (sendto(connection_sockfd, 0, 0, 0, (struct sockaddr *) &cliaddr, clilen) != 0) { //using the parent listening socket
err_sys_p("Data send error.");
}
free(recvline);
free(sendline);
free(filename);
//Client handling done. Remove from the client list
printClientList(clientListHead);
deleteClient(&clientListHead,sin->sin_addr.s_addr,ntohs(sin->sin_port));
printClientList(clientListHead);
return getpid();
}
/* end mydg_echo */