From 288490094a7fe9167747dc78d416940759a31197 Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Tue, 5 Dec 2006 13:23:07 +0000 Subject: - Massive EOL normalization & 'svn:eol-style native' flag setting for all txt/conf/h/c files. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9410 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/plugins/gui.c | 202 +++---- src/plugins/gui.txt | 28 +- src/plugins/httpd.c | 1502 ++++++++++++++++++++++++------------------------- src/plugins/httpd.h | 214 +++---- src/plugins/httpd.txt | 38 +- src/plugins/pid.c | 108 ++-- src/plugins/sample.c | 154 ++--- src/plugins/sig.c | 422 +++++++------- src/plugins/upnp.txt | 60 +- 9 files changed, 1364 insertions(+), 1364 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/gui.c b/src/plugins/gui.c index 6c9a8d85c..e8c097d21 100644 --- a/src/plugins/gui.c +++ b/src/plugins/gui.c @@ -1,101 +1,101 @@ - -#include -#include -#include -#include "../common/plugin.h" -//Needed for strcmpi -#include "../common/mmo.h" - -// "I'm Alive" and "Flush stdout" Originally by Mugendai -// Ported to plugin by Celest - -PLUGIN_INFO = { - "AthenaGUI", - PLUGIN_CORE, - "1.0", - PLUGIN_VERSION, - "Core plugin for Athena GUI functions" -}; - -PLUGIN_EVENTS_TABLE = { - { "gui_init", "Plugin_Init" }, - { NULL, NULL } -}; - -unsigned int (*gettick)(); -int (*add_timer_func_list)(int (*)(int,unsigned int,int,int),char*); -int (*add_timer_interval)(unsigned int,int (*)(int,unsigned int,int,int),int,int,int); - -//----------------------------------------------------- -//I'm Alive Alert -//Used to output 'I'm Alive' every few seconds -//Intended to let frontends know if the app froze -//----------------------------------------------------- -int imalive_timer(int tid, unsigned int tick, int id, int data){ - printf("I'm Alive\n"); - return 0; -} - -//----------------------------------------------------- -//Flush stdout -//stdout buffer needs flushed to be seen in GUI -//----------------------------------------------------- -int flush_timer(int tid, unsigned int tick, int id, int data){ - fflush(stdout); - return 0; -} - -void gui_init () -{ - char line[1024], w1[1024], w2[1024]; - int flush_on = 0; - int flush_time = 100; - int imalive_on = 0; - int imalive_time = 30; - char **argv; - int *argc; - FILE *fp; - int i; - - IMPORT_SYMBOL(argc, 2); - IMPORT_SYMBOL(argv, 3); - IMPORT_SYMBOL(gettick, 5); - IMPORT_SYMBOL(add_timer_interval, 8); - IMPORT_SYMBOL(add_timer_func_list, 9); - - do { - fp = fopen("plugins/gui.conf","r"); - if (fp == NULL) - break; - - while(fgets(line, sizeof(line) -1, fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) { - if(strcmpi(w1,"imalive_on")==0){ - imalive_on = atoi(w2); - } else if(strcmpi(w1,"imalive_time")==0){ - imalive_time = atoi(w2); - } else if(strcmpi(w1,"flush_on")==0){ - flush_on = atoi(w2); - } else if(strcmpi(w1,"flush_time")==0){ - flush_time = atoi(w2); - } - } - } - fclose(fp); - } while (0); - - for (i = 1; i < *argc ; i++) - if (strcmp(argv[i], "--gui") == 0) - flush_on = imalive_on = 1; - - if (flush_on) { - add_timer_func_list(flush_timer, "flush_timer"); - add_timer_interval(gettick()+1000,flush_timer,0,0,flush_time); - } - if (imalive_on) { - add_timer_func_list(imalive_timer, "imalive_timer"); - add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000); - } -} + +#include +#include +#include +#include "../common/plugin.h" +//Needed for strcmpi +#include "../common/mmo.h" + +// "I'm Alive" and "Flush stdout" Originally by Mugendai +// Ported to plugin by Celest + +PLUGIN_INFO = { + "AthenaGUI", + PLUGIN_CORE, + "1.0", + PLUGIN_VERSION, + "Core plugin for Athena GUI functions" +}; + +PLUGIN_EVENTS_TABLE = { + { "gui_init", "Plugin_Init" }, + { NULL, NULL } +}; + +unsigned int (*gettick)(); +int (*add_timer_func_list)(int (*)(int,unsigned int,int,int),char*); +int (*add_timer_interval)(unsigned int,int (*)(int,unsigned int,int,int),int,int,int); + +//----------------------------------------------------- +//I'm Alive Alert +//Used to output 'I'm Alive' every few seconds +//Intended to let frontends know if the app froze +//----------------------------------------------------- +int imalive_timer(int tid, unsigned int tick, int id, int data){ + printf("I'm Alive\n"); + return 0; +} + +//----------------------------------------------------- +//Flush stdout +//stdout buffer needs flushed to be seen in GUI +//----------------------------------------------------- +int flush_timer(int tid, unsigned int tick, int id, int data){ + fflush(stdout); + return 0; +} + +void gui_init () +{ + char line[1024], w1[1024], w2[1024]; + int flush_on = 0; + int flush_time = 100; + int imalive_on = 0; + int imalive_time = 30; + char **argv; + int *argc; + FILE *fp; + int i; + + IMPORT_SYMBOL(argc, 2); + IMPORT_SYMBOL(argv, 3); + IMPORT_SYMBOL(gettick, 5); + IMPORT_SYMBOL(add_timer_interval, 8); + IMPORT_SYMBOL(add_timer_func_list, 9); + + do { + fp = fopen("plugins/gui.conf","r"); + if (fp == NULL) + break; + + while(fgets(line, sizeof(line) -1, fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) { + if(strcmpi(w1,"imalive_on")==0){ + imalive_on = atoi(w2); + } else if(strcmpi(w1,"imalive_time")==0){ + imalive_time = atoi(w2); + } else if(strcmpi(w1,"flush_on")==0){ + flush_on = atoi(w2); + } else if(strcmpi(w1,"flush_time")==0){ + flush_time = atoi(w2); + } + } + } + fclose(fp); + } while (0); + + for (i = 1; i < *argc ; i++) + if (strcmp(argv[i], "--gui") == 0) + flush_on = imalive_on = 1; + + if (flush_on) { + add_timer_func_list(flush_timer, "flush_timer"); + add_timer_interval(gettick()+1000,flush_timer,0,0,flush_time); + } + if (imalive_on) { + add_timer_func_list(imalive_timer, "imalive_timer"); + add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000); + } +} diff --git a/src/plugins/gui.txt b/src/plugins/gui.txt index 87f5ac742..03554aa8d 100644 --- a/src/plugins/gui.txt +++ b/src/plugins/gui.txt @@ -1,15 +1,15 @@ -// -// GUI Plugin Configuration -// - -// Enable I'm Alive? -imalive_on: 0 - -// How often to display I'm Alive (in seconds) -imalive_time: 30 - -// Enable GUI flushing for Mugendai's GUI? -flush_on: 0 - -// How often to flush the buffer on-screen (in seconds) +// +// GUI Plugin Configuration +// + +// Enable I'm Alive? +imalive_on: 0 + +// How often to display I'm Alive (in seconds) +imalive_time: 30 + +// Enable GUI flushing for Mugendai's GUI? +flush_on: 0 + +// How often to flush the buffer on-screen (in seconds) flush_time: 60 \ No newline at end of file diff --git a/src/plugins/httpd.c b/src/plugins/httpd.c index de994766f..5e88c7dfd 100644 --- a/src/plugins/httpd.c +++ b/src/plugins/httpd.c @@ -1,751 +1,751 @@ - -#ifdef __WIN32 -#include -#else -#include -#endif -#include -#include -#include -#include - -#include "../common/db.h" -//mmo required for definition of stricmp -#include "../common/mmo.h" -#include "../common/utils.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/plugin.h" -//#include "httpd.h" - -/** Created by End_of_Exam, ported to plugin and modified by Celest **/ - -PLUGIN_INFO = { - "HttpDaemon", - PLUGIN_CORE, - "0.1", - PLUGIN_VERSION, - "HTTP Daemon" -}; - -PLUGIN_EVENTS_TABLE = { - { "do_init", "Plugin_Init" }, - { "do_final", "Plugin_Final" }, - { NULL, NULL } -}; - -enum HTTPD_STATUS { - HTTPD_REQUEST_WAIT = 0, // リクエスト待ち - HTTPD_REQUEST_WAIT_POST, // リクエスト待ち(post) - HTTPD_REQUEST_OK, // リクエスト解釈完了 - HTTPD_SEND_HEADER, // ヘッダ送信完了 - HTTPD_WAITING_SEND // データが送信し終わるまで待っている状態 -}; -enum { - HTTPD_METHOD_UNKNOWN = 0, - HTTPD_METHOD_GET, - HTTPD_METHOD_POST -}; - -struct httpd_session_data { - int fd; - int status; - int http_ver; - int header_len; - int data_len; - int method; - int persist; - int request_count; - unsigned int tick; - const unsigned char* url; - const unsigned char* query; -}; - -// undefine socket operations included from socket.h, -// since we are going to use 'sessiond' instead -#undef RFIFOP -#undef RFIFOREST -#undef WFIFOP - -#define RFIFOP(fd,pos) (sessiond[fd]->rdata+sessiond[fd]->rdata_pos+(pos)) -#define RFIFOREST(fd) (sessiond[fd]->rdata_size-sessiond[fd]->rdata_pos) -#define WFIFOP(fd,pos) (sessiond[fd]->wdata+sessiond[fd]->wdata_size+(pos)) - -struct socket_data **sessiond; -char *server_type; -unsigned int (*gettick)(); -int (*add_timer_interval)(unsigned int,int (*)(int,unsigned int,int,int),int,int,int); -int *max_fd; -int (*delete_sessiond)(int); -int (*_WFIFOSET)(int,int); -int (*_RFIFOSKIP)(int,int); - -static int max_persist_requests = 32; // 持続通信での最大リクエスト数 -static int request_timeout[] = { 2500, 60*1000 }; // タイムアウト(最初、持続) -static char document_root[256] = "./httpd/"; // ドキュメントルート - -// httpd に入っているページと、呼び出すコールバック関数の一覧 -struct dbt *httpd_files; - -void httpd_send(struct httpd_session_data*, int, const char *, int, const void *); - -int httpd_check (struct socket_data *sd) -{ - // httpd に回すどうかの判定がまだ行われてない - // 先頭2バイトが GE ならhttpd に回してみる - if (sd->rdata_size >= 2 && - sd->rdata[0] == 'G' && sd->rdata[1] == 'E') - return 1; - - return 0; -} - -int httpd_strcasencmp(const char *s1, const char *s2,int len) -{ - while(len-- && (*s1 || *s2) ) { - if((*s1 | 0x20) != (*s2 | 0x20)) { - return ((*s1 | 0x20) > (*s2 | 0x20) ? 1 : -1); - } - s1++; s2++; - } - return 0; -} - -// httpd にページを追加する -// for などでページ名を合成できるように、key はstrdup()したものを使う - -void httpd_pages (const char* url, void (*httpd_func)(struct httpd_session_data*, const char*)) -{ - if (strdb_get(httpd_files,(unsigned char*)(url+1)) == NULL) { - strdb_put(httpd_files, (unsigned char*)aStrdup(url+1), httpd_func); - } else { - strdb_put(httpd_files, (unsigned char*)(url+1), httpd_func); - } -} - -static void (*httpd_default)(struct httpd_session_data* sd,const char* url); - -const char *httpd_get_error( struct httpd_session_data* sd, int* status ) -{ - const char* msg; - // httpd のステータスを決める - switch(*status) { - case 200: msg = "OK"; break; - case 400: msg = "Bad Request"; break; - case 401: msg = "Unauthorized"; break; // 未使用 - case 403: msg = "Forbidden"; break; // 未使用 - case 404: msg = "Not Found"; break; - case 408: msg = "Request Timedout"; break; - case 411: msg = "Length Required"; break; - case 413: msg = "Request Entity Too Large"; break; - default: - *status = 500; msg = "Internal Server Error"; break; - } - return msg; -} - -void httpd_send_error(struct httpd_session_data* sd,int status) -{ - const char* msg = httpd_get_error( sd, &status ); - httpd_send(sd, status, "text/plain",strlen(msg),msg); -} - -void httpd_send_head (struct httpd_session_data* sd, int status, const char *content_type, int content_len) -{ - char head[256]; - int len; - const char* msg; - - if (sd->status != HTTPD_REQUEST_OK) - return; - msg = httpd_get_error( sd, &status ); - - if(content_len == -1 || ++sd->request_count >= max_persist_requests ) { - // 長さが分からない or リクエスト限界を超えたので切断する - len = sprintf( - head, - "HTTP/1.%d %d %s\r\nContent-Type: %s\r\nConnection: close\r\n\r\n", - sd->http_ver,status,msg,content_type - ); - sd->persist = 0; - len = sprintf( - head, - "HTTP/1.%d %d %s\r\nContent-Type: %s\r\n\r\n", - sd->http_ver,status,msg,content_type - ); - sd->http_ver = 0; // 長さが分からないので、HTTP/1.0 扱い(自動切断)にする - } else { - len = sprintf( - head, - "HTTP/1.%d %d %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n", - sd->http_ver,status,msg,content_type,content_len - ); - } - memcpy(WFIFOP(sd->fd,0),head,len); - _WFIFOSET(sd->fd,len); - sd->status = HTTPD_SEND_HEADER; - sd->data_len = content_len; -} - -void httpd_send_data (struct httpd_session_data* sd, int content_len, const void *data) -{ - const char* msg = (const char*)data; - if (sd->status == HTTPD_REQUEST_OK) { - // ヘッダの送信忘れているので、適当に補う - httpd_send_head(sd,200,"application/octet-stream",-1); - } else if(sd->status != HTTPD_SEND_HEADER && sd->status != HTTPD_WAITING_SEND) { - return; - } - sd->data_len -= content_len; - - // 巨大なサイズのファイルも送信出来るように分割して送る - while (content_len > 0) { - int send_byte = content_len; - if(send_byte > 12*1024) send_byte = 12*1024; - memcpy(WFIFOP(sd->fd,0),msg,send_byte); - _WFIFOSET(sd->fd,send_byte); - msg += send_byte; content_len -= send_byte; - } - sd->status = HTTPD_WAITING_SEND; -} - -void httpd_send (struct httpd_session_data* sd, int status, const char *content_type, int content_len, const void *data) -{ - httpd_send_head(sd,status,content_type,content_len); - httpd_send_data(sd,content_len,data); -} - -void httpd_parse_header(struct httpd_session_data* sd); -void httpd_parse_request_ok(struct httpd_session_data *sd); - -int httpd_parse (int fd) -{ - struct httpd_session_data *sd = (struct httpd_session_data *)sessiond[fd]->session_data2; - if (sessiond[fd]->eof) { - delete_sessiond(fd); - return 0; - } - if (sd == NULL) { - sd = (struct httpd_session_data*) aMalloc (sizeof(struct httpd_session_data)); - sd->fd = fd; - sessiond[fd]->session_data2 = sd; - sd->tick = gettick(); - sd->persist = 0; - sd->request_count = 0; - } - printf ("status %d\n", sd->status); - switch(sd->status) { - case HTTPD_REQUEST_WAIT: - // リクエスト待ち - if(RFIFOREST(fd) > 1024) { - // リクエストが長すぎるので、エラー扱いする - sd->status = HTTPD_REQUEST_OK; - httpd_send_error(sd,400); // Bad Request - } else if( (int)( gettick() - sd->tick ) > request_timeout[sd->persist] ) { - // リクエストに時間がかかりすぎているので、エラー扱いする - sd->status = HTTPD_REQUEST_OK; - httpd_send_error(sd,408); // Request Timeout - } else if(sd->header_len == RFIFOREST(fd)) { - // 状態が以前と同じなので、リクエストを再解析する必要は無い - } else { - int limit = RFIFOREST(fd); - unsigned char *req = RFIFOP(fd,0); - sd->header_len = RFIFOREST(fd); - do { - if(*req == '\n' && limit > 0) { - limit--; req++; - if(*req == '\r' && limit > 0) { limit--; req++; } - if(*req == '\n') { - // HTTPヘッダの終点を見つけた - *req = 0; - sd->header_len = (req - RFIFOP(fd,0)) + 1; - httpd_parse_header(sd); - break; - } - } - } while(req++,--limit > 0); - } - break; - case HTTPD_REQUEST_WAIT_POST: - if(RFIFOREST(sd->fd) >= sd->header_len) { - unsigned char temp = RFIFOB(sd->fd,sd->header_len); - RFIFOB(sd->fd,sd->header_len) = 0; - httpd_parse_request_ok(sd); - RFIFOB(sd->fd,sd->header_len) = temp; - } - break; - case HTTPD_REQUEST_OK: - case HTTPD_SEND_HEADER: - // リクエストが終わったまま何も送信されていない状態なので、 - // 強制切断 - printf ("httpd: eof\n"); - sessiond[fd]->eof = 1; - break; - case HTTPD_WAITING_SEND: - // データの送信が終わるまで待機 - //if(sessiond[fd]->wdata_size == sessiond[fd]->wdata_pos) { - // i *hope* this is correct o.o; - if(sessiond[fd]->wdata_size == 0) { - // HTTP/1.0は手動切断 -// if(sd->http_ver == 0) { - if(sd->persist == 0) { - printf ("httpd: eof\n"); - sessiond[fd]->eof = 1; - } - // RFIFO からリクエストデータの消去と構造体の初期化 - _RFIFOSKIP(fd,sd->header_len); - sd->status = HTTPD_REQUEST_WAIT; - sd->tick = gettick(); - sd->header_len = 0; - sd->query = NULL; -// sd->http_ver = 0; // ver は保持 - sd->method = HTTPD_METHOD_UNKNOWN; - printf("httpd_parse: [% 3d] request sended RFIFOREST:%d\n", fd, RFIFOREST(fd)); - } - break; - } - return 0; -} - -void httpd_parse_header_sub( struct httpd_session_data* sd, const char *p1, int* plen ) -{ - int len = 0; - // HTTPのバージョンを調査 - if(!strncmp(p1 ,"HTTP/1.1",8)) { - sd->http_ver = 1; - sd->persist = 1; - } else { - sd->http_ver = 0; - sd->persist = 0; - } - - p1 = strchr(p1,'\n'); - while(p1) { - // Content-Length: の調査 - if(!httpd_strcasencmp(p1+1,"Content-Length: ",16)) { - len = atoi(p1 + 17); - } - // Connection: の調査 - if(!httpd_strcasencmp(p1+1,"Connection: ",12)) { - if( httpd_strcasencmp(p1+13,"close",5)==0 && sd->http_ver==1 ) - sd->persist = 0; - if( httpd_strcasencmp(p1+13,"Keep-Alive",10)==0 && sd->http_ver==0 ) - sd->persist = 1; - } - p1 = strchr(p1+1,'\n'); - } - if(plen) *plen = len; - return; -} - -void httpd_parse_header(struct httpd_session_data* sd) -{ - int i; - int status = 400; // Bad Request - unsigned char* req = RFIFOP(sd->fd,0); - do { - if(!strncmp(req,"GET /",5)) { - // GET リクエスト - req += 5; - for(i = 0;req[i]; i++) { - if(req[i] == ' ' || req[i] == '?') break; - if(!isalnum(req[i]) && req[i] != '.' && req[i] != '_' && req[i] != '-') break; - } - if(req[i] == ' ') { - req[i] = 0; - sd->url = req; - sd->query = NULL; - sd->status = HTTPD_REQUEST_OK; - } else if(req[i] == '?') { - req[i] = 0; - sd->query = &req[++i]; - for(;req[i];i++) { - if( - isalnum(req[i]) || req[i] == '+' || req[i] == '%' || req[i] == '&' || - req[i] == '=' - ) { - continue; - } else { - break; - } - } - if(req[i] != ' ') { - break; - } - req[i] = 0; - sd->url = req; - } else { - break; - } - // ヘッダ解析 - httpd_parse_header_sub( sd, &req[i+1], NULL ); - - printf("httpd: request %s %s\n", sd->url, sd->query); - sd->method = HTTPD_METHOD_GET; - httpd_parse_request_ok(sd); - } else if(!strncmp(req,"POST /",6)) { - int len; - req += 6; status = 404; - for(i = 0;req[i]; i++) { - if(req[i] == ' ') break; - if(!isalnum(req[i]) && req[i] != '.' && req[i] != '_' && req[i] != '-') break; - } - if(req[i] != ' ') { - break; - } - req[i] = 0; - sd->url = req; - - // ヘッダ解析 - httpd_parse_header_sub( sd, &req[i+1], &len ); - - if(len <= 0 || len >= 32*1024) { - // とりあえず32KB以上のリクエストは不正扱い - status = ( len==0 )? 411 : ( len>32*1024 )? 413 : 400; - break; - } - - sd->query = RFIFOP(sd->fd,sd->header_len); - sd->method = HTTPD_METHOD_POST; - sd->header_len += len; - if(RFIFOREST(sd->fd) >= sd->header_len) { - unsigned char temp = RFIFOB(sd->fd,sd->header_len); - RFIFOB(sd->fd,sd->header_len) = 0; - httpd_parse_request_ok(sd); - RFIFOB(sd->fd,sd->header_len) = temp; - } else { - // POSTのデータが送られてくるのを待つ - sd->status = HTTPD_REQUEST_WAIT_POST; - } - } else { - break; - } - } while(0); - if(sd->status == HTTPD_REQUEST_WAIT) { - sd->status = HTTPD_REQUEST_OK; - httpd_send_error(sd,status); - } -} - -void httpd_parse_request_ok (struct httpd_session_data *sd) -{ - void (*httpd_parse_func)(struct httpd_session_data*,const char*); - sd->status = HTTPD_REQUEST_OK; - - // ファイル名が求まったので、ページが無いか検索する - // printf("httpd_parse: [% 3d] request /%s\n", fd, req); - httpd_parse_func = strdb_get(httpd_files,(unsigned char*)sd->url); - if(httpd_parse_func == NULL) { - httpd_parse_func = httpd_default; - } - if(httpd_parse_func == NULL) { - httpd_send_error(sd,404); // Not Found - } else { - httpd_parse_func(sd,sd->url); - if(sd->status == HTTPD_REQUEST_OK) { - httpd_send_error(sd,404); // Not Found - } - } - if(sd->persist == 1 && sd->data_len) { - // 長さが変なデータ(こんなの送るなよ…) - printf("httpd_parse: send size mismatch when parsing /%s\n", sd->url); - sessiond[sd->fd]->eof = 1; - } - if(sd->status == HTTPD_REQUEST_OK) { - httpd_send_error(sd,404); - } -} - -char* httpd_get_value(struct httpd_session_data* sd,const char* val) -{ - int src_len = strlen(val); - const unsigned char* src_p = sd->query; - if(src_p == NULL) return aStrdup(""); - - do { - if(!memcmp(src_p,val,src_len) && src_p[src_len] == '=') { - break; - } - src_p = strchr(src_p + 1,'&'); - if(src_p) src_p++; - } while(src_p); - - if(src_p != NULL) { - // 目的の文字列を見つけた - const unsigned char* p2; - int dest_len; - char* dest_p; - src_p += src_len + 1; - p2 = strchr(src_p,'&'); - if(p2 == NULL) { - src_len = strlen(src_p); - } else { - src_len = (p2 - src_p); - } - dest_p = aMalloc(src_len + 1); - dest_len = 0; - while(src_len > 0) { - if(*src_p == '%' && src_len > 2) { - int c1 = 0,c2 = 0; - if(src_p[1] >= '0' && src_p[1] <= '9') c1 = src_p[1] - '0'; - if(src_p[1] >= 'A' && src_p[1] <= 'F') c1 = src_p[1] - 'A' + 10; - if(src_p[1] >= 'a' && src_p[1] <= 'f') c1 = src_p[1] - 'a' + 10; - if(src_p[2] >= '0' && src_p[2] <= '9') c2 = src_p[2] - '0'; - if(src_p[2] >= 'A' && src_p[2] <= 'F') c2 = src_p[2] - 'A' + 10; - if(src_p[2] >= 'a' && src_p[2] <= 'f') c2 = src_p[2] - 'a' + 10; - dest_p[dest_len++] = (c1 << 4) | c2; - src_p += 3; src_len -= 3; - } else if(*src_p == '+') { - dest_p[dest_len++] = ' '; - src_p++; src_len--; - } else { - dest_p[dest_len++] = *(src_p++); src_len--; - } - } - dest_p[dest_len] = 0; - return dest_p; - } - return aStrdup(""); -} - -// MIMEタイプ判定。主要なものだけ判定して、残りはapplication/octet-stream -static const char* httpd_mimetype(const char* url) -{ - char *ext = strrchr(url,'.'); - if(ext) { - if(!strcmp(ext,".html")) return "text/html"; - if(!strcmp(ext,".htm")) return "text/html"; - if(!strcmp(ext,".css")) return "text/css"; - if(!strcmp(ext,".js")) return "text/javascript"; - if(!strcmp(ext,".txt")) return "text/plain"; - if(!strcmp(ext,".gif")) return "image/gif"; - if(!strcmp(ext,".jpg")) return "image/jpeg"; - if(!strcmp(ext,".jpeg")) return "image/jpeg"; - if(!strcmp(ext,".png")) return "image/png"; - if(!strcmp(ext,".xbm")) return "image/xbm"; - if(!strcmp(ext,".zip")) return "application/zip"; - } - return "application/octet-stream"; -} - -void httpd_send_file(struct httpd_session_data* sd, const char* url) -{ - FILE *fp; - int file_size; - char file_buf[8192]; - if(sd->status != HTTPD_REQUEST_OK) return; - if(url[0] == '\0') url = "index.html"; - - // url の最大長は約1010バイトなので、バッファオーバーフローの心配は無し - sprintf(file_buf, "%s%s", document_root, url); - - fp = fopen(file_buf,"rb"); - if(fp == NULL) { - httpd_send_error(sd,404); - } else { - fseek(fp,0,SEEK_END); - file_size = ftell(fp); - fseek(fp,0,SEEK_SET); - httpd_send_head(sd,200,httpd_mimetype(url),file_size); - while(file_size > 0) { - int read_byte = file_size; - if(file_size > 8192) read_byte = 8192; - fread(file_buf,1,read_byte,fp); - httpd_send_data(sd,read_byte,file_buf); - file_size -= read_byte; - } - fclose(fp); - } -} - - -char* httpd_binary_encode(const char* val) -{ - char *buf = aMalloc(strlen(val) * 3 + 1); - char *p = buf; - while(*val) { - if(isalnum((unsigned char)*val)) { - *(p++) = *(val++); - } else { - unsigned char c1 = *(val++); - unsigned char c2 = (c1 >> 4); - unsigned char c3 = (c1 & 0x0F); - *(p++) = '%'; - *(p++) = c2 + (c2 >= 10 ? 'A'-10 : '0'); - *(p++) = c3 + (c3 >= 10 ? 'A'-10 : '0'); - } - } - *p = 0; - return buf; -} - -char* httpd_quote_meta(const char* p1) -{ - char *buf = aMalloc(strlen(p1) * 6 + 1); - char *p2 = buf; - while(*p1) { - switch(*p1) { - case '<': memcpy(p2,"<",4); p2 += 4; p1++; break; - case '>': memcpy(p2,">",4); p2 += 4; p1++; break; - case '&': memcpy(p2,"&",5); p2 += 5; p1++; break; - case '"': memcpy(p2,""",6); p2 += 6; p1++; break; - default: *(p2++) = *(p1++); - } - } - *p2 = 0; - return buf; -} - -///////// Graph / HTML snippets functions ///////////////////////////// - -struct file_entry { - char *filename; - struct file_entry *next; -}; -struct file_entry *fileentry_head = NULL; - -static void httpd_graph_load (const char *filename) -{ - struct file_entry *entry; - char type = *server_type + 'a'; - int len = strlen(filename); - - if (len <= 7 || filename[len - 7] != type) - return; - - entry = fileentry_head; - while (entry) { - if (strcmpi(entry->filename, filename) == 0) - return; - entry = entry->next; - } - - entry = (struct file_entry *) aMalloc (sizeof(struct file_entry)); - entry->filename = aStrdup(filename); - entry->next = fileentry_head; - fileentry_head = entry; -} - -// scan for available html snippets -static int httpd_graph_find (int tid, unsigned int tick, int id, int data) -{ - findfile("httpd", ".graph", httpd_graph_load); - return 0; -} - -static void httpd_graph_parse (struct httpd_session_data *sd,const char* url) -{ - // output html - struct file_entry *entry = fileentry_head; - char buf[8192]; - char *p = buf; - FILE *fp; - - p += sprintf(p,"Athena Sensors\n\n\n"); - p += sprintf(p,"

Athena Sensors

\n\n"); - - while (entry) { - // insert snippets into html - char line[1024]; - fp = fopen(entry->filename, "r"); - if (fp == NULL) { - entry = entry->next; - continue; - } - while(fgets(line, sizeof(line) -1, fp)) - p += sprintf(p, line); - fclose(fp); - entry = entry->next; - } - p += sprintf(p,"\n"); - httpd_send(sd,200,"text/html",p - buf,buf); -} - -//////////////// Initialise / Finalise ///////////////////////////// - -void do_final (void) -{ - int fd; - struct file_entry *entry = fileentry_head, *entry2; - - // clear up graph entries - while (entry) { - entry2 = entry->next; - aFree(entry->filename); - aFree(entry); - entry = entry2; - } - // clear up existing http connections - for (fd = 0; fd < *max_fd; fd++) - if (sessiond[fd] && sessiond[fd]->type == SESSION_HTTP) - delete_sessiond(fd); - - httpd_files->destroy(httpd_files,NULL); - // clear up the database - db_final(); - // clear up allocated memory - // note: the memory manager, if enabled, would be - // separate from the parent program, which is also - // why we need to delete our http sessions - // separately above - malloc_final(); -} - -void do_init (void) -{ - struct func_parse_table *parse_table; - int enable_httpd = 1; - - do { - char line[1024], w1[1024], w2[1024]; - FILE *fp = fopen("plugins/httpd.conf","r"); - if (fp == NULL) - break; - - while(fgets(line, sizeof(line) -1, fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) { - if(strcmpi(w1,"enable_httpd")==0){ - enable_httpd = atoi(w2); - } else if(strcmpi(w1,"document_root")==0){ - strcpy(document_root, w2); - } else if(strcmpi(w1,"request_timeout_first")==0){ - request_timeout[0] = atoi(w2); - } else if(strcmpi(w1,"request_timeout_persist")==0){ - request_timeout[1] = atoi(w2); - } else if(strcmpi(w1,"max_persist_request")==0){ - max_persist_requests = atoi(w2); - } - } - } - fclose(fp); - } while (0); - - if (!enable_httpd) - return; - - malloc_init(); - db_init(); - IMPORT_SYMBOL(server_type, 0); - IMPORT_SYMBOL(gettick, 5); - IMPORT_SYMBOL(add_timer_interval, 8); - IMPORT_SYMBOL(max_fd, 13); - IMPORT_SYMBOL(sessiond, 14); - IMPORT_SYMBOL(delete_sessiond, 15); - IMPORT_SYMBOL(_WFIFOSET, 16); - IMPORT_SYMBOL(_RFIFOSKIP, 17); - IMPORT_SYMBOL(parse_table, 18); - - // register http parsing function - parse_table[SESSION_HTTP].check = httpd_check; - parse_table[SESSION_HTTP].func = httpd_parse; - - httpd_files = db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_RELEASE_KEY,50); - httpd_default = httpd_send_file; - - httpd_pages ("/graph", httpd_graph_parse); - add_timer_interval(gettick()+10000,httpd_graph_find,0,0,10000); - - return; -} + +#ifdef __WIN32 +#include +#else +#include +#endif +#include +#include +#include +#include + +#include "../common/db.h" +//mmo required for definition of stricmp +#include "../common/mmo.h" +#include "../common/utils.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/plugin.h" +//#include "httpd.h" + +/** Created by End_of_Exam, ported to plugin and modified by Celest **/ + +PLUGIN_INFO = { + "HttpDaemon", + PLUGIN_CORE, + "0.1", + PLUGIN_VERSION, + "HTTP Daemon" +}; + +PLUGIN_EVENTS_TABLE = { + { "do_init", "Plugin_Init" }, + { "do_final", "Plugin_Final" }, + { NULL, NULL } +}; + +enum HTTPD_STATUS { + HTTPD_REQUEST_WAIT = 0, // リクエスト待ち + HTTPD_REQUEST_WAIT_POST, // リクエスト待ち(post) + HTTPD_REQUEST_OK, // リクエスト解釈完了 + HTTPD_SEND_HEADER, // ヘッダ送信完了 + HTTPD_WAITING_SEND // データが送信し終わるまで待っている状態 +}; +enum { + HTTPD_METHOD_UNKNOWN = 0, + HTTPD_METHOD_GET, + HTTPD_METHOD_POST +}; + +struct httpd_session_data { + int fd; + int status; + int http_ver; + int header_len; + int data_len; + int method; + int persist; + int request_count; + unsigned int tick; + const unsigned char* url; + const unsigned char* query; +}; + +// undefine socket operations included from socket.h, +// since we are going to use 'sessiond' instead +#undef RFIFOP +#undef RFIFOREST +#undef WFIFOP + +#define RFIFOP(fd,pos) (sessiond[fd]->rdata+sessiond[fd]->rdata_pos+(pos)) +#define RFIFOREST(fd) (sessiond[fd]->rdata_size-sessiond[fd]->rdata_pos) +#define WFIFOP(fd,pos) (sessiond[fd]->wdata+sessiond[fd]->wdata_size+(pos)) + +struct socket_data **sessiond; +char *server_type; +unsigned int (*gettick)(); +int (*add_timer_interval)(unsigned int,int (*)(int,unsigned int,int,int),int,int,int); +int *max_fd; +int (*delete_sessiond)(int); +int (*_WFIFOSET)(int,int); +int (*_RFIFOSKIP)(int,int); + +static int max_persist_requests = 32; // 持続通信での最大リクエスト数 +static int request_timeout[] = { 2500, 60*1000 }; // タイムアウト(最初、持続) +static char document_root[256] = "./httpd/"; // ドキュメントルート + +// httpd に入っているページと、呼び出すコールバック関数の一覧 +struct dbt *httpd_files; + +void httpd_send(struct httpd_session_data*, int, const char *, int, const void *); + +int httpd_check (struct socket_data *sd) +{ + // httpd に回すどうかの判定がまだ行われてない + // 先頭2バイトが GE ならhttpd に回してみる + if (sd->rdata_size >= 2 && + sd->rdata[0] == 'G' && sd->rdata[1] == 'E') + return 1; + + return 0; +} + +int httpd_strcasencmp(const char *s1, const char *s2,int len) +{ + while(len-- && (*s1 || *s2) ) { + if((*s1 | 0x20) != (*s2 | 0x20)) { + return ((*s1 | 0x20) > (*s2 | 0x20) ? 1 : -1); + } + s1++; s2++; + } + return 0; +} + +// httpd にページを追加する +// for などでページ名を合成できるように、key はstrdup()したものを使う + +void httpd_pages (const char* url, void (*httpd_func)(struct httpd_session_data*, const char*)) +{ + if (strdb_get(httpd_files,(unsigned char*)(url+1)) == NULL) { + strdb_put(httpd_files, (unsigned char*)aStrdup(url+1), httpd_func); + } else { + strdb_put(httpd_files, (unsigned char*)(url+1), httpd_func); + } +} + +static void (*httpd_default)(struct httpd_session_data* sd,const char* url); + +const char *httpd_get_error( struct httpd_session_data* sd, int* status ) +{ + const char* msg; + // httpd のステータスを決める + switch(*status) { + case 200: msg = "OK"; break; + case 400: msg = "Bad Request"; break; + case 401: msg = "Unauthorized"; break; // 未使用 + case 403: msg = "Forbidden"; break; // 未使用 + case 404: msg = "Not Found"; break; + case 408: msg = "Request Timedout"; break; + case 411: msg = "Length Required"; break; + case 413: msg = "Request Entity Too Large"; break; + default: + *status = 500; msg = "Internal Server Error"; break; + } + return msg; +} + +void httpd_send_error(struct httpd_session_data* sd,int status) +{ + const char* msg = httpd_get_error( sd, &status ); + httpd_send(sd, status, "text/plain",strlen(msg),msg); +} + +void httpd_send_head (struct httpd_session_data* sd, int status, const char *content_type, int content_len) +{ + char head[256]; + int len; + const char* msg; + + if (sd->status != HTTPD_REQUEST_OK) + return; + msg = httpd_get_error( sd, &status ); + + if(content_len == -1 || ++sd->request_count >= max_persist_requests ) { + // 長さが分からない or リクエスト限界を超えたので切断する + len = sprintf( + head, + "HTTP/1.%d %d %s\r\nContent-Type: %s\r\nConnection: close\r\n\r\n", + sd->http_ver,status,msg,content_type + ); + sd->persist = 0; + len = sprintf( + head, + "HTTP/1.%d %d %s\r\nContent-Type: %s\r\n\r\n", + sd->http_ver,status,msg,content_type + ); + sd->http_ver = 0; // 長さが分からないので、HTTP/1.0 扱い(自動切断)にする + } else { + len = sprintf( + head, + "HTTP/1.%d %d %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n", + sd->http_ver,status,msg,content_type,content_len + ); + } + memcpy(WFIFOP(sd->fd,0),head,len); + _WFIFOSET(sd->fd,len); + sd->status = HTTPD_SEND_HEADER; + sd->data_len = content_len; +} + +void httpd_send_data (struct httpd_session_data* sd, int content_len, const void *data) +{ + const char* msg = (const char*)data; + if (sd->status == HTTPD_REQUEST_OK) { + // ヘッダの送信忘れているので、適当に補う + httpd_send_head(sd,200,"application/octet-stream",-1); + } else if(sd->status != HTTPD_SEND_HEADER && sd->status != HTTPD_WAITING_SEND) { + return; + } + sd->data_len -= content_len; + + // 巨大なサイズのファイルも送信出来るように分割して送る + while (content_len > 0) { + int send_byte = content_len; + if(send_byte > 12*1024) send_byte = 12*1024; + memcpy(WFIFOP(sd->fd,0),msg,send_byte); + _WFIFOSET(sd->fd,send_byte); + msg += send_byte; content_len -= send_byte; + } + sd->status = HTTPD_WAITING_SEND; +} + +void httpd_send (struct httpd_session_data* sd, int status, const char *content_type, int content_len, const void *data) +{ + httpd_send_head(sd,status,content_type,content_len); + httpd_send_data(sd,content_len,data); +} + +void httpd_parse_header(struct httpd_session_data* sd); +void httpd_parse_request_ok(struct httpd_session_data *sd); + +int httpd_parse (int fd) +{ + struct httpd_session_data *sd = (struct httpd_session_data *)sessiond[fd]->session_data2; + if (sessiond[fd]->eof) { + delete_sessiond(fd); + return 0; + } + if (sd == NULL) { + sd = (struct httpd_session_data*) aMalloc (sizeof(struct httpd_session_data)); + sd->fd = fd; + sessiond[fd]->session_data2 = sd; + sd->tick = gettick(); + sd->persist = 0; + sd->request_count = 0; + } + printf ("status %d\n", sd->status); + switch(sd->status) { + case HTTPD_REQUEST_WAIT: + // リクエスト待ち + if(RFIFOREST(fd) > 1024) { + // リクエストが長すぎるので、エラー扱いする + sd->status = HTTPD_REQUEST_OK; + httpd_send_error(sd,400); // Bad Request + } else if( (int)( gettick() - sd->tick ) > request_timeout[sd->persist] ) { + // リクエストに時間がかかりすぎているので、エラー扱いする + sd->status = HTTPD_REQUEST_OK; + httpd_send_error(sd,408); // Request Timeout + } else if(sd->header_len == RFIFOREST(fd)) { + // 状態が以前と同じなので、リクエストを再解析する必要は無い + } else { + int limit = RFIFOREST(fd); + unsigned char *req = RFIFOP(fd,0); + sd->header_len = RFIFOREST(fd); + do { + if(*req == '\n' && limit > 0) { + limit--; req++; + if(*req == '\r' && limit > 0) { limit--; req++; } + if(*req == '\n') { + // HTTPヘッダの終点を見つけた + *req = 0; + sd->header_len = (req - RFIFOP(fd,0)) + 1; + httpd_parse_header(sd); + break; + } + } + } while(req++,--limit > 0); + } + break; + case HTTPD_REQUEST_WAIT_POST: + if(RFIFOREST(sd->fd) >= sd->header_len) { + unsigned char temp = RFIFOB(sd->fd,sd->header_len); + RFIFOB(sd->fd,sd->header_len) = 0; + httpd_parse_request_ok(sd); + RFIFOB(sd->fd,sd->header_len) = temp; + } + break; + case HTTPD_REQUEST_OK: + case HTTPD_SEND_HEADER: + // リクエストが終わったまま何も送信されていない状態なので、 + // 強制切断 + printf ("httpd: eof\n"); + sessiond[fd]->eof = 1; + break; + case HTTPD_WAITING_SEND: + // データの送信が終わるまで待機 + //if(sessiond[fd]->wdata_size == sessiond[fd]->wdata_pos) { + // i *hope* this is correct o.o; + if(sessiond[fd]->wdata_size == 0) { + // HTTP/1.0は手動切断 +// if(sd->http_ver == 0) { + if(sd->persist == 0) { + printf ("httpd: eof\n"); + sessiond[fd]->eof = 1; + } + // RFIFO からリクエストデータの消去と構造体の初期化 + _RFIFOSKIP(fd,sd->header_len); + sd->status = HTTPD_REQUEST_WAIT; + sd->tick = gettick(); + sd->header_len = 0; + sd->query = NULL; +// sd->http_ver = 0; // ver は保持 + sd->method = HTTPD_METHOD_UNKNOWN; + printf("httpd_parse: [% 3d] request sended RFIFOREST:%d\n", fd, RFIFOREST(fd)); + } + break; + } + return 0; +} + +void httpd_parse_header_sub( struct httpd_session_data* sd, const char *p1, int* plen ) +{ + int len = 0; + // HTTPのバージョンを調査 + if(!strncmp(p1 ,"HTTP/1.1",8)) { + sd->http_ver = 1; + sd->persist = 1; + } else { + sd->http_ver = 0; + sd->persist = 0; + } + + p1 = strchr(p1,'\n'); + while(p1) { + // Content-Length: の調査 + if(!httpd_strcasencmp(p1+1,"Content-Length: ",16)) { + len = atoi(p1 + 17); + } + // Connection: の調査 + if(!httpd_strcasencmp(p1+1,"Connection: ",12)) { + if( httpd_strcasencmp(p1+13,"close",5)==0 && sd->http_ver==1 ) + sd->persist = 0; + if( httpd_strcasencmp(p1+13,"Keep-Alive",10)==0 && sd->http_ver==0 ) + sd->persist = 1; + } + p1 = strchr(p1+1,'\n'); + } + if(plen) *plen = len; + return; +} + +void httpd_parse_header(struct httpd_session_data* sd) +{ + int i; + int status = 400; // Bad Request + unsigned char* req = RFIFOP(sd->fd,0); + do { + if(!strncmp(req,"GET /",5)) { + // GET リクエスト + req += 5; + for(i = 0;req[i]; i++) { + if(req[i] == ' ' || req[i] == '?') break; + if(!isalnum(req[i]) && req[i] != '.' && req[i] != '_' && req[i] != '-') break; + } + if(req[i] == ' ') { + req[i] = 0; + sd->url = req; + sd->query = NULL; + sd->status = HTTPD_REQUEST_OK; + } else if(req[i] == '?') { + req[i] = 0; + sd->query = &req[++i]; + for(;req[i];i++) { + if( + isalnum(req[i]) || req[i] == '+' || req[i] == '%' || req[i] == '&' || + req[i] == '=' + ) { + continue; + } else { + break; + } + } + if(req[i] != ' ') { + break; + } + req[i] = 0; + sd->url = req; + } else { + break; + } + // ヘッダ解析 + httpd_parse_header_sub( sd, &req[i+1], NULL ); + + printf("httpd: request %s %s\n", sd->url, sd->query); + sd->method = HTTPD_METHOD_GET; + httpd_parse_request_ok(sd); + } else if(!strncmp(req,"POST /",6)) { + int len; + req += 6; status = 404; + for(i = 0;req[i]; i++) { + if(req[i] == ' ') break; + if(!isalnum(req[i]) && req[i] != '.' && req[i] != '_' && req[i] != '-') break; + } + if(req[i] != ' ') { + break; + } + req[i] = 0; + sd->url = req; + + // ヘッダ解析 + httpd_parse_header_sub( sd, &req[i+1], &len ); + + if(len <= 0 || len >= 32*1024) { + // とりあえず32KB以上のリクエストは不正扱い + status = ( len==0 )? 411 : ( len>32*1024 )? 413 : 400; + break; + } + + sd->query = RFIFOP(sd->fd,sd->header_len); + sd->method = HTTPD_METHOD_POST; + sd->header_len += len; + if(RFIFOREST(sd->fd) >= sd->header_len) { + unsigned char temp = RFIFOB(sd->fd,sd->header_len); + RFIFOB(sd->fd,sd->header_len) = 0; + httpd_parse_request_ok(sd); + RFIFOB(sd->fd,sd->header_len) = temp; + } else { + // POSTのデータが送られてくるのを待つ + sd->status = HTTPD_REQUEST_WAIT_POST; + } + } else { + break; + } + } while(0); + if(sd->status == HTTPD_REQUEST_WAIT) { + sd->status = HTTPD_REQUEST_OK; + httpd_send_error(sd,status); + } +} + +void httpd_parse_request_ok (struct httpd_session_data *sd) +{ + void (*httpd_parse_func)(struct httpd_session_data*,const char*); + sd->status = HTTPD_REQUEST_OK; + + // ファイル名が求まったので、ページが無いか検索する + // printf("httpd_parse: [% 3d] request /%s\n", fd, req); + httpd_parse_func = strdb_get(httpd_files,(unsigned char*)sd->url); + if(httpd_parse_func == NULL) { + httpd_parse_func = httpd_default; + } + if(httpd_parse_func == NULL) { + httpd_send_error(sd,404); // Not Found + } else { + httpd_parse_func(sd,sd->url); + if(sd->status == HTTPD_REQUEST_OK) { + httpd_send_error(sd,404); // Not Found + } + } + if(sd->persist == 1 && sd->data_len) { + // 長さが変なデータ(こんなの送るなよ…) + printf("httpd_parse: send size mismatch when parsing /%s\n", sd->url); + sessiond[sd->fd]->eof = 1; + } + if(sd->status == HTTPD_REQUEST_OK) { + httpd_send_error(sd,404); + } +} + +char* httpd_get_value(struct httpd_session_data* sd,const char* val) +{ + int src_len = strlen(val); + const unsigned char* src_p = sd->query; + if(src_p == NULL) return aStrdup(""); + + do { + if(!memcmp(src_p,val,src_len) && src_p[src_len] == '=') { + break; + } + src_p = strchr(src_p + 1,'&'); + if(src_p) src_p++; + } while(src_p); + + if(src_p != NULL) { + // 目的の文字列を見つけた + const unsigned char* p2; + int dest_len; + char* dest_p; + src_p += src_len + 1; + p2 = strchr(src_p,'&'); + if(p2 == NULL) { + src_len = strlen(src_p); + } else { + src_len = (p2 - src_p); + } + dest_p = aMalloc(src_len + 1); + dest_len = 0; + while(src_len > 0) { + if(*src_p == '%' && src_len > 2) { + int c1 = 0,c2 = 0; + if(src_p[1] >= '0' && src_p[1] <= '9') c1 = src_p[1] - '0'; + if(src_p[1] >= 'A' && src_p[1] <= 'F') c1 = src_p[1] - 'A' + 10; + if(src_p[1] >= 'a' && src_p[1] <= 'f') c1 = src_p[1] - 'a' + 10; + if(src_p[2] >= '0' && src_p[2] <= '9') c2 = src_p[2] - '0'; + if(src_p[2] >= 'A' && src_p[2] <= 'F') c2 = src_p[2] - 'A' + 10; + if(src_p[2] >= 'a' && src_p[2] <= 'f') c2 = src_p[2] - 'a' + 10; + dest_p[dest_len++] = (c1 << 4) | c2; + src_p += 3; src_len -= 3; + } else if(*src_p == '+') { + dest_p[dest_len++] = ' '; + src_p++; src_len--; + } else { + dest_p[dest_len++] = *(src_p++); src_len--; + } + } + dest_p[dest_len] = 0; + return dest_p; + } + return aStrdup(""); +} + +// MIMEタイプ判定。主要なものだけ判定して、残りはapplication/octet-stream +static const char* httpd_mimetype(const char* url) +{ + char *ext = strrchr(url,'.'); + if(ext) { + if(!strcmp(ext,".html")) return "text/html"; + if(!strcmp(ext,".htm")) return "text/html"; + if(!strcmp(ext,".css")) return "text/css"; + if(!strcmp(ext,".js")) return "text/javascript"; + if(!strcmp(ext,".txt")) return "text/plain"; + if(!strcmp(ext,".gif")) return "image/gif"; + if(!strcmp(ext,".jpg")) return "image/jpeg"; + if(!strcmp(ext,".jpeg")) return "image/jpeg"; + if(!strcmp(ext,".png")) return "image/png"; + if(!strcmp(ext,".xbm")) return "image/xbm"; + if(!strcmp(ext,".zip")) return "application/zip"; + } + return "application/octet-stream"; +} + +void httpd_send_file(struct httpd_session_data* sd, const char* url) +{ + FILE *fp; + int file_size; + char file_buf[8192]; + if(sd->status != HTTPD_REQUEST_OK) return; + if(url[0] == '\0') url = "index.html"; + + // url の最大長は約1010バイトなので、バッファオーバーフローの心配は無し + sprintf(file_buf, "%s%s", document_root, url); + + fp = fopen(file_buf,"rb"); + if(fp == NULL) { + httpd_send_error(sd,404); + } else { + fseek(fp,0,SEEK_END); + file_size = ftell(fp); + fseek(fp,0,SEEK_SET); + httpd_send_head(sd,200,httpd_mimetype(url),file_size); + while(file_size > 0) { + int read_byte = file_size; + if(file_size > 8192) read_byte = 8192; + fread(file_buf,1,read_byte,fp); + httpd_send_data(sd,read_byte,file_buf); + file_size -= read_byte; + } + fclose(fp); + } +} + + +char* httpd_binary_encode(const char* val) +{ + char *buf = aMalloc(strlen(val) * 3 + 1); + char *p = buf; + while(*val) { + if(isalnum((unsigned char)*val)) { + *(p++) = *(val++); + } else { + unsigned char c1 = *(val++); + unsigned char c2 = (c1 >> 4); + unsigned char c3 = (c1 & 0x0F); + *(p++) = '%'; + *(p++) = c2 + (c2 >= 10 ? 'A'-10 : '0'); + *(p++) = c3 + (c3 >= 10 ? 'A'-10 : '0'); + } + } + *p = 0; + return buf; +} + +char* httpd_quote_meta(const char* p1) +{ + char *buf = aMalloc(strlen(p1) * 6 + 1); + char *p2 = buf; + while(*p1) { + switch(*p1) { + case '<': memcpy(p2,"<",4); p2 += 4; p1++; break; + case '>': memcpy(p2,">",4); p2 += 4; p1++; break; + case '&': memcpy(p2,"&",5); p2 += 5; p1++; break; + case '"': memcpy(p2,""",6); p2 += 6; p1++; break; + default: *(p2++) = *(p1++); + } + } + *p2 = 0; + return buf; +} + +///////// Graph / HTML snippets functions ///////////////////////////// + +struct file_entry { + char *filename; + struct file_entry *next; +}; +struct file_entry *fileentry_head = NULL; + +static void httpd_graph_load (const char *filename) +{ + struct file_entry *entry; + char type = *server_type + 'a'; + int len = strlen(filename); + + if (len <= 7 || filename[len - 7] != type) + return; + + entry = fileentry_head; + while (entry) { + if (strcmpi(entry->filename, filename) == 0) + return; + entry = entry->next; + } + + entry = (struct file_entry *) aMalloc (sizeof(struct file_entry)); + entry->filename = aStrdup(filename); + entry->next = fileentry_head; + fileentry_head = entry; +} + +// scan for available html snippets +static int httpd_graph_find (int tid, unsigned int tick, int id, int data) +{ + findfile("httpd", ".graph", httpd_graph_load); + return 0; +} + +static void httpd_graph_parse (struct httpd_session_data *sd,const char* url) +{ + // output html + struct file_entry *entry = fileentry_head; + char buf[8192]; + char *p = buf; + FILE *fp; + + p += sprintf(p,"Athena Sensors\n\n\n"); + p += sprintf(p,"

Athena Sensors

\n\n"); + + while (entry) { + // insert snippets into html + char line[1024]; + fp = fopen(entry->filename, "r"); + if (fp == NULL) { + entry = entry->next; + continue; + } + while(fgets(line, sizeof(line) -1, fp)) + p += sprintf(p, line); + fclose(fp); + entry = entry->next; + } + p += sprintf(p,"\n"); + httpd_send(sd,200,"text/html",p - buf,buf); +} + +//////////////// Initialise / Finalise ///////////////////////////// + +void do_final (void) +{ + int fd; + struct file_entry *entry = fileentry_head, *entry2; + + // clear up graph entries + while (entry) { + entry2 = entry->next; + aFree(entry->filename); + aFree(entry); + entry = entry2; + } + // clear up existing http connections + for (fd = 0; fd < *max_fd; fd++) + if (sessiond[fd] && sessiond[fd]->type == SESSION_HTTP) + delete_sessiond(fd); + + httpd_files->destroy(httpd_files,NULL); + // clear up the database + db_final(); + // clear up allocated memory + // note: the memory manager, if enabled, would be + // separate from the parent program, which is also + // why we need to delete our http sessions + // separately above + malloc_final(); +} + +void do_init (void) +{ + struct func_parse_table *parse_table; + int enable_httpd = 1; + + do { + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen("plugins/httpd.conf","r"); + if (fp == NULL) + break; + + while(fgets(line, sizeof(line) -1, fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) { + if(strcmpi(w1,"enable_httpd")==0){ + enable_httpd = atoi(w2); + } else if(strcmpi(w1,"document_root")==0){ + strcpy(document_root, w2); + } else if(strcmpi(w1,"request_timeout_first")==0){ + request_timeout[0] = atoi(w2); + } else if(strcmpi(w1,"request_timeout_persist")==0){ + request_timeout[1] = atoi(w2); + } else if(strcmpi(w1,"max_persist_request")==0){ + max_persist_requests = atoi(w2); + } + } + } + fclose(fp); + } while (0); + + if (!enable_httpd) + return; + + malloc_init(); + db_init(); + IMPORT_SYMBOL(server_type, 0); + IMPORT_SYMBOL(gettick, 5); + IMPORT_SYMBOL(add_timer_interval, 8); + IMPORT_SYMBOL(max_fd, 13); + IMPORT_SYMBOL(sessiond, 14); + IMPORT_SYMBOL(delete_sessiond, 15); + IMPORT_SYMBOL(_WFIFOSET, 16); + IMPORT_SYMBOL(_RFIFOSKIP, 17); + IMPORT_SYMBOL(parse_table, 18); + + // register http parsing function + parse_table[SESSION_HTTP].check = httpd_check; + parse_table[SESSION_HTTP].func = httpd_parse; + + httpd_files = db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_RELEASE_KEY,50); + httpd_default = httpd_send_file; + + httpd_pages ("/graph", httpd_graph_parse); + add_timer_interval(gettick()+10000,httpd_graph_find,0,0,10000); + + return; +} diff --git a/src/plugins/httpd.h b/src/plugins/httpd.h index 9eef7d915..aa6989421 100644 --- a/src/plugins/httpd.h +++ b/src/plugins/httpd.h @@ -1,107 +1,107 @@ -#ifndef _HTTPD_H_ -#define _HTTPD_H_ - -struct httpd_session_data; - -// NOTE by Celest: This file is not used by httpd.c, but included only as an API reference. - -// 注意 -// 1.athena内蔵のhttpd で大きなファイルを送信することはお勧めしません。 -// 200KB を超えるようなファイルは、別のソフトを利用することを勧めます。 -// 2.ファイル名に使える文字は、[A-Za-z0-9-_\.] です。他の文字を使うと、 -// BAD REQUEST で弾かれます。 - - - -void httpd_pages(const char* url,void(*httpd_func)(struct httpd_session_data* sd,const char* url)); - -// 指定されたURL に対するコールバック関数を設定する。この関数は、以下のように -// 実装する必要がある。 -// -// 1. URL は、先頭のスラッシュが省かれたファイル名です。例えば、"GET / HTTP/1.0" -// という風にリクエストされた時、URL には""(空文字)が入り、"GET /hoge HTTP/1.0" -// の時には、"hoge"が入ります。 -// 2. リクエストされたページが見つかったら、httpd_send() または、httpd_send_head() -// とhttpd_send_data() の組を呼び出し、データを出力する。 -// 3. httpd_send_file を指定すると、httpd/ 以下にあるファイルを出力する。ファイルに -// 空文字が指定された時は、index.htmlが指定されたものとみなされる。 - - - -char* httpd_get_value(struct httpd_session_data* sd,const char* val); - -// リクエストされたアドレスに渡されたフォームデータのうち、該当する文字列を返す。 -// 例えば、"GET /status/graph?image=users HTTP/1.0"というリクエストの場合、 -// httpd_get_value(sd,"image"); は、 "users"を返す。この関数の戻り値は、呼び出し元が -// 解放しなければならない。また、該当する文字列が無い時は、空の文字列を返す。 - -unsigned int httpd_get_ip(struct httpd_session_data *sd); - -// クライアントのIPを返す。 - - -void httpd_default_page(void(*httpd_func)(struct httpd_session_data* sd,const char* url)); - -// 指定されたURL が登録されていない時に呼び出す関数を設定する。この関数を呼び出さないか、 -// 関数の引数にNULLを指定すると、404 Not Found を返す。 - - - - -void httpd_send(struct httpd_session_data* sd,int status,const char *content_type,int content_len,const void *data); - -// HTTPヘッダ、データを組にして送信する。この関数を呼び出した後に、httpd_send_data を -// 呼び出してはならない。 -// -// sd : httpd_set_parse_func() に渡されたものをそのまま渡すこと。 -// status : HTTPヘッダに加えるstatus。通常は200。 -// content_type : 送信するデータのタイプ。text/html , image/jpeg など。 -// content_len : 送信するデータの長さ。 -// data : 送信するデータへのポインタ - - - -void httpd_send_head(struct httpd_session_data* sd,int status,const char *content_type,int content_len); - -// HTTPヘッダを送信する。 -// -// sd : 同上 -// status : 同上 -// content_type : 同上 -// content_len : content_lenを-1に指定することで、この関数が呼ばれた時点で -// 長さが分からないデータを送信することができる。この場合は -// 強制的にHTTP/1.0 接続となり、オーバーヘッドが大きくなるので、 -// あまりお勧めはしない。 - - - - -void httpd_send_data(struct httpd_session_data* sd,int content_len,const void *data); - -// データを送信する。この関数を、httpd_send_head() を呼び出す前に呼び出された場合、 -// content_type = application/octet-stream, content_len = -1 としてヘッダが送信される。 -// sd : 同上 -// content_len : 送信するデータのdata長さを指定する。 -// data : 送信するデータ - - - -void httpd_send_file(struct httpd_session_data* sd,const char* url); - -// ファイルを送信する。この関数は、httpd_send_head() を呼び出す前に呼び出さなければ -// ならない。ファイルに空文字が指定されたときは、index.htmlが指定されたと見なされる。 - - - -void httpd_send_error(struct httpd_session_data* sd,int status); - -// HTTPエラーメッセージを送信する。status はHTTPのエラーコードと同じ。 -// 400 Bad Request, 404 Not Found, 500 Internal Server Error など。 - -int httpd_parse(int fd); - -// 初期化処理 -void do_init_httpd(void); -void do_final_httpd(void); - -#endif +#ifndef _HTTPD_H_ +#define _HTTPD_H_ + +struct httpd_session_data; + +// NOTE by Celest: This file is not used by httpd.c, but included only as an API reference. + +// 注意 +// 1.athena内蔵のhttpd で大きなファイルを送信することはお勧めしません。 +// 200KB を超えるようなファイルは、別のソフトを利用することを勧めます。 +// 2.ファイル名に使える文字は、[A-Za-z0-9-_\.] です。他の文字を使うと、 +// BAD REQUEST で弾かれます。 + + + +void httpd_pages(const char* url,void(*httpd_func)(struct httpd_session_data* sd,const char* url)); + +// 指定されたURL に対するコールバック関数を設定する。この関数は、以下のように +// 実装する必要がある。 +// +// 1. URL は、先頭のスラッシュが省かれたファイル名です。例えば、"GET / HTTP/1.0" +// という風にリクエストされた時、URL には""(空文字)が入り、"GET /hoge HTTP/1.0" +// の時には、"hoge"が入ります。 +// 2. リクエストされたページが見つかったら、httpd_send() または、httpd_send_head() +// とhttpd_send_data() の組を呼び出し、データを出力する。 +// 3. httpd_send_file を指定すると、httpd/ 以下にあるファイルを出力する。ファイルに +// 空文字が指定された時は、index.htmlが指定されたものとみなされる。 + + + +char* httpd_get_value(struct httpd_session_data* sd,const char* val); + +// リクエストされたアドレスに渡されたフォームデータのうち、該当する文字列を返す。 +// 例えば、"GET /status/graph?image=users HTTP/1.0"というリクエストの場合、 +// httpd_get_value(sd,"image"); は、 "users"を返す。この関数の戻り値は、呼び出し元が +// 解放しなければならない。また、該当する文字列が無い時は、空の文字列を返す。 + +unsigned int httpd_get_ip(struct httpd_session_data *sd); + +// クライアントのIPを返す。 + + +void httpd_default_page(void(*httpd_func)(struct httpd_session_data* sd,const char* url)); + +// 指定されたURL が登録されていない時に呼び出す関数を設定する。この関数を呼び出さないか、 +// 関数の引数にNULLを指定すると、404 Not Found を返す。 + + + + +void httpd_send(struct httpd_session_data* sd,int status,const char *content_type,int content_len,const void *data); + +// HTTPヘッダ、データを組にして送信する。この関数を呼び出した後に、httpd_send_data を +// 呼び出してはならない。 +// +// sd : httpd_set_parse_func() に渡されたものをそのまま渡すこと。 +// status : HTTPヘッダに加えるstatus。通常は200。 +// content_type : 送信するデータのタイプ。text/html , image/jpeg など。 +// content_len : 送信するデータの長さ。 +// data : 送信するデータへのポインタ + + + +void httpd_send_head(struct httpd_session_data* sd,int status,const char *content_type,int content_len); + +// HTTPヘッダを送信する。 +// +// sd : 同上 +// status : 同上 +// content_type : 同上 +// content_len : content_lenを-1に指定することで、この関数が呼ばれた時点で +// 長さが分からないデータを送信することができる。この場合は +// 強制的にHTTP/1.0 接続となり、オーバーヘッドが大きくなるので、 +// あまりお勧めはしない。 + + + + +void httpd_send_data(struct httpd_session_data* sd,int content_len,const void *data); + +// データを送信する。この関数を、httpd_send_head() を呼び出す前に呼び出された場合、 +// content_type = application/octet-stream, content_len = -1 としてヘッダが送信される。 +// sd : 同上 +// content_len : 送信するデータのdata長さを指定する。 +// data : 送信するデータ + + + +void httpd_send_file(struct httpd_session_data* sd,const char* url); + +// ファイルを送信する。この関数は、httpd_send_head() を呼び出す前に呼び出さなければ +// ならない。ファイルに空文字が指定されたときは、index.htmlが指定されたと見なされる。 + + + +void httpd_send_error(struct httpd_session_data* sd,int status); + +// HTTPエラーメッセージを送信する。status はHTTPのエラーコードと同じ。 +// 400 Bad Request, 404 Not Found, 500 Internal Server Error など。 + +int httpd_parse(int fd); + +// 初期化処理 +void do_init_httpd(void); +void do_final_httpd(void); + +#endif diff --git a/src/plugins/httpd.txt b/src/plugins/httpd.txt index 2de84e3d8..5a575f680 100644 --- a/src/plugins/httpd.txt +++ b/src/plugins/httpd.txt @@ -1,20 +1,20 @@ -// -// HTTP Daemon Plugin Configuration -// - -// Enabled the http daemon? -enable_httpd: 1 - -// WWW Root path -//(The ending slash is required!) -document_root: httpd/ - -// Request timeout (first request) -// Both of the following are in milliseconds -request_timeout_first: 2500 - -// Request timeout (consequent requests) -request_timeout_persist: 60000 - -// Maximum persistent requests +// +// HTTP Daemon Plugin Configuration +// + +// Enabled the http daemon? +enable_httpd: 1 + +// WWW Root path +//(The ending slash is required!) +document_root: httpd/ + +// Request timeout (first request) +// Both of the following are in milliseconds +request_timeout_first: 2500 + +// Request timeout (consequent requests) +request_timeout_persist: 60000 + +// Maximum persistent requests max_persist_request: 32 \ No newline at end of file diff --git a/src/plugins/pid.c b/src/plugins/pid.c index 1ceb49b6f..62eb6878c 100644 --- a/src/plugins/pid.c +++ b/src/plugins/pid.c @@ -1,54 +1,54 @@ - -#include -#include -#ifndef _WIN32 - #include -#else - #define getpid GetCurrentProcessId -#endif -#ifdef MINGW - #include - #include -#endif -#include "../common/plugin.h" - -PLUGIN_INFO = { - "ProcessId", - PLUGIN_ALL, - "1.0", - PLUGIN_VERSION, - "Logs the process ID" -}; - -PLUGIN_EVENTS_TABLE = { - { "pid_create", "Plugin_Init" }, - { "pid_delete", "Plugin_Final" }, - { NULL, NULL } -}; - -char pid_file[256]; -char *server_name; - -void pid_create () -{ - FILE *fp; - int len; - - IMPORT_SYMBOL(server_name, 1); - len = strlen(server_name); - strcpy(pid_file, server_name); - if(len > 4 && pid_file[len - 4] == '.') { - pid_file[len - 4] = 0; - } - strcat(pid_file, ".pid"); - fp = fopen(pid_file, "w"); - if (fp) { - fprintf(fp, "%d", getpid()); - fclose(fp); - } -} - -void pid_delete () -{ - unlink(pid_file); -} + +#include +#include +#ifndef _WIN32 + #include +#else + #define getpid GetCurrentProcessId +#endif +#ifdef MINGW + #include + #include +#endif +#include "../common/plugin.h" + +PLUGIN_INFO = { + "ProcessId", + PLUGIN_ALL, + "1.0", + PLUGIN_VERSION, + "Logs the process ID" +}; + +PLUGIN_EVENTS_TABLE = { + { "pid_create", "Plugin_Init" }, + { "pid_delete", "Plugin_Final" }, + { NULL, NULL } +}; + +char pid_file[256]; +char *server_name; + +void pid_create () +{ + FILE *fp; + int len; + + IMPORT_SYMBOL(server_name, 1); + len = strlen(server_name); + strcpy(pid_file, server_name); + if(len > 4 && pid_file[len - 4] == '.') { + pid_file[len - 4] = 0; + } + strcat(pid_file, ".pid"); + fp = fopen(pid_file, "w"); + if (fp) { + fprintf(fp, "%d", getpid()); + fclose(fp); + } +} + +void pid_delete () +{ + unlink(pid_file); +} diff --git a/src/plugins/sample.c b/src/plugins/sample.c index 5a8e2a286..39e95752b 100644 --- a/src/plugins/sample.c +++ b/src/plugins/sample.c @@ -1,77 +1,77 @@ -// Sample Athena plugin - -#include -#include -#include "../common/plugin.h" - -////// Plugin information //////// -// -PLUGIN_INFO = { -// change only the following area - "Test", // Plugin name - PLUGIN_ALL, // Which servers is this plugin for - "0.1", // Plugin version - PLUGIN_VERSION, // Minimum plugin engine version to run - "A sample plugin" // Short description of plugin -}; - -////// Plugin event list ////////// -// Format: , -// All registered functions to a event gets executed -// (In descending order) when its called. -// Multiple functions can be called by multiple events too, -// So it's up to your creativity ^^ -// -PLUGIN_EVENTS_TABLE = { -// change only the following area - { "test_me", "Plugin_Test" }, // when the plugin is tested for compatibility - { "do_init", "Plugin_Init" }, // when plugins are loaded - { "do_final", "Plugin_Final" }, // when plugins are unloaded - { "some_function", "some_event" }, - { "some_function", "another_event" }, - { NULL, NULL } -}; - -///// Variables ///// -char *server_type; -char *server_name; - -//////// Plugin functions ////////// -int do_init () -{ - // import symbols from the server - IMPORT_SYMBOL(server_type, 0); - IMPORT_SYMBOL(server_name, 1); - - printf ("Server type is "); - switch (*server_type) { - case PLUGIN_LOGIN: printf ("Login\n"); break; - case PLUGIN_CHAR: printf ("Char\n"); break; - case PLUGIN_MAP: printf ("Map\n"); break; - } - printf ("Filename is %s\n", server_name); - - return 1; -} - -int do_final () -{ - printf ("Bye world\n"); - - return 1; -} - -int some_function () -{ - printf ("Some function\n"); - return 0; -} - -// return 1 if the testing passes, otherwise 0 -// (where the plugin will be deactivated) -int test_me () -{ - if (1 + 1 == 2) - return 1; - return 0; -} +// Sample Athena plugin + +#include +#include +#include "../common/plugin.h" + +////// Plugin information //////// +// +PLUGIN_INFO = { +// change only the following area + "Test", // Plugin name + PLUGIN_ALL, // Which servers is this plugin for + "0.1", // Plugin version + PLUGIN_VERSION, // Minimum plugin engine version to run + "A sample plugin" // Short description of plugin +}; + +////// Plugin event list ////////// +// Format: , +// All registered functions to a event gets executed +// (In descending order) when its called. +// Multiple functions can be called by multiple events too, +// So it's up to your creativity ^^ +// +PLUGIN_EVENTS_TABLE = { +// change only the following area + { "test_me", "Plugin_Test" }, // when the plugin is tested for compatibility + { "do_init", "Plugin_Init" }, // when plugins are loaded + { "do_final", "Plugin_Final" }, // when plugins are unloaded + { "some_function", "some_event" }, + { "some_function", "another_event" }, + { NULL, NULL } +}; + +///// Variables ///// +char *server_type; +char *server_name; + +//////// Plugin functions ////////// +int do_init () +{ + // import symbols from the server + IMPORT_SYMBOL(server_type, 0); + IMPORT_SYMBOL(server_name, 1); + + printf ("Server type is "); + switch (*server_type) { + case PLUGIN_LOGIN: printf ("Login\n"); break; + case PLUGIN_CHAR: printf ("Char\n"); break; + case PLUGIN_MAP: printf ("Map\n"); break; + } + printf ("Filename is %s\n", server_name); + + return 1; +} + +int do_final () +{ + printf ("Bye world\n"); + + return 1; +} + +int some_function () +{ + printf ("Some function\n"); + return 0; +} + +// return 1 if the testing passes, otherwise 0 +// (where the plugin will be deactivated) +int test_me () +{ + if (1 + 1 == 2) + return 1; + return 0; +} diff --git a/src/plugins/sig.c b/src/plugins/sig.c index 7ddfaf2dc..edd0e55a2 100644 --- a/src/plugins/sig.c +++ b/src/plugins/sig.c @@ -1,211 +1,211 @@ -// $Id: sig.c 1 2005-6-13 3:17:17 PM Celestia $ - -#include -#include -#include -#include -#include -#include "../common/plugin.h" -#include "../common/version.h" -#include "../common/showmsg.h" - -PLUGIN_INFO = { - "Signals", - PLUGIN_CORE, - "1.1", - PLUGIN_VERSION, - "Handles program signals" -}; - -PLUGIN_EVENTS_TABLE = { - { "sig_init", "Plugin_Init" }, - { "sig_final", "Plugin_Final" }, - { NULL, NULL } -}; - -////////////////////////////////////// - -#if defined(_WIN32) || defined(MINGW) - int sig_init() { - ShowError("sig: This plugin is not supported - Enable 'exchndl' instead!\n"); - return 0; - } - int sig_final() { return 0; } -#elif defined (__NETBSD__) || defined (__FREEBSD__) - int sig_init() { - ShowError("sig: This plugin is not supported!\n"); - return 0; - } - int sig_final() { return 0; } -#else - -////////////////////////////////////// - -#if !defined(CYGWIN) - #include -#endif - -const char* (*getrevision)(); -unsigned long (*getuptime)(); -char *server_name; -int crash_flag = 0; - -extern const char *strsignal(int); -int sig_final (); - -// by Gabuzomeu -// This is an implementation of signal() using sigaction() for portability. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -#ifdef WIN32 // windows don't have SIGPIPE -#define SIGPIPE SIGINT -#endif - -#ifndef POSIX -#define compat_signal(signo, func) signal(signo, func) -#else -sigfunc *compat_signal(int signo, sigfunc *func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; -#ifdef SA_INTERRUPT - sact.sa_flags |= SA_INTERRUPT; /* SunOS */ -#endif - - if (sigaction(signo, &sact, &oact) < 0) - return (SIG_ERR); - - return (oact.sa_handler); -} -#endif - -/*========================================= - * Dumps the stack using glibc's backtrace - *----------------------------------------- - */ -#ifdef CYGWIN - #define FOPEN_ freopen - extern void cygwin_stackdump(); -#else - #define FOPEN_(fn,m,s) fopen(fn,m) -#endif -void sig_dump(int sn) -{ - FILE *fp; - char file[256]; - int no = 0; - - crash_flag = 1; - // search for a usable filename - do { - sprintf (file, "log/%s%04d.stackdump", server_name, ++no); - } while((fp = fopen(file,"r")) && (fclose(fp), no < 9999)); - // dump the trace into the file - - if ((fp = FOPEN_(file, "w", stderr)) != NULL) { - const char *revision; - #ifndef CYGWIN - void* array[20]; - char **stack; - size_t size; - #endif - - ShowNotice ("Dumping stack to '"CL_WHITE"%s"CL_RESET"'...\n", file); - if ((revision = getrevision()) != NULL) - fprintf(fp, "Version: svn%s \n", revision); - else - fprintf(fp, "Version: %2d.%02d.%02d mod%02d \n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION); - fprintf(fp, "Exception: %s \n", strsignal(sn)); - fflush (fp); - - #ifdef CYGWIN - cygwin_stackdump (); - #else - fprintf(fp, "Stack trace:\n"); - size = backtrace (array, 20); - stack = backtrace_symbols (array, size); - for (no = 0; no < size; no++) { - fprintf(fp, "%s\n", stack[no]); - } - fprintf(fp,"End of stack trace\n"); - free(stack); - #endif - - ShowNotice("%s Saved.\n", file); - fflush(stdout); - fclose(fp); - } - - sig_final(); // Log our uptime - // Pass the signal to the system's default handler - compat_signal(sn, SIG_DFL); - raise(sn); -} - -/*========================================= - * Shutting down (Program did not crash ^^) - * - Log our current up time - *----------------------------------------- - */ -int sig_final () -{ - time_t curtime; - char curtime2[24]; - FILE *fp; - long seconds = 0, day = 24*60*60, hour = 60*60, - minute = 60, days = 0, hours = 0, minutes = 0; - - fp = fopen("log/uptime.log","a"); - if (fp) { - time(&curtime); - strftime(curtime2, 24, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - - seconds = getuptime(); - days = seconds/day; - seconds -= (seconds/day>0)?(seconds/day)*day:0; - hours = seconds/hour; - seconds -= (seconds/hour>0)?(seconds/hour)*hour:0; - minutes = seconds/minute; - seconds -= (seconds/minute>0)?(seconds/minute)*minute:0; - - fprintf(fp, "%s: %s %s - %ld days, %ld hours, %ld minutes, %ld seconds.\n", - curtime2, server_name, (crash_flag ? "crashed" : "uptime"), - days, hours, minutes, seconds); - fclose(fp); - } - - return 1; -} - -/*========================================= - * Register the signal handlers - *----------------------------------------- - */ -int sig_init () -{ - void (*func) = sig_dump; -#ifdef CYGWIN // test if dumper is enabled - char *buf = getenv ("CYGWIN"); - if (buf && strstr(buf, "error_start") != NULL) - func = SIG_DFL; -#endif - - IMPORT_SYMBOL(server_name, 1); - IMPORT_SYMBOL(getrevision, 6); - IMPORT_SYMBOL(getuptime, 11); - - compat_signal(SIGSEGV, func); - compat_signal(SIGFPE, func); - compat_signal(SIGILL, func); - #ifndef __WIN32 - compat_signal(SIGBUS, func); - #endif - - return 1; -} -#endif - +// $Id: sig.c 1 2005-6-13 3:17:17 PM Celestia $ + +#include +#include +#include +#include +#include +#include "../common/plugin.h" +#include "../common/version.h" +#include "../common/showmsg.h" + +PLUGIN_INFO = { + "Signals", + PLUGIN_CORE, + "1.1", + PLUGIN_VERSION, + "Handles program signals" +}; + +PLUGIN_EVENTS_TABLE = { + { "sig_init", "Plugin_Init" }, + { "sig_final", "Plugin_Final" }, + { NULL, NULL } +}; + +////////////////////////////////////// + +#if defined(_WIN32) || defined(MINGW) + int sig_init() { + ShowError("sig: This plugin is not supported - Enable 'exchndl' instead!\n"); + return 0; + } + int sig_final() { return 0; } +#elif defined (__NETBSD__) || defined (__FREEBSD__) + int sig_init() { + ShowError("sig: This plugin is not supported!\n"); + return 0; + } + int sig_final() { return 0; } +#else + +////////////////////////////////////// + +#if !defined(CYGWIN) + #include +#endif + +const char* (*getrevision)(); +unsigned long (*getuptime)(); +char *server_name; +int crash_flag = 0; + +extern const char *strsignal(int); +int sig_final (); + +// by Gabuzomeu +// This is an implementation of signal() using sigaction() for portability. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +#ifdef WIN32 // windows don't have SIGPIPE +#define SIGPIPE SIGINT +#endif + +#ifndef POSIX +#define compat_signal(signo, func) signal(signo, func) +#else +sigfunc *compat_signal(int signo, sigfunc *func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; +#ifdef SA_INTERRUPT + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ +#endif + + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); + + return (oact.sa_handler); +} +#endif + +/*========================================= + * Dumps the stack using glibc's backtrace + *----------------------------------------- + */ +#ifdef CYGWIN + #define FOPEN_ freopen + extern void cygwin_stackdump(); +#else + #define FOPEN_(fn,m,s) fopen(fn,m) +#endif +void sig_dump(int sn) +{ + FILE *fp; + char file[256]; + int no = 0; + + crash_flag = 1; + // search for a usable filename + do { + sprintf (file, "log/%s%04d.stackdump", server_name, ++no); + } while((fp = fopen(file,"r")) && (fclose(fp), no < 9999)); + // dump the trace into the file + + if ((fp = FOPEN_(file, "w", stderr)) != NULL) { + const char *revision; + #ifndef CYGWIN + void* array[20]; + char **stack; + size_t size; + #endif + + ShowNotice ("Dumping stack to '"CL_WHITE"%s"CL_RESET"'...\n", file); + if ((revision = getrevision()) != NULL) + fprintf(fp, "Version: svn%s \n", revision); + else + fprintf(fp, "Version: %2d.%02d.%02d mod%02d \n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION); + fprintf(fp, "Exception: %s \n", strsignal(sn)); + fflush (fp); + + #ifdef CYGWIN + cygwin_stackdump (); + #else + fprintf(fp, "Stack trace:\n"); + size = backtrace (array, 20); + stack = backtrace_symbols (array, size); + for (no = 0; no < size; no++) { + fprintf(fp, "%s\n", stack[no]); + } + fprintf(fp,"End of stack trace\n"); + free(stack); + #endif + + ShowNotice("%s Saved.\n", file); + fflush(stdout); + fclose(fp); + } + + sig_final(); // Log our uptime + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); +} + +/*========================================= + * Shutting down (Program did not crash ^^) + * - Log our current up time + *----------------------------------------- + */ +int sig_final () +{ + time_t curtime; + char curtime2[24]; + FILE *fp; + long seconds = 0, day = 24*60*60, hour = 60*60, + minute = 60, days = 0, hours = 0, minutes = 0; + + fp = fopen("log/uptime.log","a"); + if (fp) { + time(&curtime); + strftime(curtime2, 24, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + + seconds = getuptime(); + days = seconds/day; + seconds -= (seconds/day>0)?(seconds/day)*day:0; + hours = seconds/hour; + seconds -= (seconds/hour>0)?(seconds/hour)*hour:0; + minutes = seconds/minute; + seconds -= (seconds/minute>0)?(seconds/minute)*minute:0; + + fprintf(fp, "%s: %s %s - %ld days, %ld hours, %ld minutes, %ld seconds.\n", + curtime2, server_name, (crash_flag ? "crashed" : "uptime"), + days, hours, minutes, seconds); + fclose(fp); + } + + return 1; +} + +/*========================================= + * Register the signal handlers + *----------------------------------------- + */ +int sig_init () +{ + void (*func) = sig_dump; +#ifdef CYGWIN // test if dumper is enabled + char *buf = getenv ("CYGWIN"); + if (buf && strstr(buf, "error_start") != NULL) + func = SIG_DFL; +#endif + + IMPORT_SYMBOL(server_name, 1); + IMPORT_SYMBOL(getrevision, 6); + IMPORT_SYMBOL(getuptime, 11); + + compat_signal(SIGSEGV, func); + compat_signal(SIGFPE, func); + compat_signal(SIGILL, func); + #ifndef __WIN32 + compat_signal(SIGBUS, func); + #endif + + return 1; +} +#endif + diff --git a/src/plugins/upnp.txt b/src/plugins/upnp.txt index 32d0e75bf..d5d0d43ff 100644 --- a/src/plugins/upnp.txt +++ b/src/plugins/upnp.txt @@ -1,31 +1,31 @@ -// -// UPnP Plugin Configuration -// - -// Enable UPnP -enable_upnp: 1 - -// Remove mapped router ports when shutting down -release_mappings: 1 - -// Close opened firewall ports when shutting down -close_ports: 1 - -// -// You can set these if necessary -// login server port -//login_port: 6900 -// -// char server port -//char_port: 6121 -// -// map server port -//map_port: 5121 -// -// NAT IP address to map your ports to -//nat_ip: 192.168.0.1 - - -// Note: This plugin only works on Windows XP or higher -// For more info on UPnP try here: +// +// UPnP Plugin Configuration +// + +// Enable UPnP +enable_upnp: 1 + +// Remove mapped router ports when shutting down +release_mappings: 1 + +// Close opened firewall ports when shutting down +close_ports: 1 + +// +// You can set these if necessary +// login server port +//login_port: 6900 +// +// char server port +//char_port: 6121 +// +// map server port +//map_port: 5121 +// +// NAT IP address to map your ports to +//nat_ip: 192.168.0.1 + + +// Note: This plugin only works on Windows XP or higher +// For more info on UPnP try here: // http://www.google.com/search?q=what+is+upnp \ No newline at end of file -- cgit v1.2.3-70-g09d2