#include "jabberd.h"
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "single.h"
#include "revision.h"
HASHTABLE cmd__line, debug__zones;
extern HASHTABLE instance__ids;
extern int deliver__flag;
extern xmlnode greymatter__;
pool jabberd__runtime = NULL;
static char *cfgfile = NULL;
int jabberd__signalflag = 0;
int configurate(char *file);
void static_init(void);
void dynamic_init(void);
void deliver_init(void);
void heartbeat_birth(void);
void heartbeat_death(void);
int configo(int exec);
void shutdown_callbacks(void);
int config_reload(char *file);
int instance_startup(xmlnode x, int exec);
void instance_shutdown(instance i);
void _jabberd_signal(int sig);
void RemovePIDfile(void);
void Exit(int status);
void MaxOpenFiles()
{
struct rlimit rl;
rl.rlim_cur = RLIM_INFINITY;
rl.rlim_max = RLIM_INFINITY;
getrlimit(RLIMIT_NOFILE, &rl);
log_debug(ZONE,"current open file limit: %lu", (long unsigned) rl.rlim_cur);
log_debug(ZONE,"max open file limit: %lu", (long unsigned) rl.rlim_max);
rl.rlim_cur = FD_SETSIZE;
rl.rlim_max = FD_SETSIZE;
setrlimit (RLIMIT_NOFILE, &rl);
getrlimit(RLIMIT_NOFILE, &rl);
log_debug(ZONE,"new open file limit: %lu", (long unsigned) rl.rlim_cur);
log_debug(ZONE,"new open file max: %lu", (long unsigned) rl.rlim_max);
}
void Exit(int status)
{
RemovePIDfile();
exit(status);
}
int main (int argc, char** argv)
{
int help, i;
char *c, *cmd, *home = NULL;
pool cfg_pool=pool_new();
float avload;
int do_debug = 0;
int do_background = 0;
jabberd__runtime = pool_new();
help = 0;
cmd__line = ghash_create_pool(jabberd__runtime, 11,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp);
for(i = 1; i < argc; i++)
{
if(argv[i][0]!='-')
{
help=1;
break;
}
for(c=argv[i]+1;c[0]!='\0';c++)
{
if(*c == 'D')
{
do_debug = 1;
continue;
}
else if(*c == 'V' || *c == 'v')
{
printf("Jabberd Version %s Build %s\n", VERSION, BUILD);
exit(0);
}
else if(*c == 'B')
{
if (do_debug)
{
printf("Debug output is enabled, can not background.\n");
}
else
{
do_background = 1;
}
continue;
}
cmd = pmalloco(cfg_pool,2);
cmd[0]=*c;
if(i+1<argc)
{
ghash_put(cmd__line,cmd,argv[++i]);
}else{
help=1;
break;
}
}
}
if((cmd = ghash_get(cmd__line,"Z")) != NULL)
{
set_debug_flag(1);
debug__zones = ghash_create_pool(jabberd__runtime, 11,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp);
while(cmd != NULL)
{
c = strchr(cmd,',');
if(c != NULL)
{
*c = '\0';
c++;
}
ghash_put(debug__zones,cmd,cmd);
cmd = c;
}
}else{
debug__zones = NULL;
}
if(help)
{
fprintf(stderr,"Usage:\n%s [params]\n Optional Parameters:\n -c\t\tconfiguration file\n -D\t\tenable debug output (disables background)\n -H\t\tlocation of home folder\n -B\t\tbackground the server process\n -Z\t\tdebug zones\n -v\t\tserver version\n -V\t\tserver version\n", argv[0]);
exit(0);
}
set_debug_flag(do_debug);
MaxOpenFiles();
#ifdef SINGLE
SINGLE_STARTUP
#else
if((home = ghash_get(cmd__line,"H")) == NULL)
home = pstrdup(jabberd__runtime,HOME);
#endif
cmd = ghash_get(cmd__line, "U");
if (cmd == NULL)
cmd = pstrdup(jabberd__runtime,"jabber");
if (cmd != NULL)
{
struct passwd* user = NULL;
user = getpwnam(cmd);
if (user == NULL)
{
fprintf(stderr, "Unable to lookup user %s.\n", cmd);
exit(1);
}
if (initgroups(cmd, user->pw_gid) < 0)
{
fprintf(stderr, "Unable to initialize group memberships.\n");
exit(1);
}
if (setgid(user->pw_gid) < 0)
{
fprintf(stderr, "Unable to set group permissions.\n");
exit(1);
}
if (setuid(user->pw_uid) < 0)
{
fprintf(stderr, "Unable to set user permissions.\n");
exit(1);
}
}
if(home != NULL && chdir(home))
fprintf(stderr,"Unable to access home folder %s: %s\n",home,strerror(errno));
if(do_background != 0)
{
if (fork() != 0)
{
exit(0);
}
}
if((cfgfile = ghash_get(cmd__line,"c")) == NULL)
cfgfile = pstrdup(jabberd__runtime,CONFIGXML);
if(configurate(cfgfile))
Exit(1);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP,_jabberd_signal);
signal(SIGINT,_jabberd_signal);
signal(SIGTERM,_jabberd_signal);
openlog("iChatServer-jabberd", LOG_PID, LOG_DAEMON);
pth_init();
heartbeat_birth();
mio_init();
static_init();
dynamic_init();
deliver_init();
deliver__flag = 0;
if(configo(0))
Exit(1);
log_notice(NULL,"initializing server");
if(configo(1))
Exit(1);
log_notice(NULL,"server started");
deliver__flag=1;
deliver(NULL,NULL);
while(1)
{
pth_ctrl(PTH_CTRL_GETAVLOAD, &avload);
log_debug(ZONE,"main load check of %.2f with %ld total threads", avload, pth_ctrl(PTH_CTRL_GETTHREADS));
pth_sleep(60);
};
return 0;
}
void _jabberd_signal(int sig)
{
log_debug(ZONE,"received signal %d",sig);
jabberd__signalflag = sig;
}
void _jabberd_restart(void)
{
xmlnode temp_greymatter;
log_notice(NULL, "reloading configuration");
temp_greymatter = greymatter__;
log_debug(ZONE, "Loading new config file");
if(configurate(cfgfile))
{
log_debug(ZONE, "Failed to load new config, resetting greymatter");
log_alert(ZONE, "Failed to reload config! Resetting internal config -- please check your configuration!");
greymatter__ = temp_greymatter;
return;
}
log_debug(ZONE, "reload process complete");
}
void RemovePIDfile(void)
{
xmlnode pidfile;
char *pidpath;
pidfile = xmlnode_get_tag(greymatter__, "pidfile");
if(pidfile != NULL)
{
pidpath = xmlnode_get_data(pidfile);
if(pidpath != NULL)
unlink(pidpath);
}
}
void _jabberd_shutdown(void)
{
log_notice(NULL,"shutting down server");
deliver__flag = 0;
shutdown_callbacks();
pth_sleep(1);
mio_stop();
heartbeat_death();
pth_kill();
RemovePIDfile();
xmlnode_free(greymatter__);
pool_free(jabberd__runtime);
closelog();
exit(0);
}
void jabberd_signal(void)
{
if(jabberd__signalflag == SIGHUP)
{
_jabberd_restart();
jabberd__signalflag = 0;
return;
}
_jabberd_shutdown();
}