6
6
#include <sys/socket.h>
7
7
#include <netinet/in.h>
8
8
#include <arpa/inet.h>
9
- #include <ctype.h>
9
+ #ifdef __PPU__
10
+ #include <net/poll.h>
11
+ #else
12
+ #include <poll.h>
13
+ #endif
10
14
11
15
#include "dbglogger.h"
12
16
#include "systhread.h"
@@ -20,7 +24,7 @@ const char ERROR_PAGE[] = "<HTML><HEAD><TITLE>.:: HTTP/Error</TITLE></HEAD>"
20
24
"<BODY BGCOLOR=\"#FFFFFF\" ALINK=\"#000000\" VLINK=\"#000000\" LINK=\"#000000\">"
21
25
"<FONT FACE=\"Arial\"><H1>.:: <I>HTTP/Error</I></H1></FONT>"
22
26
"<CENTER><IMG SRC=\"https://bucanero.github.io/bucanero/error.gif\" WIDTH=\"228\" HEIGHT=\"155\" BORDER=\"0\" ALT=\"Error\"></CENTER>"
23
- "<P ALIGN=\"RIGHT\"><B><FONT FACE=\"Arial\" SIZE=\"3\"><< <A HREF=\"javascript:history.go(-1);\">go back</A> ::.</FONT></B></P></BODY></HTML>" ;
27
+ "<P ALIGN=\"RIGHT\"><B><FONT FACE=\"Arial\" SIZE=\"3\"><< <A HREF=\"javascript:history.go(-1);\">go back</A> ::.</FONT></B></P></BODY></HTML>\r\n " ;
24
28
25
29
typedef struct {
26
30
int idx ;
@@ -37,7 +41,7 @@ static struct {
37
41
{".html" , "text/html" },
38
42
{".txt" , "text/plain" },
39
43
{".png" , "image/png" },
40
- {".PNG " , "image/png " },
44
+ {".gif " , "image/gif " },
41
45
{".jpg" , "image/jpeg" },
42
46
{".xml" , "application/xml" },
43
47
{".css" , "text/css" },
@@ -47,6 +51,8 @@ static struct {
47
51
48
52
static void * threads = NULL ;
49
53
static int run_server = 0 ;
54
+ static int sockfd ;
55
+
50
56
51
57
static char * getContentType (const char * path )
52
58
{
@@ -60,7 +66,23 @@ static char* getContentType(const char *path)
60
66
return extensions [0 ].filetype ;
61
67
}
62
68
63
- static int serveFile (int socket , const char * path )
69
+ static void sendResponse (int fd , char * buf , const char * code , const char * type , long len , const char * page )
70
+ {
71
+ snprintf (buf , BUFSIZ , "HTTP/1.0 %s\r\n"
72
+ "Connection: close\r\n"
73
+ "Content-Type: %s\r\n"
74
+ "Content-Length: %ld\r\n"
75
+ "Server: dbglogger/1.0 (PlayStation)\r\n\r\n%s" , code , type , len , page ? page : "" );
76
+ if (send (fd , buf , strlen (buf ), 0 ) == -1 )
77
+ dbglogger_log ("(error) send" );
78
+ }
79
+
80
+ static inline void errorPage (int fd , char * buf )
81
+ {
82
+ sendResponse (fd , buf , "404 Not Found" , "text/html" , strlen (ERROR_PAGE ), ERROR_PAGE );
83
+ }
84
+
85
+ static int serveFile (int socket , const char * path , char method )
64
86
{
65
87
FILE * fd ;
66
88
int readRet = strlen (path );
@@ -70,10 +92,7 @@ static int serveFile(int socket, const char* path)
70
92
71
93
if ((readRet > 0 && path [readRet - 1 ] == '/' ) || (fd = fopen (path , "rb" )) == NULL )
72
94
{
73
- snprintf (buf , BUFSIZ , "HTTP/1.0 404 Not Found\r\nContent-Type: text/html\r\n\r\n%s\r\n" , ERROR_PAGE );
74
- if (send (socket , buf , strlen (buf ), 0 ) == -1 )
75
- dbglogger_log ("(error) send" );
76
-
95
+ errorPage (socket , buf );
77
96
return 404 ;
78
97
}
79
98
@@ -82,9 +101,13 @@ static int serveFile(int socket, const char* path)
82
101
fseek (fd , 0 , SEEK_SET );
83
102
84
103
// Write header
85
- snprintf (buf , BUFSIZ , "HTTP/1.0 200 OK\r\nContent-Length: %ld\r\n"
86
- "Content-Type: %s\r\nServer: dbglogger\r\n\r\n" , fsize , getContentType (path ));
87
- send (socket , buf , strlen (buf ), 0 );
104
+ sendResponse (socket , buf , "200 OK" , getContentType (path ), fsize , NULL );
105
+
106
+ // skip data for HEAD method
107
+ if (method == 'H' ) {
108
+ fclose (fd );
109
+ return 200 ;
110
+ }
88
111
89
112
// Read file and Write to body
90
113
while ((readRet = fread (buf , 1 , BUFSIZ , fd )) > 0 )
@@ -101,13 +124,12 @@ static int serveFile(int socket, const char* path)
101
124
return 200 ;
102
125
}
103
126
104
- static dWebRequest_t * parseRequest (const char * buf )
127
+ static dWebRequest_t * parseRequest (const char * start )
105
128
{
106
129
dWebRequest_t * newRequest ;
107
- const char * start = buf ;
108
130
const char * end ;
109
131
110
- if (strncmp ("GET" , start , 3 ) != 0 )
132
+ if (strncmp ("GET" , start , 3 ) != 0 && strncmp ( "HEAD" , start , 4 ) != 0 )
111
133
{
112
134
dbglogger_log ("[!] Unsupported HTTP Method" );
113
135
return NULL ;
@@ -116,16 +138,12 @@ static dWebRequest_t * parseRequest(const char *buf)
116
138
newRequest = malloc (sizeof (dWebRequest_t ));
117
139
memset (newRequest , 0 , sizeof (dWebRequest_t ));
118
140
119
- strncpy ( newRequest -> method , "GET" , sizeof ( newRequest -> method )) ;
141
+ newRequest -> method = start [ 0 ] ;
120
142
// Jump past: "GET "
121
- start += 4 ;
122
-
123
- end = start ;
124
- while (* end && !isspace (* end ))
125
- ++ end ;
143
+ start = strchr (start , ' ' ) + 1 ;
144
+ end = strchr (start , ' ' );
126
145
127
- size_t pathLen = (end - start );
128
- strncpy (newRequest -> resource , start , pathLen );
146
+ strncpy (newRequest -> resource , start , end - start );
129
147
// newRequest->resource[pathLen] = '\0';
130
148
131
149
return newRequest ;
@@ -139,55 +157,104 @@ static void* get_in_addr(struct sockaddr* sa)
139
157
return NULL ;
140
158
}
141
159
142
- static void thread_handler (void * td )
160
+ static void client_handler (void * td )
143
161
{
144
- int new_fd ;
145
162
threadData_t * data = (threadData_t * ) td ;
146
- struct sockaddr_in their_addr ; // connector's address
147
- socklen_t sin_size = sizeof (their_addr );
148
163
char buf [BUFSIZ ];
149
164
165
+ dbglogger_printf ("Thread #%d started (0x%08X)\n" , data -> idx , data -> sockfd );
166
+
150
167
while (run_server )
151
168
{
152
- dbglogger_printf ("Thread #%d running (0x%08X)\n" , data -> idx , data -> sockfd );
153
-
154
- new_fd = accept (data -> sockfd , (struct sockaddr * ) & their_addr , & sin_size );
155
- if (new_fd == -1 || !run_server )
169
+ if (data -> sockfd < 0 )
156
170
{
157
- dbglogger_log ("(error) accept" );
158
- free (td );
159
- sys_thread_exit (0 );
171
+ usleep (5000 );
172
+ continue ;
160
173
}
161
174
162
- inet_ntop (their_addr .sin_family , get_in_addr ((struct sockaddr * ) & their_addr ), buf , sizeof (buf ));
163
- dbglogger_printf ("Thread #%d: got connection from %s\n" , data -> idx , buf );
175
+ dbglogger_printf ("Client #%d running (0x%08X)\n" , data -> idx , data -> sockfd );
164
176
165
177
memset (buf , 0 , BUFSIZ );
166
- recv (new_fd , buf , BUFSIZ , 0 );
178
+ recv (data -> sockfd , buf , BUFSIZ , 0 );
167
179
168
- dbglogger_printf ("---\n%s\n---\n" , buf );
180
+ dbglogger_printf ("%d>>\n ---\n%s\n---\n" , data -> idx , buf );
169
181
dWebRequest_t * newRequest = parseRequest (buf );
170
182
171
183
// If parsing failed shutdown and exit
172
184
if (newRequest )
173
185
{
174
186
if (data -> reqHandler && data -> reqHandler (newRequest , buf ))
175
- serveFile (new_fd , buf );
187
+ serveFile (data -> sockfd , buf , newRequest -> method );
188
+ else
189
+ errorPage (data -> sockfd , buf );
176
190
177
191
free (newRequest );
178
- }
192
+ }
193
+ else sendResponse (data -> sockfd , buf , "501 Not Implemented" , "text/plain" , 0 , NULL );
194
+
195
+ shutdown (data -> sockfd , SHUT_RDWR );
196
+ close (data -> sockfd );
197
+ data -> sockfd = -1 ;
198
+ }
199
+
200
+ dbglogger_log ("(end) #%d" , data -> idx );
201
+ sys_thread_exit (0 );
202
+ }
203
+
204
+ static void httpd (void * td )
205
+ {
206
+ int new_fd ;
207
+ threadData_t * data = (threadData_t * ) td ;
208
+ struct pollfd pfds [1 ];
209
+ struct sockaddr_in their_addr ; // connector's address
210
+ socklen_t sin_size = sizeof (their_addr );
211
+ char str [INET_ADDRSTRLEN ];
212
+
213
+ pfds [0 ].fd = data -> sockfd ;
214
+ pfds [0 ].events = POLLIN ;
215
+ pfds [0 ].revents = 0 ;
216
+
217
+ while (run_server )
218
+ {
219
+ dbglogger_log ("webserver:%d running (0x%08X)" , run_server , data -> sockfd );
179
220
180
- close (new_fd );
221
+ new_fd = poll (pfds , 1 , 500 );
222
+ if (new_fd <= 0 || !(pfds [0 ].revents & POLLIN ) || !run_server )
223
+ continue ;
224
+
225
+ new_fd = accept (data -> sockfd , (struct sockaddr * ) & their_addr , & sin_size );
226
+ if (new_fd < 0 )
227
+ {
228
+ dbglogger_log ("(error) accept" );
229
+ continue ;
230
+ }
231
+
232
+ inet_ntop (their_addr .sin_family , get_in_addr ((struct sockaddr * ) & their_addr ), str , sizeof (str ));
233
+ dbglogger_printf ("httpd #%d: got connection from %s\n" , data -> idx , str );
234
+
235
+ while (new_fd )
236
+ {
237
+ for (int i = 1 ; new_fd && i <= NUM_THREADS ; i ++ )
238
+ if (data [i ].sockfd < 0 )
239
+ {
240
+ data [i ].sockfd = new_fd ;
241
+ new_fd = 0 ;
242
+ }
243
+ usleep (new_fd ? 1000 : 0 );
244
+ }
181
245
}
182
246
183
- dbglogger_log ("(end)" );
247
+ shutdown (data -> sockfd , SHUT_RDWR );
248
+ close (data -> sockfd );
249
+
250
+ dbglogger_log ("(stop) httpd" );
184
251
free (td );
185
252
sys_thread_exit (0 );
186
253
}
187
254
188
255
int web_start (int port , dWebReqHandler_t handler )
189
256
{
190
- int sockfd , yes = 1 ;
257
+ int yes = 1 ;
191
258
struct sockaddr_in sa ;
192
259
193
260
memset (& sa , 0 , sizeof (sa ));
@@ -213,52 +280,42 @@ int web_start(int port, dWebReqHandler_t handler)
213
280
return 0 ;
214
281
}
215
282
216
- if ((threads = sys_thread_alloc (NUM_THREADS )) == NULL ) {
283
+ if ((threads = sys_thread_alloc (NUM_THREADS + 1 )) == NULL ) {
217
284
dbglogger_log ("(error) thread alloc" );
218
285
return 0 ;
219
286
}
220
287
221
288
run_server = port ;
222
- dbglogger_log ("webserver:%d starting threads..." , port );
289
+ dbglogger_log ("webserver:%d starting httpd..." , port );
290
+
291
+ threadData_t * tdata = malloc (sizeof (threadData_t ) * (NUM_THREADS + 1 ));
292
+ tdata [0 ].idx = 0 ;
293
+ tdata [0 ].sockfd = sockfd ;
294
+ tdata [0 ].reqHandler = NULL ;
223
295
224
- for (int i = 0 ; i < NUM_THREADS ; ++ i )
296
+ sys_thread_create2 (threads , 0 , & httpd , tdata );
297
+
298
+ for (int i = 1 ; i <= NUM_THREADS ; i ++ )
225
299
{
226
- threadData_t * tdata = malloc (sizeof (threadData_t ));
227
- tdata -> idx = i ;
228
- tdata -> sockfd = sockfd ;
229
- tdata -> reqHandler = handler ;
300
+ tdata [i ].idx = i ;
301
+ tdata [i ].sockfd = -1 ;
302
+ tdata [i ].reqHandler = handler ;
230
303
231
- sys_thread_create2 (threads , i , & thread_handler , tdata );
304
+ sys_thread_create2 (threads , i , & client_handler , & tdata [ i ] );
232
305
}
233
306
234
- dbglogger_log ("webserver:%d running" , port );
235
307
return 1 ;
236
308
}
237
309
238
- static void end_socket (int port )
239
- {
240
- struct sockaddr_in stSockAddr ;
241
- int socketFD = socket (AF_INET , SOCK_STREAM , IPPROTO_TCP );
242
-
243
- memset (& stSockAddr , 0 , sizeof (stSockAddr ));
244
- stSockAddr .sin_family = AF_INET ;
245
- stSockAddr .sin_port = htons (port );
246
- inet_pton (AF_INET , "127.0.0.1" , & stSockAddr .sin_addr );
247
-
248
- connect (socketFD , (struct sockaddr * )& stSockAddr , sizeof (stSockAddr ));
249
- close (socketFD );
250
- }
251
-
252
310
void web_stop ()
253
311
{
254
- int port = run_server ;
255
- run_server = 0 ;
256
-
257
- for (int i = 0 ; i < NUM_THREADS ; ++ i )
258
- {
259
- dbglogger_log ("stop %d" , i );
260
- end_socket (port );
261
- }
312
+ if (!run_server )
313
+ return ;
262
314
315
+ run_server = 0 ;
316
+ shutdown (sockfd , SHUT_RDWR );
317
+ close (sockfd );
263
318
sys_thread_free (threads );
319
+
320
+ dbglogger_log ("webserver:off" );
264
321
}
0 commit comments