-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathftpServer.cpp
399 lines (329 loc) · 9.01 KB
/
ftpServer.cpp
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#include "include/ftpServer.h"
ftpServer::ftpServer(){
lastPort = INITPORT;
socket.setPort(CONTROL_PORT);
socket.setHints(1);
}
int ftpServer::getNewPort(){
lastPort++;
return lastPort;
}
tcpSocket ftpServer::getSocket(){
return socket;
}
tcpSocket ftpServer::getControlSocket(){
return c_socket;
}
tcpSocket ftpServer::getDataSocket(){
return d_socket;
}
void ftpServer::setSocket(tcpSocket socket){
this->socket = socket;
}
void ftpServer::setControlSocket(tcpSocket socket){
this->c_socket = socket;
}
void ftpServer::setDataSocket(tcpSocket socket){
this->d_socket = socket;
}
int ftpServer::sendData(string str){
if(DEBUG)
cout << "Sending data: " << str << endl;
return d_socket.sendMsg(str, 0);
}
int ftpServer::sendData(char* data, int num_bytes){
int bytes_sent = send(d_socket.getSocket(), data, num_bytes, 0);
if(DEBUG)
cout << "Sending data: " << data << endl;
return bytes_sent;
}
int ftpServer::sendControl(string str){
if(DEBUG)
cout << "Sending msg: " << str << endl;
return c_socket.sendMsg(str, 0);
}
string ftpServer::recvControl(int toRead){
string str = c_socket.recvMsg(0, toRead);
if(DEBUG)
cout << "Received msg: " << str << endl;
return str;
}
int ftpServer::recvData(char* data){
int bytes_recv = recv(d_socket.getSocket(), data, MAXBUFFSIZE-1, 0);
return bytes_recv;
}
int ftpServer::start(){
if(socket.bind() != 0){
return 1;
}
if(socket.listen() != 0){
return 2;
}
printf("Successfully started on PORT: %d\n", socket.getPort());
return 0;
}
int ftpServer::acceptClient(){
c_socket = getSocket().accept();
if(c_socket.getSocket() == -1){
return 3;
}
printf("Successfully connected to a client (control port)\n");
client_IP = c_socket.getOtherIp();
return 0;
}
int ftpServer::allocateDataPort(){
int new_port = atoi(recvControl(MAXBUFFSIZE).c_str());
if(DEBUG)
cout << "Got port: " << new_port << endl;
d_socket.setIp(client_IP);
d_socket.setPort(new_port);
d_socket.setHints(0);
if(d_socket.connect() != 0)
return 1;
printf("Successfully connected to client again (data socket): %s\n", client_IP.c_str());
return 0;
}
int ftpServer::sendResponse(){
string cmd = recvControl(MAXBUFFSIZE);
FILE *pf;
string str, responseControl;
char output[MAXBUFFSIZE];
if(DEBUG)
cout << "Got command from client: " << cmd << endl;
if(cmd.substr(0, 3) == "pwd"){
pf = popen(cmd.append(" 2>&1").c_str(), "r");
if(!pf){
sendData(" ");
sendControl("Error occurred while opening pipe for output, calling fork or allocating memory.\n");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
fgets(output, MAXBUFFSIZE-1, pf);
str = output;
sendData(str);
if (pclose(pf) != 0){
sendControl("Incorrect use of pwd \n");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
sendControl("pwd successfully executed in server \n");
cout << "Command successfully executed for client\n";
}
else if(cmd.substr(0, 2) == "ls"){
pf = popen(cmd.append(" 2>&1").c_str(), "r"); //popen does not return stderr file handle. Only stdout. So we are redirecting stderr to stdout
if(!pf){
sendData(" ");
sendControl("Error occurred while opening pipe for output, calling fork or allocating memory.\n");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
while(fgets(output, MAXBUFFSIZE-1, pf)){
if(str.size() + strlen(output) >= MAXBUFFSIZE){
sendData(str);
str = "";
}
str.append(output);
}
str.append(" ");
sendData(str);
if (pclose(pf) != 0){
sendControl("Incorrect use of ls \n");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
sendControl("ls successfully executed in server \n");
cout << "Command successfully executed for client\n";
}
else if(cmd.substr(0, 2) == "cd"){
if(cmd.size() == 2){
char *env = getenv("HOME");
chdir(env);
sendControl("Directory successfully changed \n");
cout << "Command successfully executed for client\n";
return(0);
}
if(cmd.substr(2, 2) == " ~"){
char *env = getenv("HOME");
cmd.replace(3, 1, env);
}
if(chdir(cmd.substr(3).c_str())){
str = "Error occurred while changing directory using cd in server\ncd: ";
str.append(cmd.substr(3)).append(": No such file or directory\n");
sendControl(str);
cout << "Command could NOT be successfully executed for client\n";
}
else {
sendControl("Directory successfully changed \n");
cout << "Command successfully executed for client\n";
}
}
else if(cmd.substr(0, 3) == "put"){
if(fileExists(cmd.substr(4).c_str())){
sendControl("EXISTS");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
sendControl("DNE"); //Does Not Exist
responseControl = recvControl(MAXBUFFSIZE);
if(responseControl == "EMPTY"){
FILE *fp = fopen(cmd.substr(4).c_str(), "w");
fclose(fp);
cout << "Command successfully executed for client\n";
return 0;
}
if(receiveFile(cmd.substr(4))){
sendControl("Error occurred while receiving file in server \n");
cout << "Command could NOT be successfully executed for client\n";
}
else {
sendControl("File successfully received in server \n");
cout << "Command successfully executed for client\n";
}
}
else if(cmd.substr(0, 3) == "get"){
if(!fileExists(cmd.substr(4).c_str())){
sendControl("DNE");
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
sendControl("EXISTS"); //File Exists
if(isEmpty(cmd.substr(4))){
sendControl("EMPTY"); //Empty File
cout << "Command could NOT be successfully executed for client\n";
return(0);
}
sendControl("NEF"); //Not Empty File (NEF)
if(transferFile(cmd.substr(4)) < 0){
sendControl("Error occurred while sending file from server \n");
cout << "Command could NOT be successfully executed for client\n";
}
else {
sendControl("File successfully sent from server \n");
cout << "Command successfully executed for client\n";
}
}
else if(cmd == "quit"){
d_socket.close();
c_socket.close();
cout << "Child Process exiting ... \n";
cout << "Command successfully executed for client\n";
exit(0);
}
else {
sendControl("Invalid command sent to server \n");
}
return 0;
}
int ftpServer::receiveFile(string filename){
char data[MAXBUFFSIZE];
string msgControl;
size_t bytes_recv;
FILE* fp = fopen(filename.c_str(), "w");
if (fp == NULL) {
fputs("File not found\n", stderr);
return 6;
}
while ((bytes_recv = recvData(data)) > 0) {
fwrite(data, 1, bytes_recv, fp);
msgControl = recvControl(4);
if(msgControl == "EOF")
break;
}
if (bytes_recv < 0) {
perror("recv");
}
fclose(fp);
return 0;
}
int ftpServer::transferFile(string filename){
FILE* fp;
char data[MAXBUFFSIZE];
size_t bytes_read, bytes_sent;
long fSize, remaining;
fp = fopen(filename.c_str(), "r");
if (fp == NULL) {
fputs("File not found\n", stderr);
return 7;
}
// obtain file size:
fseek (fp, 0, SEEK_END);
fSize = ftell(fp);
rewind(fp);
remaining = fSize;
do {
bytes_read = fread(data, 1, MAXBUFFSIZE-1, fp);
if (bytes_read < 0) {
fputs("Error in reading the file\n", stderr);
return 8;
}
if ((bytes_sent = sendData(data, bytes_read)) < 0) {
fputs("Error in send function\n", stderr);
return 9;
}
if((unsigned long)remaining == bytes_sent)
sendControl("EOF");
else sendControl("FSR");
fseek(fp, bytes_sent-bytes_read, SEEK_CUR); //As send() function may not send bytes_read amount of data
remaining -= bytes_sent;
} while (remaining > 0);
fclose(fp);
return 0;
}
int ftpServer::handleClients(){
if(start() != 0)
return 1;
while(1){
if(acceptClient() != 0)
return 2;
if(allocateDataPort() != 0)
return 3;
pid_t childPID = fork();
if(childPID == 0) {//child process
//start waiting for the commands and send data
while(1){
printf("\nWaiting for request from client -- \n");
if(sendResponse() != 0){
cout << "Error while sending a response to client" << endl;
break;
}
}
if(DEBUG){
printf("Terminating one of the child of server\n");
exit(0);
}
} else if(childPID < 0) {//error while forking
perror("error while forking");
return 4;
} else {//parent process
continue;
}
}
}
string getStrFromInt(int val){
stringstream str;
str << val;
return str.str();
}
/*To determine if a file exists with a given name*/
int ftpServer::fileExists(const char* filename){
struct stat buffer;
if (stat(filename, &buffer) != -1)
return 1; //File exists
return 0; //File does not exist
}
int ftpServer::isEmpty(string filename){
ifstream file(filename.c_str(), ios::binary | ios::ate);
if(!file.tellg())
return 1; //File is empty;
return 0; //File is not empty
}
int main(){
ftpServer server;
cout << "*********************** \nServer Program for FTP \n***********************\n";
cout << "Amit Mittal & Rahul Radhakrishnan, IIT Guwahati\n\n";
if(server.handleClients() != 0){
cout << "Error while handling clients" << endl;
exit(1);
}
return 0;
}