mirror of
https://bitbucket.org/jsuto/piler.git
synced 2026-04-05 18:19:19 +02:00
initial release
This commit is contained in:
249
src/piler.c
Normal file
249
src/piler.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* piler.c, SJ
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <piler.h>
|
||||
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
int sd;
|
||||
int nconn = 0;
|
||||
char *configfile = CONFIG_FILE;
|
||||
struct __config cfg;
|
||||
struct __data data;
|
||||
struct passwd *pwd;
|
||||
|
||||
|
||||
void clean_exit(){
|
||||
if(sd != -1) close(sd);
|
||||
|
||||
freeList(data.blackhole);
|
||||
|
||||
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
|
||||
|
||||
unlink(cfg.pidfile);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void fatal(char *s){
|
||||
syslog(LOG_PRIORITY, "%s\n", s);
|
||||
clean_exit();
|
||||
}
|
||||
|
||||
|
||||
void sigchld(){
|
||||
int pid, wstat;
|
||||
|
||||
while((pid = wait_nohang(&wstat)) > 0){
|
||||
if(nconn > 0) nconn--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void initialiseConfiguration(){
|
||||
|
||||
cfg = read_config(configfile);
|
||||
|
||||
if(strlen(cfg.username) > 1){
|
||||
pwd = getpwnam(cfg.username);
|
||||
if(!pwd) fatal(ERR_NON_EXISTENT_USER);
|
||||
}
|
||||
|
||||
|
||||
if(getuid() == 0 && pwd){
|
||||
check_and_create_directories(&cfg, pwd->pw_uid, pwd->pw_gid);
|
||||
}
|
||||
|
||||
|
||||
if(chdir(cfg.workdir)){
|
||||
syslog(LOG_PRIORITY, "workdir: *%s*", cfg.workdir);
|
||||
fatal(ERR_CHDIR);
|
||||
}
|
||||
|
||||
setlocale(LC_MESSAGES, cfg.locale);
|
||||
setlocale(LC_CTYPE, cfg.locale);
|
||||
|
||||
freeList(data.blackhole);
|
||||
data.blackhole = NULL;
|
||||
|
||||
syslog(LOG_PRIORITY, "reloaded config: %s", configfile);
|
||||
|
||||
#ifdef HAVE_MEMCACHED
|
||||
memcached_init(&(data.memc), cfg.memcached_servers, 11211);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int read_key(struct __config *cfg){
|
||||
int fd, n;
|
||||
|
||||
fd = open(KEYFILE, O_RDONLY);
|
||||
if(fd == -1){
|
||||
syslog(LOG_PRIORITY, "cannot read keyfile: %s", KEYFILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = read(fd, cfg->key, KEYLEN);
|
||||
|
||||
close(fd);
|
||||
|
||||
if(n > 5) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i, new_sd, yes=1, pid, daemonise=0;
|
||||
unsigned int clen;
|
||||
struct sockaddr_in client_addr, serv_addr;
|
||||
struct in_addr addr;
|
||||
|
||||
while((i = getopt(argc, argv, "c:dvVh")) > 0){
|
||||
switch(i){
|
||||
|
||||
case 'c' :
|
||||
configfile = optarg;
|
||||
break;
|
||||
|
||||
case 'd' :
|
||||
daemonise = 1;
|
||||
break;
|
||||
|
||||
case 'v' :
|
||||
case 'V' :
|
||||
__fatal(PROGNAME " " PROGINFO);
|
||||
break;
|
||||
|
||||
case 'h' :
|
||||
default :
|
||||
__fatal("usage: ...");
|
||||
}
|
||||
}
|
||||
|
||||
(void) openlog(PROGNAME, LOG_PID, LOG_MAIL);
|
||||
|
||||
sig_catch(SIGINT, clean_exit);
|
||||
sig_catch(SIGQUIT, clean_exit);
|
||||
sig_catch(SIGKILL, clean_exit);
|
||||
sig_catch(SIGTERM, clean_exit);
|
||||
sig_catch(SIGHUP, initialiseConfiguration);
|
||||
|
||||
|
||||
data.blackhole = NULL;
|
||||
|
||||
|
||||
sig_block(SIGCHLD);
|
||||
sig_catch(SIGCHLD, sigchld);
|
||||
|
||||
|
||||
initialiseConfiguration();
|
||||
|
||||
|
||||
if(read_key(&cfg)) fatal(ERR_READING_KEY);
|
||||
|
||||
|
||||
if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
fatal(ERR_OPEN_SOCKET);
|
||||
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(cfg.listen_port);
|
||||
inet_aton(cfg.listen_addr, &addr);
|
||||
serv_addr.sin_addr.s_addr = addr.s_addr;
|
||||
bzero(&(serv_addr.sin_zero), 8);
|
||||
|
||||
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
|
||||
fatal(ERR_SET_SOCK_OPT);
|
||||
|
||||
if(bind(sd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
|
||||
fatal(ERR_BIND_TO_PORT);
|
||||
|
||||
if(listen(sd, cfg.backlog) == -1)
|
||||
fatal(ERR_LISTEN);
|
||||
|
||||
|
||||
if(drop_privileges(pwd)) fatal(ERR_SETUID);
|
||||
|
||||
|
||||
syslog(LOG_PRIORITY, "%s %s starting", PROGNAME, VERSION);
|
||||
|
||||
|
||||
#if HAVE_DAEMON == 1
|
||||
if(daemonise == 1) i = daemon(1, 0);
|
||||
#endif
|
||||
|
||||
write_pid_file(cfg.pidfile);
|
||||
|
||||
|
||||
/* main accept loop */
|
||||
|
||||
for(;;){
|
||||
|
||||
/* let new connections wait if we are too busy now */
|
||||
|
||||
if(nconn >= cfg.max_connections) sig_pause();
|
||||
|
||||
clen = sizeof(client_addr);
|
||||
|
||||
sig_unblock(SIGCHLD);
|
||||
new_sd = accept(sd, (struct sockaddr *)&client_addr, &clen);
|
||||
sig_block(SIGCHLD);
|
||||
|
||||
if(new_sd == -1) continue;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if(pid == 0){
|
||||
sig_uncatch(SIGCHLD);
|
||||
sig_unblock(SIGCHLD);
|
||||
|
||||
sig_uncatch(SIGINT);
|
||||
sig_uncatch(SIGQUIT);
|
||||
sig_uncatch(SIGKILL);
|
||||
sig_uncatch(SIGTERM);
|
||||
sig_block(SIGHUP);
|
||||
|
||||
syslog(LOG_PRIORITY, "connection from client: %s", inet_ntoa(client_addr.sin_addr));
|
||||
|
||||
handle_smtp_session(new_sd, &data, &cfg);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
else if(pid > 0){
|
||||
nconn++;
|
||||
}
|
||||
|
||||
else {
|
||||
syslog(LOG_PRIORITY, "%s", ERR_FORK_FAILED);
|
||||
}
|
||||
|
||||
close(new_sd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user