Subversion Repositories Tewi

Rev

Rev 193 | Rev 200 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: main.c 197 2024-09-29 07:13:35Z nishi $ */
2
 
16 nishi 3
#define SOURCE
4
 
43 nishi 5
#include "../config.h"
6
 
189 nishi 7
#include <unistd.h>
3 nishi 8
#include <stdio.h>
9
#include <stdbool.h>
10
#include <string.h>
16 nishi 11
#include <signal.h>
116 nishi 12
#include <stdlib.h>
3 nishi 13
 
43 nishi 14
#ifndef NO_SSL
6 nishi 15
#include <openssl/opensslv.h>
43 nishi 16
#endif
6 nishi 17
 
3 nishi 18
#include <cm_log.h>
62 nishi 19
#include <cm_string.h>
3 nishi 20
 
4 nishi 21
#include "tw_config.h"
8 nishi 22
#include "tw_server.h"
3 nishi 23
#include "tw_version.h"
24
 
51 nishi 25
#ifdef __MINGW32__
26
#include <windows.h>
27
#endif
28
 
182 nishi 29
#ifdef _PSP
30
#include <pspkernel.h>
31
#include <pspdebug.h>
183 nishi 32
#include <pspsdk.h>
33
#include <psputility.h>
34
#include <pspctrl.h>
35
#include <pspnet_apctl.h>
36
#include <pspwlan.h>
182 nishi 37
 
38
PSP_MODULE_INFO("Tewi HTTPd", PSP_MODULE_USER, 1, 1);
39
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
40
 
41
#define printf(...) pspDebugScreenPrintf(__VA_ARGS__)
183 nishi 42
#define STDERR_LOG(...) pspDebugScreenPrintf(__VA_ARGS__)
189 nishi 43
#elif defined(__ps2sdk__)
44
#include <debug.h>
45
#include <sifrpc.h>
46
 
47
#define printf(...) scr_printf(__VA_ARGS__)
48
#define STDERR_LOG(...) scr_printf(__VA_ARGS__)
191 nishi 49
#elif defined(__PPU__)
50
#include <rsx/gcm_sys.h>
51
#include <rsx/rsx.h>
52
#include <sysutil/video.h>
53
#include <malloc.h>
54
#include <sys/thread.h>
55
#include <stdarg.h>
197 nishi 56
#include <png.h>
191 nishi 57
 
58
#define printf(...) tt_printf(__VA_ARGS__)
59
#define STDERR_LOG(...) tt_printf(__VA_ARGS__)
183 nishi 60
#else
61
#define STDERR_LOG(...) fprintf(stderr, __VA_ARGS__)
182 nishi 62
#endif
63
 
3 nishi 64
extern bool cm_do_log;
18 nishi 65
extern struct tw_config config;
62 nishi 66
extern FILE* logfile;
3 nishi 67
 
18 nishi 68
char tw_server[2048];
69
 
62 nishi 70
int startup(int argc, char** argv);
71
 
72
#ifdef SERVICE
73
SERVICE_STATUS status;
74
SERVICE_STATUS_HANDLE status_handle;
75
 
70 nishi 76
void WINAPI servhandler(DWORD control) {
77
	switch(control) {
78
	case SERVICE_CONTROL_STOP:
79
	case SERVICE_CONTROL_SHUTDOWN:
80
		status.dwCurrentState = SERVICE_STOP_PENDING;
81
		break;
62 nishi 82
	}
83
	SetServiceStatus(status_handle, &status);
84
}
85
 
70 nishi 86
void WINAPI servmain(DWORD argc, LPSTR* argv) {
62 nishi 87
	logfile = fopen(PREFIX "/logs/tewi.log", "a");
88
	if(logfile == NULL) logfile = stderr;
89
	status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
90
	status.dwCurrentState = SERVICE_START_PENDING;
91
	status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
92
	status.dwWin32ExitCode = NO_ERROR;
93
	status.dwServiceSpecificExitCode = 0;
94
	status.dwCheckPoint = 0;
95
	status.dwWaitHint = 0;
96
	status_handle = RegisterServiceCtrlHandler("Tewi HTTPd", servhandler);
97
	if(status_handle == NULL) return;
98
	if(SetServiceStatus(status_handle, &status) == 0) return;
99
	int st = startup(argc, argv);
70 nishi 100
	if(st != -1) {
62 nishi 101
		status.dwWin32ExitCode = NO_ERROR;
102
		status.dwServiceSpecificExitCode = st;
103
		status.dwCurrentState = SERVICE_STOPPED;
104
		SetServiceStatus(status_handle, &status);
105
		return;
106
	}
107
	status.dwCurrentState = SERVICE_RUNNING;
108
	SetServiceStatus(status_handle, &status);
109
	tw_server_loop();
110
	status.dwCurrentState = SERVICE_STOPPED;
111
	SetServiceStatus(status_handle, &status);
112
}
113
#endif
114
 
183 nishi 115
int running = 1;
116
#ifdef _PSP
117
 
118
int psp_exit_callback(int arg1, int arg2, void* arg3) { running = 0; }
119
 
120
int psp_callback_thread(SceSize args, void* argp) {
121
	int cid;
122
	cid = sceKernelCreateCallback("Exit Call Back", psp_exit_callback, NULL);
123
	sceKernelRegisterExitCallback(cid);
124
	sceKernelSleepThreadCB();
125
	return 0;
126
}
127
#endif
128
 
191 nishi 129
#ifdef __PPU__
130
uint32_t depth_pitch;
131
uint32_t depth_offset;
132
uint32_t* depth_buffer;
133
 
134
#define CB_SIZE 0x100000
135
#define HOST_SIZE (32 * 1024 * 1024)
136
 
137
struct rsx_buffer {
138
	int width, height, id;
139
	uint32_t* ptr;
140
	uint32_t offset;
141
};
142
 
143
void wait_rsx(gcmContextData* ctx, uint32_t label) {
144
	rsxSetWriteBackendLabel(ctx, GCM_INDEX_TYPE_32B, label);
145
 
146
	rsxFlushBuffer(ctx);
147
 
148
	while(*(uint32_t*)gcmGetLabelAddress(GCM_INDEX_TYPE_32B) != label) usleep(50);
149
 
150
	label++;
151
}
152
 
153
void wait_rsx_until_idle(gcmContextData* ctx) {
154
	uint32_t label = 1;
155
	rsxSetWriteBackendLabel(ctx, GCM_INDEX_TYPE_32B, label);
156
	rsxSetWaitLabel(ctx, GCM_INDEX_TYPE_32B, label);
157
	label++;
158
	wait_rsx(ctx, label);
159
}
160
 
161
void get_resolution(int* width, int* height) {
162
	videoState state;
163
	videoResolution res;
164
	if(videoGetState(0, 0, &state) != 0) {
165
		return;
166
	}
167
 
168
	if(state.state != 0) {
169
		return;
170
	}
171
 
172
	if(videoGetResolution(state.displayMode.resolution, &res) != 0) {
173
		return;
174
	}
175
	*width = res.width;
176
	*height = res.height;
177
}
178
 
179
void make_buffer(struct rsx_buffer* buffer, int id) {
180
	int w, h;
181
	get_resolution(&w, &h);
182
 
183
	buffer->ptr = (uint32_t*)rsxMemalign(64, 4 * w * h);
184
	if(buffer->ptr == NULL) return;
185
 
186
	if(rsxAddressToOffset(buffer->ptr, &buffer->offset) != 0) return;
187
 
188
	if(gcmSetDisplayBuffer(id, buffer->offset, 4 * w, w, h) != 0) return;
189
	buffer->width = w;
190
	buffer->height = h;
191
	buffer->id = id;
192
}
193
 
194
gcmContextData* init_screen(void) {
195
	void* host = memalign(1024 * 1024, HOST_SIZE);
196
	gcmContextData* ctx = NULL;
197
	videoState state;
198
	videoConfiguration vconfig;
199
	videoResolution res;
200
	rsxInit(&ctx, CB_SIZE, HOST_SIZE, host);
201
	if(ctx == NULL) {
202
		free(host);
203
		return NULL;
204
	}
205
 
206
	if(videoGetState(0, 0, &state) != 0) {
207
		rsxFinish(ctx, 0);
208
		free(host);
209
		return NULL;
210
	}
211
 
212
	if(state.state != 0) {
213
		rsxFinish(ctx, 0);
214
		free(host);
215
		return NULL;
216
	}
217
 
218
	if(videoGetResolution(state.displayMode.resolution, &res) != 0) {
219
		rsxFinish(ctx, 0);
220
		free(host);
221
		return NULL;
222
	}
223
 
224
	memset(&vconfig, 0, sizeof(vconfig));
225
	vconfig.resolution = state.displayMode.resolution;
226
	vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
227
	vconfig.pitch = res.width * 4;
228
	vconfig.aspect = state.displayMode.aspect;
229
 
230
	wait_rsx_until_idle(ctx);
231
 
232
	if(videoConfigure(0, &vconfig, NULL, 0) != 0) {
233
		rsxFinish(ctx, 0);
234
		free(host);
235
		return NULL;
236
	}
237
 
238
	if(videoGetState(0, 0, &state) != 0) {
239
		rsxFinish(ctx, 0);
240
		free(host);
241
		return NULL;
242
	}
243
	gcmSetFlipMode(GCM_FLIP_VSYNC);
244
 
245
	depth_pitch = res.width * 4;
246
	depth_buffer = (uint32_t*)rsxMemalign(64, (res.height * depth_pitch) * 2);
247
	rsxAddressToOffset(depth_buffer, &depth_offset);
248
 
249
	gcmResetFlipStatus();
250
 
251
	return ctx;
252
}
253
 
254
void set_render_target(gcmContextData* context, struct rsx_buffer* buffer) {
255
	gcmSurface sf;
256
 
257
	sf.colorFormat = GCM_SURFACE_X8R8G8B8;
258
	sf.colorTarget = GCM_SURFACE_TARGET_0;
259
	sf.colorLocation[0] = GCM_LOCATION_RSX;
260
	sf.colorOffset[0] = buffer->offset;
261
	sf.colorPitch[0] = depth_pitch;
262
 
263
	sf.colorLocation[1] = GCM_LOCATION_RSX;
264
	sf.colorLocation[2] = GCM_LOCATION_RSX;
265
	sf.colorLocation[3] = GCM_LOCATION_RSX;
266
	sf.colorOffset[1] = 0;
267
	sf.colorOffset[2] = 0;
268
	sf.colorOffset[3] = 0;
269
	sf.colorPitch[1] = 64;
270
	sf.colorPitch[2] = 64;
271
	sf.colorPitch[3] = 64;
272
 
273
	sf.depthFormat = GCM_SURFACE_ZETA_Z16;
274
	sf.depthLocation = GCM_LOCATION_RSX;
275
	sf.depthOffset = depth_offset;
276
	sf.depthPitch = depth_pitch;
277
 
278
	sf.type = GCM_TEXTURE_LINEAR;
279
	sf.antiAlias = GCM_SURFACE_CENTER_1;
280
 
281
	sf.width = buffer->width;
282
	sf.height = buffer->height;
283
	sf.x = 0;
284
	sf.y = 0;
285
 
286
	rsxSetSurface(context, &sf);
287
}
288
 
289
void wait_flip(void) {
290
	while(gcmGetFlipStatus() != 0) usleep(200);
291
	gcmResetFlipStatus();
292
}
293
 
294
void flip(gcmContextData* ctx, uint32_t buffer) {
295
	if(gcmSetFlip(ctx, buffer) == 0) {
296
		rsxFlushBuffer(ctx);
297
		gcmSetWaitFlip(ctx);
298
	}
299
}
300
 
301
uint8_t* tvram;
302
 
303
extern uint8_t font[];
304
 
305
int tt_x = 0;
306
int tt_y = 0;
307
int tt_width;
308
int tt_height;
309
 
310
void tt_putstr(const char* str) {
311
	int i;
193 nishi 312
	for(i = 0; str[i] != 0; i++) {
191 nishi 313
		tvram[tt_y * tt_width + tt_x] = str[i];
193 nishi 314
		if(str[i] == '\n') {
191 nishi 315
			tt_x = 0;
316
			tt_y++;
193 nishi 317
		} else {
191 nishi 318
			tt_x++;
193 nishi 319
			if(tt_x == tt_width) {
191 nishi 320
				tt_x = 0;
321
				tt_y++;
322
			}
323
		}
193 nishi 324
		if(tt_y == tt_height) {
191 nishi 325
			tt_y--;
326
			int x, y;
193 nishi 327
			for(y = 0; y < tt_height - 1; y++) {
328
				for(x = 0; x < tt_width; x++) {
191 nishi 329
					tvram[y * tt_width + x] = tvram[(y + 1) * tt_width + x];
330
				}
331
			}
193 nishi 332
			for(x = 0; x < tt_width; x++) {
197 nishi 333
				tvram[(tt_height - 1) * tt_width + x] = 0x20;
191 nishi 334
			}
335
		}
336
	}
337
}
338
 
193 nishi 339
void tt_putchar(struct rsx_buffer* buffer, int x, int y, uint8_t c) {
191 nishi 340
	int i, j;
197 nishi 341
	if(c == 0) return;
191 nishi 342
	if(c < 0x20) c = 0x20;
343
	if(c >= 0x7f) c = 0x20;
197 nishi 344
	for(i = 0; i < 8; i++) {
345
		uint8_t l = i == 7 ? 0 : font[(c - 0x20) * 8 + i];
346
		for(j = 0; j < 6; j++) {
347
			uint32_t col = 0;
193 nishi 348
			if(l & (1 << 7)) {
197 nishi 349
				col = 0xffffff;
191 nishi 350
			}
351
			l = l << 1;
197 nishi 352
			buffer->ptr[(y * 8 + i) * buffer->width + x * 6 + j] = col;
191 nishi 353
		}
354
	}
355
}
356
 
357
void draw(struct rsx_buffer* buffer, int current) {
358
	int i, j, c;
359
	for(i = 0; i < buffer->height / 8; i++) {
360
		for(j = 0; j < buffer->width / 6; j++) {
361
			uint8_t c = tvram[i * (buffer->width / 6) + j];
362
			tt_putchar(buffer, j, i, c);
363
		}
364
	}
365
}
366
 
197 nishi 367
#define BUFFERS 1
191 nishi 368
gcmContextData* ctx;
369
struct rsx_buffer buffers[BUFFERS];
370
 
371
void text_thread(void* arg) {
372
	int current = 0;
373
	while(1) {
374
		wait_flip();
375
		draw(&buffers[current], current);
376
		flip(ctx, buffers[current].id);
377
		current++;
378
		if(current >= BUFFERS) current = 0;
379
	}
380
}
381
 
382
void tt_printf(const char* tmpl, ...) {
383
	va_list va;
384
	va_start(va, tmpl);
385
	int i;
386
	char cbuf[2];
387
	cbuf[1] = 0;
388
	char* log = cm_strdup("");
389
	for(i = 0; tmpl[i] != 0; i++) {
390
		if(tmpl[i] == '%') {
391
			i++;
193 nishi 392
			if(tmpl[i] == 's') {
191 nishi 393
				char* tmp = log;
394
				log = cm_strcat(tmp, va_arg(va, char*));
395
				free(tmp);
193 nishi 396
			} else if(tmpl[i] == 'd') {
191 nishi 397
				char buf[513];
398
				sprintf(buf, "%d", va_arg(va, int));
399
				char* tmp = log;
400
				log = cm_strcat(tmp, buf);
401
				free(tmp);
193 nishi 402
			} else if(tmpl[i] == '%') {
191 nishi 403
				char* tmp = log;
404
				log = cm_strcat(tmp, "%");
405
				free(tmp);
406
			}
407
		} else {
408
			cbuf[0] = tmpl[i];
409
			char* tmp = log;
410
			log = cm_strcat(tmp, cbuf);
411
			free(tmp);
412
		}
413
	}
414
	va_end(va);
415
	tt_putstr(log);
416
}
417
 
197 nishi 418
void show_png(void) {
419
	FILE* f = fopen(PREFIX "/pbtewi.png", "rb");
420
	if(f == NULL) {
421
		f = fopen(PREFIX "/../ICON0.PNG", "rb");
422
	}
423
	if(f == NULL) return;
424
	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
425
	png_infop info = png_create_info_struct(png);
426
	if(setjmp(png_jmpbuf(png))) {
427
		png_destroy_read_struct(&png, &info, NULL);
428
		fclose(f);
429
		return;
430
	}
431
 
432
	png_init_io(png, f);
433
	png_read_info(png, info);
434
 
435
	int width = png_get_image_width(png, info);
436
	int height = png_get_image_height(png, info);
437
	int depth = png_get_bit_depth(png, info);
438
	int type = png_get_color_type(png, info);
439
 
440
	if(depth == 16) png_set_strip_16(png);
441
	if(type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
442
	if(type == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_expand_gray_1_2_4_to_8(png);
443
	if(png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
444
	if(type == PNG_COLOR_TYPE_RGB || type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
445
	if(type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png);
446
	png_read_update_info(png, info);
447
	png_bytep* rows = (png_bytep*)malloc(sizeof(*rows) * (height));
448
 
449
	int i;
450
 
451
	for(i = 0; i < height; i++) {
452
		rows[i] = (png_byte*)malloc(png_get_rowbytes(png, info));
453
	}
454
 
455
	png_read_image(png, rows);
456
 
457
	for(i = 0; i < height; i++) {
458
		int j;
459
		for(j = 0; j < width; j++) {
460
			png_bytep byte = &(rows[i][j * 4]);
461
			uint32_t col = (byte[0] << 16) | (byte[1] << 8) | (byte[2]);
462
			int k;
463
			for(k = 0; k < BUFFERS; k++) {
464
				buffers[k].ptr[buffers[k].width * i - width + j] = col;
465
			}
466
		}
467
	}
468
 
469
	png_destroy_read_struct(&png, &info, NULL);
470
	fclose(f);
471
 
472
	for(i = 0; i < height; i++) {
473
		free(rows[i]);
474
	}
475
	free(rows);
476
}
477
 
191 nishi 478
#endif
479
 
3 nishi 480
int main(int argc, char** argv) {
62 nishi 481
	logfile = stderr;
482
#ifdef SERVICE
483
	SERVICE_TABLE_ENTRY table[] = {{"Tewi HTTPd", servmain}, {NULL, NULL}};
484
	StartServiceCtrlDispatcher(table);
485
#else
182 nishi 486
#ifdef _PSP
487
	pspDebugScreenInit();
488
	pspDebugScreenSetXY(0, 0);
183 nishi 489
	printf("PSP Bootstrap, Tewi/%s\n", tw_get_version());
490
	int thid = sceKernelCreateThread("update_thread", psp_callback_thread, 0x11, 0xfa0, 0, NULL);
491
	if(thid >= 0) {
492
		sceKernelStartThread(thid, 0, NULL);
493
	} else {
494
		printf("Failed to start thread\n");
495
		while(running) sceKernelDelayThread(50 * 1000);
496
		sceKernelExitGame();
497
	}
498
	sceCtrlSetSamplingCycle(0);
499
	sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
500
	sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON);
501
	sceUtilityLoadNetModule(PSP_NET_MODULE_INET);
502
	if(pspSdkInetInit()) {
503
		printf("Could not init the network\n");
504
		while(running) sceKernelDelayThread(50 * 1000);
505
		sceKernelExitGame();
506
	} else {
507
		printf("Network initialization successful\n");
508
	}
509
	if(sceWlanGetSwitchState() != 1) {
510
		printf("Turn the Wi-Fi switch on\n");
511
		while(sceWlanGetSwitchState() != 1) {
512
			sceKernelDelayThread(1000 * 1000);
513
		}
514
	} else {
515
		printf("Wi-Fi is turned on\n");
516
	}
517
	int i;
518
	int choice[100];
519
	int incr = 0;
520
	int last = 0;
521
	int cur = 0;
522
	for(i = 1; i < 100; i++) {
523
		choice[i - 1] = 0;
524
		netData name;
525
		netData data;
526
		if(sceUtilityCheckNetParam(i) != 0) continue;
527
		choice[incr++] = i;
528
		pspDebugScreenSetXY(0, 1 + 3 + incr - 1);
529
		if(incr == 1) printf("> ");
530
		pspDebugScreenSetXY(2, 1 + 3 + incr - 1);
531
		sceUtilityGetNetParam(i, 0, &name);
532
		sceUtilityGetNetParam(i, 1, &data);
533
		printf("SSID=%s", data.asString);
534
		sceUtilityGetNetParam(i, 4, &data);
535
		if(data.asString[0]) {
536
			sceUtilityGetNetParam(i, 5, &data);
537
			printf(" IPADDR=%s\n", data.asString);
538
		} else {
539
			printf(" DHCP\n");
540
		}
541
	}
542
	int press = 0;
543
	while(1) {
544
		if(!running) {
545
			sceKernelExitGame();
546
		}
547
		SceCtrlData c;
548
		sceCtrlReadBufferPositive(&c, 1);
549
		press = 0;
550
		if(c.Buttons & PSP_CTRL_DOWN) {
551
			if(cur < incr - 1) {
552
				cur++;
553
			}
554
			press = 1;
555
		} else if(c.Buttons & PSP_CTRL_UP) {
556
			if(cur > 0) {
557
				cur--;
558
			}
559
			press = -1;
560
		} else if(c.Buttons & PSP_CTRL_START) {
561
			break;
562
		}
563
		if(last != cur) {
564
			pspDebugScreenSetXY(0, 1 + 3 + last);
565
			printf("  ");
566
			pspDebugScreenSetXY(0, 1 + 3 + cur);
567
			printf("> ");
568
			last = cur;
569
		}
570
		if(press != 0) {
571
			while(1) {
572
				SceCtrlData c;
573
				sceCtrlReadBufferPositive(&c, 1);
574
				if(press == 1) {
575
					if(!(c.Buttons & PSP_CTRL_DOWN)) break;
576
				} else if(press == -1) {
577
					if(!(c.Buttons & PSP_CTRL_UP)) break;
578
				}
579
			}
580
		}
581
	}
582
	pspDebugScreenSetXY(0, 1 + 3 + incr + 1);
583
	int err = sceNetApctlConnect(choice[cur]);
584
	if(err != 0) {
585
		printf("Apctl initialization failure\n");
586
		while(running) sceKernelDelayThread(50 * 1000);
587
		sceKernelExitGame();
588
	} else {
589
		printf("Apctl initialization successful\n");
590
	}
591
	printf("Apctl connecting\n");
592
	while(1) {
593
		int state;
594
		err = sceNetApctlGetState(&state);
595
		if(err != 0) {
596
			printf("Apctl getting status failure\n");
597
			while(running) sceKernelDelayThread(50 * 1000);
598
			sceKernelExitGame();
599
		}
600
		if(state == 4) {
601
			break;
602
		}
603
		sceKernelDelayThread(50 * 1000);
604
	}
605
	union SceNetApctlInfo info;
606
	if(sceNetApctlGetInfo(8, &info) != 0) {
607
		printf("Got an unknown IP\n");
608
		while(running) sceKernelDelayThread(50 * 1000);
609
		sceKernelExitGame();
610
	}
611
	printf("Connected, My IP is %s\n", info.ip);
187 nishi 612
#elif defined(__PPU__)
191 nishi 613
	int i;
614
	ctx = init_screen();
615
	int w, h;
616
	get_resolution(&w, &h);
617
	tt_width = w / 6;
618
	tt_height = h / 8;
619
	tvram = malloc((w / 6) * (h / 8));
620
	for(i = 0; i < BUFFERS; i++) make_buffer(&buffers[i], i);
621
	flip(ctx, BUFFERS - 1);
622
	sys_ppu_thread_t id;
623
	sysThreadCreate(&id, text_thread, NULL, 1500, 0x1000, THREAD_JOINABLE, "TextThread");
187 nishi 624
	printf("PS3 Bootstrap, Tewi/%s\n", tw_get_version());
197 nishi 625
	show_png();
187 nishi 626
	netInitialize();
189 nishi 627
#elif defined(__ps2sdk__)
628
	SifInitRpc(0);
629
	init_scr();
630
	scr_printf("PS2 Bootstrap, Tewi/%s\n", tw_get_version());
631
	while(1)
632
		;
182 nishi 633
#endif
62 nishi 634
	int st = startup(argc, argv);
183 nishi 635
	if(st != -1) {
636
#ifdef _PSP
637
		printf("Error code %d\n", st);
638
		while(running) sceKernelDelayThread(50 * 1000);
639
		sceKernelExitGame();
640
#else
191 nishi 641
#ifdef __PPU__
642
		printf("Error code %d\n", st);
643
		while(1)
644
			;
645
#endif
183 nishi 646
		return st;
647
#endif
648
	}
62 nishi 649
	tw_server_loop();
650
#endif
183 nishi 651
#ifdef _PSP
652
	sceKernelExitGame();
653
#endif
168 nishi 654
	return 0;
62 nishi 655
}
656
 
70 nishi 657
int startup(int argc, char** argv) {
3 nishi 658
	int i;
18 nishi 659
	const char* confpath = PREFIX "/etc/tewi.conf";
70 nishi 660
	if(argv != NULL) {
62 nishi 661
		for(i = 1; i < argc; i++) {
662
			if(argv[i][0] == '-') {
663
				if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
664
					if(!cm_do_log) {
665
						cm_do_log = true;
70 nishi 666
#ifndef NO_SSL
62 nishi 667
						cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT);
70 nishi 668
#else
62 nishi 669
						cm_log("", "This is Tewi HTTPd, version %s", tw_get_version());
70 nishi 670
#endif
62 nishi 671
					} else {
672
						cm_do_log = true;
673
					}
674
				} else if(strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-C") == 0) {
675
					i++;
676
					if(argv[i] == NULL) {
183 nishi 677
						STDERR_LOG("Missing argument\n");
62 nishi 678
						return 1;
679
					}
680
					confpath = argv[i];
182 nishi 681
#ifndef _PSP
117 nishi 682
				} else if(strcmp(argv[i], "--logfile") == 0 || strcmp(argv[i], "-l") == 0) {
683
					i++;
684
					if(argv[i] == NULL) {
183 nishi 685
						STDERR_LOG("Missing argument\n");
117 nishi 686
						return 1;
687
					}
688
					if(logfile != NULL && logfile != stderr) {
689
						fclose(logfile);
690
					}
691
					logfile = fopen(argv[i], "a");
692
					if(logfile == NULL) {
183 nishi 693
						STDERR_LOG("Failed to open logfile\n");
117 nishi 694
						return 1;
695
					}
182 nishi 696
#endif
62 nishi 697
				} else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) {
698
					printf("Tewi HTTPd Tewi/%s\n", tw_get_version());
699
					printf("Under public domain.\n");
700
					printf("Original by 2024 Nishi\n");
701
					printf("\n");
702
					printf("Usage: %s [--config|-C config] [--verbose|-v] [--version|-V]\n", argv[0]);
119 nishi 703
					printf("--config  | -C config      : Specify config\n");
182 nishi 704
#ifndef _PSP
119 nishi 705
					printf("--logfile | -l logfile     : Specify logfile\n");
182 nishi 706
#endif
119 nishi 707
					printf("--verbose | -v             : Verbose mode\n");
708
					printf("--version | -V             : Version information\n");
62 nishi 709
					return 0;
3 nishi 710
				} else {
183 nishi 711
					STDERR_LOG("Unknown option: %s\n", argv[i]);
4 nishi 712
					return 1;
713
				}
3 nishi 714
			}
715
		}
716
	}
6 nishi 717
	tw_config_init();
18 nishi 718
	if(tw_config_read(confpath) != 0) {
183 nishi 719
		STDERR_LOG("Could not read the config\n");
4 nishi 720
		return 1;
721
	}
8 nishi 722
	if(tw_server_init() != 0) {
183 nishi 723
		STDERR_LOG("Could not initialize the server\n");
8 nishi 724
		return 1;
725
	}
18 nishi 726
	sprintf(tw_server, "Tewi/%s (%s)%s", tw_get_version(), tw_get_platform(), config.extension == NULL ? "" : config.extension);
62 nishi 727
	char* r = cm_strcat(tw_server, " running...");
728
	cm_force_log(r);
729
	free(r);
16 nishi 730
#ifndef __MINGW32__
731
	signal(SIGCHLD, SIG_IGN);
90 nishi 732
	signal(SIGPIPE, SIG_IGN);
50 nishi 733
#else
734
	SetConsoleTitle(tw_server);
16 nishi 735
#endif
62 nishi 736
	return -1;
3 nishi 737
}