-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.c
243 lines (219 loc) · 7.75 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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h> // Used for creating threads
#include <ctype.h> // Used for isspace() function
#include <errno.h> // error reporting using stderror(errno)
#define SERVER_STRING "Server: athttp-server/2.0\r\n"
int startup(u_short port);
void not_found(int client);
void content(int client, FILE *resource);
void *acceptRequest(void * client);
void errorMessage(const char* msg);
int get_line(int sock, char *buf, int size);
void serve_file(int client, const char *filename);
void headers(int client, const char *filename);
/**********************************************************************/
/* Just a helping functions for error reporting using perror */
/**********************************************************************/
void errorMessage(const char* msg){
perror(msg);
}
/**********************************************************************/
/* Send a regular file to the client. Use headers, and report
* errors to client if they occur. */
/**********************************************************************/
void serve_file(int client, const char *filename) {
FILE *resource = NULL;
resource = fopen(filename, "r");
if (resource == NULL){
printf("%s\n", strerror(errno));
not_found(client);
} else {
headers(client, filename);
content(client, resource);
}
fclose(resource);
}
/**********************************************************************/
/* Return the informational HTTP headers about a file. */
/**********************************************************************/
void headers(int client, const char *filename) {
char buf[1024];
(void)filename; /* could use filename to determine file type */
strcpy(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, "\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Put the entire contents of a file out on a socket */
/**********************************************************************/
void content(int client, FILE *resource) {
char buf[1024];
fgets(buf, sizeof(buf), resource);
while (!feof(resource))
{
send(client, buf, strlen(buf), 0);
fgets(buf, sizeof(buf), resource);
}
}
/**********************************************************************/
/* Give a client a 404 not found
us message. */
/**********************************************************************/
void not_found(int client) {
char buf[1024];
sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "your request because the resource specified\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "is unavailable or nonexistent.\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Get a line from a socket, whether the line ends in a newline,
* carriage return, or a CRLF combination. Terminates the string read
* with a null character. If no newline indicator is found before the
* end of the buffer, the string is terminated with a null. If any of
* the above three line terminators is read, the last character of the
* string will be a linefeed and the string will be terminated with a
* null character.
*/
/**********************************************************************/
int get_line(int sock, char *buff, int size){
int i = 0;
char c = '\0';
long n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buff[i] = c;
i++;
}
else
c = '\n';
}
buff[i] = '\0';
return i;
}
/**********************************************************************/
/* A request causes a call to accept() on the server port.
* This function is executed by a seperate thread which is created when
* a connection is received */
/**********************************************************************/
void *acceptRequest(void * client) {
char buff[1024];
int numchars;
int method[255];
char path[512];
size_t i, j;
int client_socket = (int)client;
numchars = get_line(client_socket, buff, sizeof(buff));
/* This section gets the methods used */
i = 0; j = 0;
while (!isspace((int)buff[j]) && (i < sizeof(method) - 1))
{
method[i] = buff[j];
i++; j++;
}
method[i] = '\0';
/* This section gets the url requested */
char *url = NULL;
if(strtok(buff, " "))
{
url = strtok(NULL, " ");
if(url)
url = strdup(path);
}
/* This section identifies the path of file requested */
sprintf(path, "htdocs/%s", url);
if (path[strlen(path) - 1] == '/')
strcat(path, "index.html");
/* serve_file function serves the requested file */
serve_file(client_socket, path);
close(client_socket);
return 0;
}
/********************************************************************/
/* Creates socket and starts listening on given port
* bzero function zeroes various feild in server_addr struct
* This function basically implements the create socket, bind socket,
* and listen function. */
/********************************************************************/
int startup(u_short port){
/* Socket creating */
int serverfd = socket(AF_INET, SOCK_STREAM, 0);
if (serverfd < 0) {
fprintf(stderr, "Error opening socket");
return 0;
}
struct sockaddr_in server_addr;
bzero((char*)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9001);
server_addr.sin_addr.s_addr = INADDR_ANY;
/* Binding */
if (bind(serverfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
errorMessage("Error in connection");
return 0;
}
/* Listening */
if(listen(serverfd, 5) < 0){
errorMessage("Error listening");
return 0;
}
printf("Server listening at port 9001...\n");
return serverfd;
}
/********************************************************************/
int main(){
int server_socket = -1;
u_short port = 9001;
pthread_t newthread;
server_socket = startup(port);
struct sockaddr client_addr;
long clientfd;
int client_len = 0;
while (1) {
client_len = sizeof(client_addr);
clientfd = accept(server_socket, (struct sockaddr*)&client_addr, (socklen_t*)&client_len);
printf("Connection received\n");
if (clientfd < 0) {
errorMessage("Error accepting connection");
}
if (pthread_create(&newthread , NULL, acceptRequest, (void *)clientfd) != 0)
errorMessage("pthread creation");
}
return 0;
}