-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.c
304 lines (252 loc) · 8.99 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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/*******************************
* Name: Robert Boespflug
* Date: 06/05/2018
* Description: This is the file transfer server. This program
* waits for a cmd from the ftclient and sends either the file that
* was requested or the entire current directory. Txt files only.
********************************/
#include <stdio.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//error function calls perror and exits
void error(const char *msg) { perror(msg); exit(1); }
//function prototypes
void bind_(struct sockaddr_in * ADDRESS, int * SOCKET);
void receive_conn(char buffer[], int * CONNECTION);
void setup_sock(int * SOCKET, int * option);
int countFiles(DIR * dir, struct dirent * file_in);
void getFiles(DIR * dir, struct dirent * file_in, char * buffer[]);
void sendFile(char * filename, int DATA_CONNECTION);
//void sendFileName(char * filename, int DATA_CONNECTION);
void connect_conn(struct sockaddr_in * ADDRESS, int * PORT);
void accept_conn(struct sockaddr_in * ADDRESS, int * SOCKET, int * CONNECTION);
//void parse_cmd(char buffer[], char * command, char * file, char * sbPort);
//main entry point
int main(int argc, char *argv[])
{
//declare sockets, buffers
int RECVSOCKET, CONTROL_CONNECTION, DATA_CONNECTION, DATA_PORT, CONTROL_PORT;
int option = 1;
char buffer[4096];
struct sockaddr_in SERVER_ADDRESS, CLIENT_ADDRESS;
//get the port number from cmd line, convert to an integer from a string
CONTROL_PORT = atoi(argv[1]);
//set up the connection to client
connect_conn(&SERVER_ADDRESS, &CONTROL_PORT);
setup_sock(&RECVSOCKET, &option);
//bind socket to port to create server
if (bind(RECVSOCKET, (struct sockaddr *)&SERVER_ADDRESS, sizeof(SERVER_ADDRESS)) < 0)
{
error("SERVER: ERROR on binding address to socket");
}
while(1)
{
//listen for incoming connections, up to five
listen(RECVSOCKET, 5);
//accpet a connection and receive command from client
accept_conn(&CLIENT_ADDRESS, &RECVSOCKET, &CONTROL_CONNECTION);
receive_conn(buffer, &CONTROL_CONNECTION);
//tokenize the command, filename (if necessary), and the data port number
char * command; char * file; char * sbPort;
command = strtok(buffer, "@");
if(strcmp(command, "-g") == 0) file = strtok(NULL, "@");
if(strcmp(command, "-l") == 0) sbPort = strtok(NULL, "@");
else sbPort = strtok(NULL, " ");
//print what the client sent
/*printf("message: %s\n", buffer);
printf("the command was: %s\n", command);
printf("the file name was: %s\n", file);
printf("the sendBackPort was: %s\n", sbPort);*/
//data to screen for info
/*printf("client IP address is: %s\n", inet_ntoa(CLIENT_ADDRESS.sin_addr));*/
//set up the address struct for the send-back to client
DATA_PORT = atoi(sbPort); //change to int first
CLIENT_ADDRESS.sin_family = AF_INET; //create a network socket
CLIENT_ADDRESS.sin_port = htons(DATA_PORT); //store the port number in network order
//create the socket and set options to be able to quickly reuse the socket
DATA_CONNECTION = socket(AF_INET, SOCK_STREAM, 0);
if (DATA_CONNECTION < 0)
{
error("CLIENT: ERROR opening socket");
}
setsockopt(DATA_CONNECTION, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//connect socket to addr
if (connect(DATA_CONNECTION, (struct sockaddr*)&CLIENT_ADDRESS, sizeof(CLIENT_ADDRESS)) < 0)
{
error("CLIENT: ERROR connecting");
}
//depending on which cmd the client sent, send back
//either the file name requested or the entire contents
//of the current working dir
if(strcmp(command, "-g") == 0)
{
sendFile(file, DATA_CONNECTION);
}
else if(strcmp(command, "-l") == 0)
{
//open current dir and init dirent to hold for dir properties
DIR * dir = opendir(".");
if(dir == NULL) error("Could not open current directory" );
struct dirent * file_in;
//count the number of txt files in the current dir
int numfiles = countFiles(dir, file_in);
printf("number of txt files: %d\n", numfiles);
//declare an array of strings that represents the filenames
char * buffer[numfiles];
//the getFiles function will put all the .txt filenames
//in the buffer of strings
getFiles(dir, file_in, buffer);
//for every file in the filename array
int x = 0;
for(x; x < numfiles; x++)
{
//make a send buffer to gather the filenames and
//delimiters into one string to send over to the client
char sbuff[4096];
memset(sbuff, '\0', sizeof(sbuff));
strcpy(sbuff, buffer[x]);
strcat(sbuff, "#");
//send over the send buffer
int chars = 0;
while(chars < strlen(buffer[x]))
{ chars += send(DATA_CONNECTION, sbuff, strlen(sbuff), 0); }
}
//for every file in the filename buffer,
//send over that filename
x = 0;
for(x; x < numfiles; x++)
{
sendFile(buffer[x], DATA_CONNECTION);
}
}
else
{error("bad command: ");}
//close(CONTROL_CONNECTION); //close the connection to client
//close(RECVSOCKET); //close control port socket
close(DATA_CONNECTION); //close data port socket
}
return 0;
}
/*************************
* Description:
*************************/
void setup_sock(int * SOCKET, int * option)
{
// Set up the socket
*SOCKET = socket(AF_INET, SOCK_STREAM, 0); // Create the socket
if (*SOCKET < 0) error("SERVER: ERROR opening socket");
setsockopt(*SOCKET, SOL_SOCKET, SO_REUSEADDR, option, sizeof(int)); //from piazza
}
/*************************
* Description:
*************************/
void connect_conn(struct sockaddr_in * ADDRESS, int * PORT)
{
//set up the address struct for this process (the serve
memset((char *)ADDRESS, '\0', sizeof(ADDRESS)); // Clear out the address struct
ADDRESS->sin_family = AF_INET; // Create a network-capable socket
ADDRESS->sin_port = htons(*PORT); // Store the port number
ADDRESS->sin_addr.s_addr = INADDR_ANY; // Any address is allowed for connection to this process
}
/*************************
* Description:
*************************/
int countFiles(DIR * dir, struct dirent * file_in)
{
int fileNum = 0;
while ((file_in = readdir(dir)) != NULL)
{
if(strcmp(file_in->d_name, ".") != 0 && strcmp(file_in->d_name, "..") != 0)
{
if(strstr(file_in->d_name, ".txt") != NULL)
{
fileNum++;
}
}
}
rewinddir(dir);
return fileNum;
}
/*************************
* Description:
*************************/
void getFiles(DIR * dir, struct dirent * file_in, char * buffer[])
{
int fileNum = 0;
while ((file_in = readdir(dir)) != NULL)
{
if(strcmp(file_in->d_name, ".") != 0 && strcmp(file_in->d_name, "..") != 0)
{
if(strstr(file_in->d_name, ".txt") != NULL)
{
buffer[fileNum] = (char *)malloc(strlen(file_in->d_name));
strcpy(buffer[fileNum], file_in->d_name);
//printf("buffer: %s\n", buffer[fileNum]);
fileNum++;
}
}
}
closedir(dir);
}
/*************************
* Description:
*************************/
void sendFile(char * filename, int DATA_CONNECTION)
{
//try to open the passed in filename
printf("Sending over: %s\n", filename);
FILE * fp;
fp = fopen(filename,"r");
//if no filename then send back error and stop
if(!fp) {
send(DATA_CONNECTION, "error", strlen("error"), 0);
error("No file found!");
}
//else file does exist, so make a buffer to hold
//the files contents to send back
char buffer[4096];
memset(buffer, '\0', sizeof(buffer));
//seek to the beginning of the file
fseek(fp, 0, SEEK_SET);
//read contents of file into buffer
fgets(buffer, sizeof(buffer), fp);
//print file contents to window
//printf("file contents: %s", buffer);
//send the contents of the file client and close file
int chars = 0;
while(chars < strlen(buffer))
{
chars += send(DATA_CONNECTION, buffer, strlen(buffer), 0);
printf("chars sent: %d\n", chars);
}
fclose(fp);
}
/*************************
* Description:
*************************/
void accept_conn(struct sockaddr_in * ADDRESS, int * SOCKET, int * CONNECTION)
{
socklen_t sizeOfClientInfo;
//accept a connection, blocking if one is not available until one connects
sizeOfClientInfo = sizeof(*ADDRESS); //get the size of the address for the client that will connect
*CONNECTION = accept(*SOCKET, (struct sockaddr *)ADDRESS, &sizeOfClientInfo);
if (*CONNECTION < 0) { error("SERVER: ERROR on accept! exit "); }
}
/*************************
* Description:
*************************/
void receive_conn(char buffer[], int * CONNECTION)
{
//make sure buffer is null terminated
memset(buffer, '\0', 4096);
//receive data from client
int charsRead;
charsRead = recv(*CONNECTION, buffer, 4096, 0);
printf("chars read: %d\n", charsRead);
}