├── .gitignore ├── .vimrc.custom.FTP ├── Makefile ├── README ├── TODO ├── bin ├── client │ └── .empty └── server │ └── .empty ├── client_ftp.c ├── client_ftp.h ├── client_ftp_functions.c ├── commons.c ├── commons.h ├── file_transfer_functions.c ├── file_transfer_functions.h ├── obj └── .empty ├── server_ftp.c ├── server_ftp.h └── server_ftp_functions.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.out 3 | .*.swp 4 | .*.swo 5 | zzz* 6 | -------------------------------------------------------------------------------- /.vimrc.custom.FTP: -------------------------------------------------------------------------------- 1 | set autoindent 2 | set nu 3 | set ts=8 4 | set noexpandtab 5 | 6 | e commons.c 7 | vs commons.h 8 | tabnew file_transfer_functions.c 9 | vs file_transfer_functions.h 10 | tabnew client_ftp.c 11 | vs client_ftp.h 12 | tabnew client_ftp_functions.c 13 | vs client_ftp.h 14 | tabnew server_ftp.c 15 | vs server_ftp.h 16 | tabnew server_ftp_functions.c 17 | vs server_ftp.h 18 | tabnew Makefile 19 | tabnew TODO 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g -I./ 3 | SRCCLIENT = . 4 | SRCSERVER = . 5 | BINCLIENT = bin/client 6 | BINSERVER = bin/server 7 | OBJCLIENT = obj 8 | OBJSERVER = obj 9 | OBJECTSCLIENT = ${OBJCLIENT}/commons.o ${OBJCLIENT}/client_ftp_functions.o ${OBJCLIENT}/file_transfer_functions.o ${OBJCLIENT}/client_ftp.o 10 | OBJECTSSERVER = ${OBJSERVER}/commons.o ${OBJSERVER}/server_ftp_functions.o ${OBJSERVER}/file_transfer_functions.o ${OBJSERVER}/server_ftp.o 11 | EXECUTABLECLIENT = ${BINCLIENT}/client_ftp.out 12 | EXECUTABLESERVER = ${BINSERVER}/server_ftp.out 13 | 14 | all: clean client server 15 | 16 | client: ${OBJECTSCLIENT} 17 | ${CC} ${CFLAGS} $^ -o ${EXECUTABLECLIENT} 18 | 19 | server: ${OBJECTSSERVER} 20 | ${CC} ${CFLAGS} $^ -o ${EXECUTABLESERVER} 21 | 22 | ${OBJCLIENT}/%.o: ${SRCCLIENT}/%.c 23 | ${CC} ${CFLAGS} -c $< -o $@ 24 | 25 | ${OBJSERVER}/%.o: ${SRCSERVER}/%.c 26 | ${CC} ${CFLAGS} -c $< -o $@ 27 | 28 | clean: 29 | rm -f ${OBJCLIENT}/*.o 30 | rm -f ${OBJSERVER}/*.o 31 | rm -f ${BINCLIENT}/*.out 32 | rm -f ${BINSERVER}/*.out 33 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rovinbhandari/FTP/96c1a3543b159427d41b89dd8d64792c83572774/README -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | remove set0(chp) and chp->conid = -1 from the functions in client_udp_functions.c so that the conid is maintained. 2 | implement different connections for control and for data. 3 | implement command queueing on client/server. 4 | NOT IMPORTANT: implement multi-threading on server side. 5 | put the server on port 21. 6 | DONE: make the client capable of parsing spaces in filenames. 7 | remove struct packet* data from the argument of all the functions as it is not necessary. 8 | implement lrm, rm, lrmdir, rmdir. 9 | -------------------------------------------------------------------------------- /bin/client/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rovinbhandari/FTP/96c1a3543b159427d41b89dd8d64792c83572774/bin/client/.empty -------------------------------------------------------------------------------- /bin/server/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rovinbhandari/FTP/96c1a3543b159427d41b89dd8d64792c83572774/bin/server/.empty -------------------------------------------------------------------------------- /client_ftp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | //BEGIN: initialization 6 | struct sockaddr_in sin_server; 7 | int sfd_client, x; 8 | size_t size_sockaddr = sizeof(struct sockaddr), size_packet = sizeof(struct packet); 9 | short int connection_id; 10 | struct packet* chp = (struct packet*) malloc(size_packet); // client host packet 11 | set0(chp); 12 | struct packet* data; // network packet 13 | 14 | if((x = sfd_client = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 15 | er("socket()", x); 16 | 17 | memset((char*) &sin_server, 0, sizeof(struct sockaddr_in)); 18 | sin_server.sin_family = AF_INET; 19 | sin_server.sin_addr.s_addr = inet_addr(IPSERVER); 20 | sin_server.sin_port = htons(PORTSERVER); 21 | 22 | if((x = connect(sfd_client, (struct sockaddr*) &sin_server, size_sockaddr)) < 0) 23 | er("connect()", x); 24 | 25 | printf(ID "FTP Client started up. Attempting communication with server @ %s:%d...\n\n", IPSERVER, PORTSERVER); 26 | //END: initialization 27 | 28 | 29 | struct command* cmd; 30 | char lpwd[LENBUFFER], pwd[LENBUFFER]; 31 | char userinput[LENUSERINPUT]; 32 | while(1) 33 | { 34 | printf("\t> "); 35 | fgets(userinput, LENUSERINPUT, stdin); // in order to give \ 36 | a filename with spaces, put ':' \ 37 | instead of ' '. If a command needs \ 38 | x paths, and y (y > x) paths are \ 39 | provided, y - x paths will be \ 40 | ignored. 41 | cmd = userinputtocommand(userinput); 42 | if(!cmd) 43 | continue; 44 | //printcommand(cmd); 45 | switch(cmd->id) 46 | { 47 | case GET: 48 | if(cmd->npaths) 49 | command_get(chp, data, sfd_client, *cmd->paths); 50 | else 51 | fprintf(stderr, "No path to file given.\n"); 52 | break; 53 | case PUT: 54 | if(cmd->npaths) 55 | command_put(chp, data, sfd_client, *cmd->paths); 56 | else 57 | fprintf(stderr, "No path to file given.\n"); 58 | break; 59 | case MGET: 60 | if(cmd->npaths) 61 | command_mget(chp, data, sfd_client, cmd->npaths, cmd->paths); 62 | else 63 | fprintf(stderr, "No path to file given.\n"); 64 | break; 65 | case MPUT: 66 | if(cmd->npaths) 67 | command_mput(chp, data, sfd_client, cmd->npaths, cmd->paths); 68 | else 69 | fprintf(stderr, "No path to file given.\n"); 70 | break; 71 | case MGETWILD: 72 | command_mgetwild(chp, data, sfd_client); 73 | break; 74 | case MPUTWILD: 75 | if(!getcwd(lpwd, sizeof lpwd)) 76 | er("getcwd()", 0); 77 | command_mputwild(chp, data, sfd_client, lpwd); 78 | break; 79 | case CD: 80 | if(cmd->npaths) 81 | command_cd(chp, data, sfd_client, *cmd->paths); 82 | else 83 | fprintf(stderr, "No path given.\n"); 84 | break; 85 | case LCD: 86 | if(cmd->npaths) 87 | command_lcd(*cmd->paths); 88 | else 89 | fprintf(stderr, "No path given.\n"); 90 | break; 91 | case PWD: 92 | command_pwd(chp, data, sfd_client); 93 | break; 94 | case LPWD: 95 | if(!getcwd(lpwd, sizeof lpwd)) 96 | er("getcwd()", 0); 97 | printf("\t%s\n", lpwd); 98 | break; 99 | case DIR_: 100 | case LS: 101 | command_ls(chp, data, sfd_client); 102 | break; 103 | case LDIR: 104 | case LLS: 105 | if(!getcwd(lpwd, sizeof lpwd)) 106 | er("getcwd()", 0); 107 | command_lls(lpwd); 108 | break; 109 | case MKDIR: 110 | if(cmd->npaths) 111 | command_mkdir(chp, data, sfd_client, *cmd->paths); 112 | else 113 | fprintf(stderr, "No path to directory given.\n"); 114 | break; 115 | case LMKDIR: 116 | if(cmd->npaths) 117 | command_lmkdir(*cmd->paths); 118 | else 119 | fprintf(stderr, "No path to directory given.\n"); 120 | break; 121 | case RGET: 122 | if(!getcwd(lpwd, sizeof lpwd)) 123 | er("getcwd()", 0); 124 | command_rget(chp, data, sfd_client); 125 | if((x = chdir(lpwd)) == -1) 126 | fprintf(stderr, "Wrong path.\n"); 127 | break; 128 | case RPUT: 129 | if(!getcwd(lpwd, sizeof lpwd)) 130 | er("getcwd()", 0); 131 | command_rput(chp, data, sfd_client); 132 | if((x = chdir(lpwd)) == -1) 133 | fprintf(stderr, "Wrong path.\n"); 134 | break; 135 | case EXIT: 136 | goto outside_client_command_loop; 137 | default: 138 | // display error 139 | break; 140 | } 141 | } 142 | outside_client_command_loop: 143 | 144 | /* 145 | chp->type = REQU; 146 | chp->conid = -1; 147 | strcpy(path, argv[1]); 148 | strcpy(chp->buffer, argv[1]); 149 | //printpacket(chp, HP); 150 | data = htonp(chp); 151 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 152 | er("send()", x); 153 | set0(data); 154 | do 155 | { 156 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 157 | er("recv()", x); 158 | chp = htonp(data); 159 | if(chp->type == INFO) 160 | printf(ID "Server says: %s\n", chp->buffer); 161 | else if(chp->type == DATA) 162 | { 163 | //printpacket(chp, HP); 164 | receive_file(extract_filename(path), sfd_client, chp); 165 | } 166 | } 167 | while(chp->type != TERM); 168 | 169 | fprintf(stderr, "TERM received; exiting...\n"); 170 | */ 171 | 172 | close(sfd_client); 173 | printf(ID "Done.\n"); 174 | fflush(stdout); 175 | 176 | return 0; 177 | } 178 | 179 | -------------------------------------------------------------------------------- /client_ftp.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define IPSERVER "127.0.0.1" 5 | #define ID "CLIENT=> " 6 | 7 | #define LENUSERINPUT 1024 8 | 9 | struct command 10 | { 11 | short int id; 12 | int npaths; 13 | char** paths; 14 | }; 15 | 16 | struct command* userinputtocommand(char [LENUSERINPUT]); 17 | 18 | void printcommand(struct command*); 19 | 20 | void command_pwd(struct packet*, struct packet*, int); 21 | void command_lcd(char*); 22 | void command_cd(struct packet*, struct packet*, int, char*); 23 | void command_lls(char*); 24 | void command_ls(struct packet*, struct packet*, int); 25 | void command_get(struct packet*, struct packet*, int, char*); 26 | void command_put(struct packet*, struct packet*, int, char*); 27 | void command_mget(struct packet*, struct packet*, int, int, char**); 28 | void command_mput(struct packet*, struct packet*, int, int, char**); 29 | void command_mgetwild(struct packet*, struct packet*, int); 30 | void command_mputwild(struct packet*, struct packet*, int, char*); 31 | void command_lmkdir(char*); 32 | void command_mkdir(struct packet*, struct packet*, int, char*); 33 | void command_rget(struct packet*, struct packet*, int); 34 | void command_rput(struct packet*, struct packet*, int); 35 | 36 | -------------------------------------------------------------------------------- /client_ftp_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static size_t size_packet = sizeof(struct packet); 4 | 5 | static const char commandlist[NCOMMANDS][10] = 6 | { 7 | "get", 8 | "put", 9 | 10 | "mget", 11 | "mput", 12 | 13 | "cd", 14 | "lcd", 15 | 16 | "mgetwild", 17 | "mputwild", 18 | 19 | "dir", 20 | "ldir", 21 | 22 | "ls", 23 | "lls", 24 | 25 | "mkdir", 26 | "lmkdir", 27 | 28 | "rget", 29 | "rput", 30 | 31 | "pwd", 32 | "lpwd", 33 | 34 | "exit" 35 | }; // any change made here should also be \ 36 | replicated accordingly in the COMMANDS \ 37 | enum in commons.h 38 | 39 | static void append_path(struct command* c, char* s) 40 | { 41 | c->npaths++; 42 | char** temppaths = (char**) malloc(c->npaths * sizeof(char*)); 43 | if(c->npaths > 1) 44 | memcpy(temppaths, c->paths, (c->npaths - 1) * sizeof(char*)); 45 | 46 | char* temps = (char*) malloc((strlen(s) + 1) * sizeof(char)); 47 | int i; 48 | for(i = 0; *(temps + i) = *(s + i) == ':' ? ' ' : *(s + i); i++) 49 | ; 50 | 51 | *(temppaths + c->npaths - 1) = temps; 52 | 53 | c->paths = temppaths; 54 | } 55 | 56 | 57 | struct command* userinputtocommand(char s[LENUSERINPUT]) 58 | { 59 | struct command* cmd = (struct command*) malloc(sizeof(struct command)); 60 | cmd->id = -1; 61 | cmd->npaths = 0; 62 | cmd->paths = NULL; 63 | char* savestate; 64 | char* token; 65 | int i, j; 66 | for(i = 0; ; i++, s = NULL) 67 | { 68 | token = strtok_r(s, " \t\n", &savestate); 69 | if(token == NULL) 70 | break; 71 | if(cmd->id == -1) 72 | for(j = 0; j < NCOMMANDS; j++) 73 | { 74 | if(!strcmp(token, commandlist[j])) 75 | { 76 | cmd->id = j; 77 | break; 78 | } 79 | }// ommitting braces for the "for loop" here is \ 80 | disastrous because the else below gets \ 81 | associated with the "if inside the for loop". \ 82 | #BUGFIX 83 | else 84 | append_path(cmd, token); 85 | } 86 | if(cmd->id == MGET && !strcmp(*cmd->paths, "*")) 87 | cmd->id = MGETWILD; 88 | else if(cmd->id == MPUT && !strcmp(*cmd->paths, "*")) 89 | cmd->id = MPUTWILD; 90 | if(cmd->id != -1) 91 | return cmd; 92 | else 93 | { 94 | fprintf(stderr, "\tError parsing command\n"); 95 | return NULL; 96 | } 97 | } 98 | 99 | void printcommand(struct command* c) 100 | { 101 | if(!DEBUG) 102 | return; 103 | 104 | printf("\t\tPrinting contents of the above command...\n"); 105 | printf("\t\tid = %d\n", c->id); 106 | printf("\t\tnpaths = %d\n", c->npaths); 107 | printf("\t\tpaths =\n"); 108 | int i; 109 | for(i = 0; i < c->npaths; i++) 110 | printf("\t\t\t%s\n", c->paths[i]); 111 | printf("\n"); 112 | } 113 | 114 | void command_pwd(struct packet* chp, struct packet* data, int sfd_client) 115 | { 116 | int x; 117 | set0(chp); 118 | chp->type = REQU; 119 | chp->conid = -1; 120 | chp->comid = PWD; 121 | data = htonp(chp); 122 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 123 | er("send()", x); 124 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 125 | er("recv()", x); 126 | chp = ntohp(data); 127 | if(chp->type == DATA && chp->comid == PWD && strlen(chp->buffer) > 0) 128 | printf("\t%s\n", chp->buffer); 129 | else 130 | fprintf(stderr, "\tError retrieving information.\n"); 131 | } 132 | 133 | void command_cd(struct packet* chp, struct packet* data, int sfd_client, char* path) 134 | { 135 | int x; 136 | set0(chp); 137 | chp->type = REQU; 138 | chp->conid = -1; 139 | chp->comid = CD; 140 | strcpy(chp->buffer, path); 141 | data = htonp(chp); 142 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 143 | er("send()", x); 144 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 145 | er("recv()", x); 146 | chp = ntohp(data); 147 | if(chp->type == INFO && chp->comid == CD && !strcmp(chp->buffer, "success")) 148 | ; 149 | else 150 | fprintf(stderr, "\tError executing command on the server.\n"); 151 | } 152 | 153 | void command_lls(char* lpwd) 154 | { 155 | DIR* d = opendir(lpwd); 156 | if(!d) 157 | er("opendir()", (int) d); 158 | struct dirent* e; 159 | while(e = readdir(d)) 160 | printf("\t%s\t%s\n", e->d_type == 4 ? "DIR:" : e->d_type == 8 ? "FILE:" : "UNDEF", e->d_name); 161 | closedir(d); 162 | } 163 | 164 | void command_ls(struct packet* chp, struct packet* data, int sfd_client) 165 | { 166 | int x; 167 | set0(chp); 168 | chp->type = REQU; 169 | chp->conid = -1; 170 | chp->comid = LS; 171 | data = htonp(chp); 172 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 173 | er("send()", x); 174 | while(chp->type != EOT) 175 | { 176 | if(chp->type == DATA && chp->comid == LS && strlen(chp->buffer)) 177 | printf("\t%s\n", chp->buffer); 178 | /* 179 | else 180 | fprintf(stderr, "\tError executing command on the server.\n"); 181 | */ 182 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 183 | er("recv()", x); 184 | chp = ntohp(data); 185 | } 186 | } 187 | 188 | void command_get(struct packet* chp, struct packet* data, int sfd_client, char* filename) 189 | { 190 | FILE* f = fopen(filename, "wb"); 191 | if(!f) 192 | { 193 | fprintf(stderr, "File could not be opened for writing. Aborting...\n"); 194 | return; 195 | } 196 | int x; 197 | set0(chp); 198 | chp->type = REQU; 199 | chp->conid = -1; 200 | chp->comid = GET; 201 | strcpy(chp->buffer, filename); 202 | data = htonp(chp); 203 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 204 | er("send()", x); 205 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 206 | er("recv()", x); 207 | chp = ntohp(data); 208 | //printpacket(chp, HP); 209 | if(chp->type == INFO && chp->comid == GET && strlen(chp->buffer)) 210 | { 211 | printf("\t%s\n", chp->buffer); 212 | receive_file(chp, data, sfd_client, f); 213 | fclose(f); 214 | } 215 | else 216 | fprintf(stderr, "Error getting remote file : <%s>\n", filename); 217 | } 218 | 219 | void command_put(struct packet* chp, struct packet* data, int sfd_client, char* filename) 220 | { 221 | FILE* f = fopen(filename, "rb"); // Yo! 222 | if(!f) 223 | { 224 | fprintf(stderr, "File could not be opened for reading. Aborting...\n"); 225 | return; 226 | } 227 | int x; 228 | set0(chp); 229 | chp->type = REQU; 230 | chp->conid = -1; 231 | chp->comid = PUT; 232 | strcpy(chp->buffer, filename); 233 | data = htonp(chp); 234 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 235 | er("send()", x); 236 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 237 | er("recv()", x); 238 | chp = ntohp(data); 239 | //printpacket(chp, HP); 240 | if(chp->type == INFO && chp->comid == PUT && strlen(chp->buffer)) 241 | { 242 | printf("\t%s\n", chp->buffer); 243 | chp->type = DATA; 244 | send_file(chp, data, sfd_client, f); 245 | fclose(f); 246 | } 247 | else 248 | fprintf(stderr, "Error sending file.\n"); 249 | send_EOT(chp, data, sfd_client); 250 | } 251 | 252 | void command_mget(struct packet* chp, struct packet* data, int sfd_client, int n, char** filenames) 253 | { 254 | int i; 255 | char* filename; 256 | for(i = 0; i < n; i++) 257 | { 258 | filename = *(filenames + i); 259 | printf("\tProcessing file %d of %d:\t%s\n", i + 1, n, filename); 260 | command_get(chp, data, sfd_client, filename); 261 | } 262 | if(i != n) 263 | fprintf(stderr, "Not all files could be downloaded.\n"); 264 | } 265 | 266 | void command_mput(struct packet* chp, struct packet* data, int sfd_client, int n, char** filenames) 267 | { 268 | int i; 269 | char* filename; 270 | for(i = 0; i < n; i++) 271 | { 272 | filename = *(filenames + i); 273 | printf("\tProcessing file %d of %d:\t%s\n", i + 1, n, filename); 274 | command_put(chp, data, sfd_client, filename); 275 | } 276 | if(i != n) 277 | fprintf(stderr, "Not all files could be uploaded.\n"); 278 | } 279 | 280 | void command_mgetwild(struct packet* chp, struct packet* data, int sfd_client) 281 | { 282 | int x; 283 | set0(chp); 284 | chp->type = REQU; 285 | chp->conid = -1; 286 | chp->comid = LS; 287 | data = htonp(chp); 288 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 289 | er("send()", x); 290 | struct command* cmd = (struct command*) malloc(sizeof(struct command)); 291 | cmd->id = MGETWILD; 292 | cmd->npaths = 0; 293 | cmd->paths = NULL; 294 | while(chp->type != EOT) 295 | { 296 | if(chp->type == DATA && chp->comid == LS && strlen(chp->buffer)) 297 | if(*chp->buffer == 'F') 298 | append_path(cmd, chp->buffer + 6); 299 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 300 | er("recv()", x); 301 | chp = ntohp(data); 302 | } 303 | command_mget(chp, data, sfd_client, cmd->npaths, cmd->paths); 304 | } 305 | 306 | void command_mputwild(struct packet* chp, struct packet* data, int sfd_client, char* lpwd) 307 | { 308 | DIR* d = opendir(lpwd); 309 | if(!d) 310 | er("opendir()", (int) d); 311 | struct dirent* e; 312 | struct command* cmd = (struct command*) malloc(sizeof(struct command)); 313 | cmd->id = MPUTWILD; 314 | cmd->npaths = 0; 315 | cmd->paths = NULL; 316 | while(e = readdir(d)) 317 | if(e->d_type == 8) 318 | append_path(cmd, e->d_name); 319 | closedir(d); 320 | command_mput(chp, data, sfd_client, cmd->npaths, cmd->paths); 321 | } 322 | 323 | void command_rput(struct packet* chp, struct packet* data, int sfd_client) 324 | { 325 | static char lpwd[LENBUFFER]; 326 | if(!getcwd(lpwd, sizeof lpwd)) 327 | er("getcwd()", 0); 328 | int x; 329 | DIR* d = opendir(lpwd); 330 | if(!d) 331 | er("opendir()", (int) d); 332 | struct dirent* e; 333 | struct command* cmd = (struct command*) malloc(sizeof(struct command)); 334 | cmd->id = RPUT; 335 | cmd->npaths = 0; 336 | cmd->paths = NULL; 337 | while(e = readdir(d)) 338 | if(e->d_type == 8) 339 | append_path(cmd, e->d_name); 340 | else if(e->d_type == 4 && strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) 341 | { 342 | command_mkdir(chp, data, sfd_client, e->d_name); 343 | 344 | command_cd(chp, data, sfd_client, e->d_name); 345 | command_lcd(e->d_name); 346 | 347 | command_rput(chp, data, sfd_client); 348 | 349 | command_cd(chp, data, sfd_client, ".."); 350 | command_lcd(".."); 351 | } 352 | closedir(d); 353 | command_mput(chp, data, sfd_client, cmd->npaths, cmd->paths); 354 | } 355 | 356 | void command_rget(struct packet* chp, struct packet* data, int sfd_client) 357 | { 358 | char temp[LENBUFFER]; 359 | int x; 360 | set0(chp); 361 | chp->type = REQU; 362 | chp->conid = -1; 363 | chp->comid = RGET; 364 | data = htonp(chp); 365 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 366 | er("send()", x); 367 | 368 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 369 | er("recv()", x); 370 | chp = ntohp(data); 371 | //printpacket(chp, HP); 372 | while(chp->type == REQU) 373 | { 374 | if(chp->comid == LMKDIR) 375 | { 376 | strcpy(temp, chp->buffer); 377 | command_lmkdir(temp); 378 | } 379 | else if(chp->comid == LCD) 380 | { 381 | strcpy(temp, chp->buffer); 382 | command_lcd(temp); 383 | } 384 | else if(chp->comid == GET) 385 | { 386 | strcpy(temp, chp->buffer); 387 | command_get(chp, data, sfd_client, temp); 388 | } 389 | 390 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 391 | er("recv()", x); 392 | chp = ntohp(data); 393 | //printpacket(chp, HP); 394 | } 395 | if(chp->type == EOT) 396 | printf("\tTransmission successfully ended.\n"); 397 | else 398 | fprintf(stderr, "There was a problem completing the request.\n"); 399 | } 400 | 401 | void command_mkdir(struct packet* chp, struct packet* data, int sfd_client, char* dirname) 402 | { 403 | int x; 404 | set0(chp); 405 | chp->type = REQU; 406 | chp->conid = -1; 407 | chp->comid = MKDIR; 408 | strcpy(chp->buffer, dirname); 409 | data = htonp(chp); 410 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 411 | er("send()", x); 412 | if((x = recv(sfd_client, data, size_packet, 0)) <= 0) 413 | er("recv()", x); 414 | chp = ntohp(data); 415 | if(chp->type == INFO && chp->comid == MKDIR) 416 | { 417 | if(!strcmp(chp->buffer, "success")) 418 | printf("\tCreated directory on server.\n"); 419 | else if(!strcmp(chp->buffer, "already exists")) 420 | printf("\tDirectory already exitst on server.\n"); 421 | } 422 | else 423 | fprintf(stderr, "\tError executing command on the server.\n"); 424 | } 425 | 426 | void command_lmkdir(char* dirname) 427 | { 428 | DIR* d = opendir(dirname); 429 | if(d) 430 | { 431 | printf("\tDirectory already exists.\n"); 432 | closedir(d); 433 | } 434 | else if(mkdir(dirname, 0777) == -1) 435 | fprintf(stderr, "Error in creating directory.\n"); 436 | else 437 | printf("\tCreated directory.\n"); 438 | } 439 | 440 | void command_lcd(char* path) 441 | { 442 | if(chdir(path) == -1) 443 | fprintf(stderr, "Wrong path : <%s>\n", path); 444 | } 445 | 446 | -------------------------------------------------------------------------------- /commons.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static size_t size_packet = sizeof(struct packet); 4 | 5 | void set0(struct packet* p) 6 | { 7 | memset(p, 0, sizeof(struct packet)); 8 | } 9 | 10 | struct packet* ntohp(struct packet* np) 11 | { 12 | struct packet* hp = (struct packet*) malloc(size_packet); 13 | memset(hp, 0, size_packet); 14 | 15 | hp->conid = ntohs(np->conid); 16 | hp->type = ntohs(np->type); 17 | hp->comid = ntohs(np->comid); 18 | hp->datalen = ntohs(np->datalen); 19 | memcpy(hp->buffer, np->buffer, LENBUFFER); 20 | 21 | return hp; 22 | } 23 | 24 | struct packet* htonp(struct packet* hp) 25 | { 26 | struct packet* np = (struct packet*) malloc(size_packet); 27 | memset(np, 0, size_packet); 28 | 29 | np->conid = ntohs(hp->conid); 30 | np->type = ntohs(hp->type); 31 | np->comid = ntohs(hp->comid); 32 | np->datalen = ntohs(hp->datalen); 33 | memcpy(np->buffer, hp->buffer, LENBUFFER); 34 | 35 | return np; 36 | } 37 | 38 | void printpacket(struct packet* p, int ptype) 39 | { 40 | if(!DEBUG) 41 | return; 42 | 43 | if(ptype) 44 | printf("\t\tHOST PACKET\n"); 45 | else 46 | printf("\t\tNETWORK PACKET\n"); 47 | 48 | printf("\t\tconid = %d\n", p->conid); 49 | printf("\t\ttype = %d\n", p->type); 50 | printf("\t\tcomid = %d\n", p->comid); 51 | printf("\t\tdatalen = %d\n", p->datalen); 52 | printf("\t\tbuffer = %s\n", p->buffer); 53 | 54 | fflush(stdout); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /commons.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMONS_H 2 | #define COMMONS_H 3 | 4 | #include 5 | /* 6 | for: 7 | htons() 8 | htonl() 9 | ntohs() 10 | inet_aton() 11 | inet_ntoa() 12 | */ 13 | 14 | #include 15 | /* 16 | for: 17 | inet_aton() 18 | inet_ntoa() 19 | */ 20 | 21 | #include 22 | /* 23 | for: 24 | socket() 25 | bind() 26 | recvfrom() 27 | sendto() 28 | stat() 29 | */ 30 | 31 | #include 32 | /* 33 | for: 34 | socket() 35 | bind() 36 | recvfrom() 37 | sendto() 38 | inet_aton() 39 | inet_ntoa() 40 | AF_INET 41 | SOCK_DGRAM 42 | */ 43 | 44 | #include 45 | /* 46 | for: 47 | return type of system calls 48 | */ 49 | 50 | #include 51 | /* 52 | for: 53 | printf() 54 | sprintf() 55 | fflush() 56 | perror() 57 | */ 58 | 59 | #include 60 | /* 61 | for: 62 | exit() 63 | malloc() 64 | */ 65 | 66 | #include 67 | /* 68 | for: 69 | memset() 70 | strlen() 71 | strcpy() 72 | */ 73 | 74 | #include 75 | /* 76 | for: 77 | close() 78 | sleep() 79 | stat() 80 | */ 81 | 82 | #include 83 | 84 | #define DEBUG 1 85 | 86 | #define PORTSERVER 8487 87 | #define CONTROLPORT PORTSERVER 88 | #define DATAPORT (PORTSERVER + 1) 89 | 90 | enum TYPE 91 | { 92 | REQU, 93 | DONE, 94 | INFO, 95 | TERM, 96 | DATA, 97 | EOT 98 | }; 99 | 100 | #define NP 0 101 | #define HP 1 102 | 103 | #define er(e, x) \ 104 | do \ 105 | { \ 106 | perror("ERROR IN: " #e "\n"); \ 107 | fprintf(stderr, "%d\n", x); \ 108 | exit(-1); \ 109 | } \ 110 | while(0) 111 | 112 | #define LENBUFFER 504 // so as to make the whole packet well-rounded ( = 512 bytes) 113 | struct packet 114 | { 115 | short int conid; 116 | short int type; 117 | short int comid; 118 | short int datalen; 119 | char buffer[LENBUFFER]; 120 | }; 121 | 122 | void set0(struct packet*); 123 | 124 | struct packet* ntohp(struct packet*); 125 | struct packet* htonp(struct packet*); 126 | 127 | void printpacket(struct packet*, int); 128 | 129 | #define NCOMMANDS 19 130 | enum COMMAND 131 | { 132 | GET, 133 | PUT, 134 | MGET, 135 | MPUT, 136 | CD, 137 | LCD, 138 | MGETWILD, 139 | MPUTWILD, 140 | DIR_, // _ to avoid conflict with directory pointer DIR 141 | LDIR, 142 | LS, 143 | LLS, 144 | MKDIR, 145 | LMKDIR, 146 | RGET, 147 | RPUT, 148 | PWD, 149 | LPWD, 150 | EXIT 151 | }; // any change made here should also be \ 152 | replicated accordingly in the commandlist \ 153 | 2D array in client_ftp_fucntions.c 154 | 155 | #endif 156 | 157 | -------------------------------------------------------------------------------- /file_transfer_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static size_t size_packet = sizeof(struct packet); 4 | 5 | void send_EOT(struct packet* hp, struct packet* data, int sfd) 6 | { 7 | int x; 8 | hp->type = EOT; 9 | data = htonp(hp); 10 | if((x = send(sfd, data, size_packet, 0)) != size_packet) 11 | er("send()", x); 12 | } 13 | 14 | void send_TERM(struct packet* hp, struct packet* data, int sfd) 15 | { 16 | int x; 17 | hp->type = TERM; 18 | data = htonp(hp); 19 | if((x = send(sfd, data, size_packet, 0)) != size_packet) 20 | er("send()", x); 21 | } 22 | 23 | void send_file(struct packet* hp, struct packet* data, int sfd, FILE* f) 24 | { 25 | int x; 26 | int i = 0, j = 0; 27 | while(!feof(f)) 28 | { 29 | memset(hp->buffer, '\0', sizeof(char) * LENBUFFER); 30 | hp->datalen = fread(hp->buffer, 1, LENBUFFER - 1, f); 31 | i += hp->datalen; 32 | //printpacket(hp, HP); 33 | data = htonp(hp); 34 | if((x = send(sfd, data, size_packet, 0)) != size_packet) 35 | er("send()", x); 36 | j++; 37 | } 38 | fprintf(stderr, "\t%d byte(s) read.\n", i); 39 | fprintf(stderr, "\t%d data packet(s) sent.\n", j); 40 | fflush(stderr); 41 | } 42 | 43 | void receive_file(struct packet* hp, struct packet* data, int sfd, FILE* f) 44 | { 45 | int x; 46 | int i = 0, j = 0; 47 | if((x = recv(sfd, data, size_packet, 0)) <= 0) 48 | er("recv()", x); 49 | j++; 50 | hp = ntohp(data); 51 | //printpacket(hp, HP); 52 | while(hp->type == DATA) 53 | { 54 | i += fwrite(hp->buffer, 1, hp->datalen, f); 55 | if((x = recv(sfd, data, size_packet, 0)) <= 0) 56 | er("recv()", x); 57 | j++; 58 | hp = ntohp(data); 59 | //printpacket(hp, HP); 60 | } 61 | fprintf(stderr, "\t%d data packet(s) received.\n", --j); // j decremented because the last packet is EOT. 62 | fprintf(stderr, "\t%d byte(s) written.\n", i); 63 | if(hp->type == EOT) 64 | return; 65 | else 66 | { 67 | fprintf(stderr, "Error occured while downloading remote file.\n"); 68 | exit(2); 69 | } 70 | fflush(stderr); 71 | } 72 | 73 | -------------------------------------------------------------------------------- /file_transfer_functions.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define extract_filename(filepath) ((strrchr(filepath, '/') != NULL) ? (strrchr(filepath, '/') + 1) : filepath) 4 | 5 | void send_EOT(struct packet*, struct packet*, int); 6 | void send_TERM(struct packet*, struct packet* , int); 7 | 8 | void send_file(struct packet*, struct packet*, int, FILE*); 9 | void receive_file(struct packet*, struct packet*, int, FILE*); 10 | 11 | -------------------------------------------------------------------------------- /obj/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rovinbhandari/FTP/96c1a3543b159427d41b89dd8d64792c83572774/obj/.empty -------------------------------------------------------------------------------- /server_ftp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t size_sockaddr = sizeof(struct sockaddr), size_packet = sizeof(struct packet); 4 | 5 | void* serve_client(void*); 6 | 7 | int main(void) 8 | { 9 | //BEGIN: initialization 10 | struct sockaddr_in sin_server, sin_client; 11 | int sfd_server, sfd_client, x; 12 | short int connection_id = 0; 13 | 14 | if((x = sfd_server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 15 | er("socket()", x); 16 | 17 | memset((char*) &sin_server, 0, sizeof(struct sockaddr_in)); 18 | sin_server.sin_family = AF_INET; 19 | sin_server.sin_port = htons(PORTSERVER); 20 | sin_server.sin_addr.s_addr = htonl(INADDR_ANY); 21 | 22 | if((x = bind(sfd_server, (struct sockaddr*) &sin_server, size_sockaddr)) < 0) 23 | er("bind()", x); 24 | 25 | if((x = listen(sfd_server, 1)) < 0) 26 | er("listen()", x); 27 | 28 | printf(ID "FTP Server started up @ local:%d. Waiting for client(s)...\n\n", PORTSERVER); 29 | //END: initialization 30 | 31 | 32 | while(1) 33 | { 34 | if((x = sfd_client = accept(sfd_server, (struct sockaddr*) &sin_client, &size_sockaddr)) < 0) 35 | er("accept()", x); 36 | printf(ID "Communication started with %s:%d\n", inet_ntoa(sin_client.sin_addr), ntohs(sin_client.sin_port)); 37 | fflush(stdout); 38 | 39 | struct client_info* ci = client_info_alloc(sfd_client, connection_id++); 40 | serve_client(ci); 41 | } 42 | 43 | close(sfd_server); 44 | printf(ID "Done.\n"); 45 | fflush(stdout); 46 | 47 | return 0; 48 | } 49 | 50 | void* serve_client(void* info) 51 | { 52 | int sfd_client, connection_id, x; 53 | struct packet* data = (struct packet*) malloc(size_packet); 54 | struct packet* shp; 55 | char lpwd[LENBUFFER]; 56 | struct client_info* ci = (struct client_info*) info; 57 | sfd_client = ci->sfd; 58 | connection_id = ci->cid; 59 | 60 | while(1) 61 | { 62 | if((x = recv(sfd_client, data, size_packet, 0)) == 0) 63 | { 64 | fprintf(stderr, "client closed/terminated. closing connection.\n"); 65 | break; 66 | } 67 | 68 | shp = ntohp(data); 69 | 70 | if(shp->type == TERM) 71 | break; 72 | 73 | if(shp->conid == -1) 74 | shp->conid = connection_id; 75 | 76 | if(shp->type == REQU) 77 | { 78 | switch(shp->comid) 79 | { 80 | case PWD: 81 | if(!getcwd(lpwd, sizeof lpwd)) 82 | er("getcwd()", 0); 83 | command_pwd(shp, data, sfd_client, lpwd); 84 | break; 85 | case CD: 86 | if((x = chdir(shp->buffer)) == -1) 87 | fprintf(stderr, "Wrong path.\n"); 88 | command_cd(shp, data, sfd_client, x == -1 ? "fail" : "success"); 89 | break; 90 | case MKDIR: 91 | command_mkdir(shp, data, sfd_client); 92 | break; 93 | case LS: 94 | if(!getcwd(lpwd, sizeof lpwd)) 95 | er("getcwd()", 0); 96 | command_ls(shp, data, sfd_client, lpwd); 97 | break; 98 | case GET: 99 | command_get(shp, data, sfd_client); 100 | break; 101 | case PUT: 102 | command_put(shp, data, sfd_client); 103 | break; 104 | case RGET: 105 | if(!getcwd(lpwd, sizeof lpwd)) 106 | er("getcwd()", 0); 107 | command_rget(shp, data, sfd_client); 108 | send_EOT(shp, data, sfd_client); 109 | if((x = chdir(lpwd)) == -1) 110 | fprintf(stderr, "Wrong path.\n"); 111 | default: 112 | // print error 113 | break; 114 | } 115 | /* 116 | //send info and then proceed to complete the request 117 | shp->type = INFO; 118 | strcpy(path, shp->buffer); 119 | sprintf(shp->buffer, "File found. Processing..."); 120 | data = htonp(shp); 121 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 122 | er("send()", x); 123 | 124 | send_file(path, sfd_client, shp); 125 | send_TERM(sfd_client, shp); 126 | */ 127 | } 128 | else 129 | { 130 | //show error, send TERM and break 131 | fprintf(stderr, "packet incomprihensible. closing connection.\n"); 132 | send_TERM(shp, data, sfd_client); 133 | break; 134 | } 135 | } 136 | 137 | close(sfd_client); 138 | fflush(stdout); 139 | } 140 | 141 | -------------------------------------------------------------------------------- /server_ftp.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | /* 6 | for: 7 | ctime() 8 | */ 9 | 10 | #include 11 | /* 12 | for: 13 | stat() 14 | */ 15 | 16 | #define ID "SERVER=> " 17 | 18 | struct client_info 19 | { 20 | int sfd; 21 | int cid; 22 | }; 23 | 24 | struct client_info* client_info_alloc(int, int); 25 | 26 | void command_pwd(struct packet*, struct packet*, int, char*); 27 | void command_cd(struct packet*, struct packet*, int, char*); 28 | void command_ls(struct packet*, struct packet*, int, char*); 29 | void command_get(struct packet*, struct packet*, int); 30 | void command_put(struct packet*, struct packet*, int); 31 | void command_mkdir(struct packet*, struct packet*, int); 32 | void command_rget(struct packet*, struct packet*, int); 33 | 34 | -------------------------------------------------------------------------------- /server_ftp_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static size_t size_packet = sizeof(struct packet); 4 | 5 | struct client_info* client_info_alloc(int s, int c) 6 | { 7 | struct client_info* ci = (struct client_info*) malloc(sizeof(struct client_info)); 8 | ci->sfd = s; 9 | ci->cid = c; 10 | return ci; 11 | } 12 | 13 | void command_pwd(struct packet* shp, struct packet* data, int sfd_client, char* lpwd) 14 | { 15 | int x; 16 | shp->type = DATA; 17 | strcpy(shp->buffer, lpwd); 18 | data = htonp(shp); 19 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 20 | er("send()", x); 21 | } 22 | 23 | void command_cd(struct packet* shp, struct packet* data, int sfd_client, char* message) 24 | { 25 | int x; 26 | shp->type = INFO; 27 | strcpy(shp->buffer, message); 28 | data = htonp(shp); 29 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 30 | er("send()", x); 31 | } 32 | 33 | void command_ls(struct packet* shp, struct packet* data, int sfd_client, char* lpwd) 34 | { 35 | int x; 36 | shp->type = DATA; 37 | DIR* d = opendir(lpwd); 38 | if(!d) 39 | er("opendir()", (int) d); 40 | struct dirent* e; 41 | while(e = readdir(d)) 42 | { 43 | sprintf(shp->buffer, "%s\t%s", e->d_type == 4 ? "DIR:" : e->d_type == 8 ? "FILE:" : "UNDEF:", e->d_name); 44 | data = htonp(shp); 45 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 46 | er("send()", x); 47 | } 48 | send_EOT(shp, data, sfd_client); 49 | } 50 | 51 | void command_get(struct packet* shp, struct packet* data, int sfd_client) 52 | { 53 | int x; 54 | FILE* f = fopen(shp->buffer, "rb"); // Yo! 55 | shp->type = INFO; 56 | shp->comid = GET; 57 | strcpy(shp->buffer, f ? "File found; processing" : "Error opening file."); 58 | //printpacket(shp, HP); 59 | data = htonp(shp); 60 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 61 | er("send()", x); 62 | if(f) 63 | { 64 | shp->type = DATA; 65 | send_file(shp, data, sfd_client, f); 66 | fclose(f); 67 | } 68 | send_EOT(shp, data, sfd_client); 69 | } 70 | 71 | void command_put(struct packet* shp, struct packet* data, int sfd_client) 72 | { 73 | int x; 74 | FILE* f = fopen(shp->buffer, "wb"); 75 | shp->type = INFO; 76 | shp->comid = PUT; 77 | strcpy(shp->buffer, f ? "Everything in order; processing" : "Error opening file for writing on server side."); 78 | //printpacket(shp, HP); 79 | data = htonp(shp); 80 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 81 | er("send()", x); 82 | if(f) 83 | { 84 | receive_file(shp, data, sfd_client, f); 85 | fclose(f); 86 | } 87 | } 88 | 89 | void command_mkdir(struct packet* shp, struct packet* data, int sfd_client) 90 | { 91 | char message[LENBUFFER]; 92 | DIR* d = opendir(shp->buffer); 93 | if(d) 94 | { 95 | strcpy(message, "already exists"); 96 | closedir(d); 97 | } 98 | else if(mkdir(shp->buffer, 0777) == -1) 99 | { 100 | fprintf(stderr, "Wrong path.\n"); 101 | strcpy(message, "fail"); 102 | } 103 | else 104 | strcpy(message, "success"); 105 | int x; 106 | shp->type = INFO; 107 | strcpy(shp->buffer, message); 108 | data = htonp(shp); 109 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 110 | er("send()", x); 111 | } 112 | 113 | void command_rget(struct packet* shp, struct packet* data, int sfd_client) 114 | { 115 | static char lpwd[LENBUFFER]; 116 | if(!getcwd(lpwd, sizeof lpwd)) 117 | er("getcwd()", 0); 118 | int x; 119 | DIR* d = opendir(lpwd); 120 | if(!d) 121 | er("opendir()", (int) d); 122 | struct dirent* e; 123 | while(e = readdir(d)) 124 | if(e->d_type == 4 && strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) 125 | { 126 | shp->type = REQU; 127 | shp->comid = LMKDIR; 128 | strcpy(shp->buffer, e->d_name); 129 | data = htonp(shp); 130 | //fprintf(stderr, "LMKDIR: e->d_name = <%s>\n", e->d_name); 131 | //printpacket(shp, HP); 132 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 133 | er("send()", x); 134 | 135 | shp->type = REQU; 136 | shp->comid = LCD; 137 | strcpy(shp->buffer, e->d_name); 138 | data = htonp(shp); 139 | //fprintf(stderr, "LCD: e->d_name = <%s>\n", e->d_name); 140 | //printpacket(shp, HP); 141 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 142 | er("send()", x); 143 | if((x = chdir(e->d_name)) == -1) 144 | er("chdir()", x); 145 | 146 | command_rget(shp, data, sfd_client); 147 | 148 | shp->type = REQU; 149 | shp->comid = LCD; 150 | strcpy(shp->buffer, ".."); 151 | data = htonp(shp); 152 | //fprintf(stderr, "LCD: <..>\n"); 153 | //printpacket(shp, HP); 154 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 155 | er("send()", x); 156 | if((x = chdir("..")) == -1) 157 | er("chdir()", x); 158 | } 159 | else if(e->d_type == 8) 160 | { 161 | shp->type = REQU; 162 | shp->comid = GET; 163 | strcpy(shp->buffer, e->d_name); 164 | data = htonp(shp); 165 | //fprintf(stderr, "GET: e->d_name = <%s>\n", e->d_name); 166 | //printpacket(shp, HP); 167 | if((x = send(sfd_client, data, size_packet, 0)) != size_packet) 168 | er("send()", x); 169 | if((x = recv(sfd_client, data, size_packet, 0)) == 0) 170 | er("recv()", x); 171 | shp = ntohp(data); 172 | if(shp->type == REQU && shp->comid == GET) 173 | command_get(shp, data, sfd_client); 174 | } 175 | closedir(d); 176 | } 177 | 178 | --------------------------------------------------------------------------------