/* * newslettersan.c * * Small newsletter web server * * Author: Dario Rodriguez dario@softhome.net * This program is licensed under the terms of the Affero GPL v1+ */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include "gen_res.h" #include "socklib.h" #include "loglib.h" #include "webkernel.h" #include "newslettersan.h" #include "newsl_config.h" #define CONFIGFILE "newslettersan.cfg" #define CFLOGFILE "newslettersan.log" static int signal_init(int signum, void (*fn)(int)); static void sigint(int signum); volatile int sigint_flag=0; wk_action callback_http(wk *web, int connid, wk_uri *uri, void *userptr); int main(int argc, char *argv[]) { int timeout=500; int serverfd; newslettersan *newsl,newslstore; char *hostnameport; char hostname[128]; char *host; long hostsize; char *ptr,*sep; memset(&newslstore,0,sizeof(newslstore)); newsl=&newslstore; if(argc!=2) { printf("Syntax: %s [ip:]port\n",argv[0]); return(1); } hostnameport=argv[1]; if(newslconfig_exists(CONFIGFILE)!=0) { log_setlogfile(CFLOGFILE); log_write("INIT","Config file not found, writing default file %s",CONFIGFILE); newslconfig_write(CONFIGFILE,CFLOGFILE); } if((newsl->config=newslconfig_init(CONFIGFILE))==NULL) { log_setlogfile(CFLOGFILE); log_write("INIT","ERROR: insufficient memory or config file error"); return(1); } log_setlogfile((newsl->config->logfile!=NULL)?newsl->config->logfile:CFLOGFILE); if((newsl->ssel=sselect_init())==NULL) { log_write("INIT","ERROR: insufficient memory"); return(1); } if((sep=strchr(hostnameport,':'))!=NULL) { serverfd=-1; strncpy(hostname,hostnameport,sizeof(hostname)); hostname[sizeof(hostname)-1]='\0'; if((ptr=strchr(hostname,':'))!=NULL) *ptr='\0'; if((host=ipv4_genip(hostname,&hostsize))!=NULL) { serverfd=ipv4_serverbinded(host,hostsize,atoi(sep+1)); free(host),host=NULL; } } else { serverfd=ipv4_server(atoi(hostnameport)); } if(serverfd==-1) { sselect_free(newsl->ssel),newsl->ssel=NULL; log_write("INIT","ERROR: couldn't listen on port"); return(2); } sock_setunsafe(serverfd); if((newsl->web=wk_init(serverfd,newsl->ssel,NULL,callback_http,NULL,NULL,newsl))==NULL) { sselect_free(newsl->ssel),newsl->ssel=NULL; log_write("INIT","ERROR: couldn't init web server"); return(2); } sigint_flag=0; signal_init(SIGINT,sigint); log_write("INIT","Server initialized, waiting connections..."); while(!sigint_flag) { sselect_wait(newsl->ssel,timeout); if(sigint_flag) break; wk_service(newsl->web); } wk_free(newsl->web),newsl->web=NULL; close(serverfd),serverfd=-1; sselect_free(newsl->ssel),newsl->ssel=NULL; newslconfig_free(newsl->config),newsl->config=NULL; log_write("FINI","SIGINT detected, exiting..."); return(0); } static int signal_init(int signum, void (*fn)(int)) { struct sigaction sa; sa.sa_handler=fn; sigemptyset(&sa.sa_mask); sa.sa_flags=0; return(sigaction(signum,&sa,0)); } static void sigint(int signum) { sigint_flag=1; } wk_action callback_http(wk *web, int connid, wk_uri *uri, void *userptr) { newslettersan *newsl=(newslettersan *)userptr; resindex *res; char partialpath[1024]; if(newsl==NULL) return(wkact_finished); strncpy(partialpath,uri->path,sizeof(partialpath)-1); partialpath[sizeof(partialpath)-1]='\0'; if(strcmp(uri->path,"/")==0) strcpy(partialpath,"/index.html"); if(partialpath[0]=='/' && (res=res_find(resindexdata,partialpath+1))!=NULL) { log_write("HTTP","Serving in-memory file %s",partialpath+1); wk_serve_etagset(web,connid,res->etag); wk_serve_buffer_as_file(web,connid,res->data,res->len,mime_getdefault(res->name,"application/octet-stream")); return(wkact_finished); } wk_serve_error(web,connid,wkerr_notfound); return(wkact_finished); }