You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

643 lines
19 KiB

/***************************************************************************/
/* */
/* Project: OpenSLP - OpenSource implementation of Service Location */
/* Protocol Version 2 */
/* */
/* File: slpd_main.c */
/* */
/* Abstract: Main daemon loop */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Please submit patches to http://www.openslp.org */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Copyright (C) 2000 Caldera Systems, Inc */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the */
/* distribution. */
/* */
/* Neither the name of Caldera Systems nor the names of its */
/* contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/***************************************************************************/
#include "slpd.h"
/*=========================================================================*/
/* slpd includes */
/*=========================================================================*/
#include "slpd_log.h"
#include "slpd_socket.h"
#include "slpd_incoming.h"
#include "slpd_outgoing.h"
#include "slpd_database.h"
#include "slpd_cmdline.h"
#include "slpd_knownda.h"
#include "slpd_property.h"
#ifdef ENABLE_SLPv2_SECURITY
#include "slpd_spi.h"
#endif
/*=========================================================================*/
/* common code includes */
/*=========================================================================*/
#include "slp_xmalloc.h"
#include "slp_xid.h"
/*==========================================================================*/
int G_SIGALRM;
int G_SIGTERM;
int G_SIGHUP;
#ifdef DEBUG
int G_SIGINT; /* Signal being used for dumping registrations */
#endif
/*==========================================================================*/
/*-------------------------------------------------------------------------*/
void LoadFdSets(SLPList* socklist,
int* highfd,
fd_set* readfds,
fd_set* writefds)
/*-------------------------------------------------------------------------*/
{
SLPDSocket* sock = 0;
SLPDSocket* del = 0;
sock = (SLPDSocket*)socklist->head;
while(sock)
{
if(sock->fd > *highfd)
{
*highfd = sock->fd;
}
switch(sock->state)
{
case DATAGRAM_UNICAST:
case DATAGRAM_MULTICAST:
case DATAGRAM_BROADCAST:
FD_SET(sock->fd,readfds);
break;
case SOCKET_LISTEN:
if(socklist->count < SLPD_MAX_SOCKETS)
{
FD_SET(sock->fd,readfds);
}
break;
case STREAM_READ:
case STREAM_READ_FIRST:
FD_SET(sock->fd,readfds);
break;
case STREAM_WRITE:
case STREAM_WRITE_FIRST:
case STREAM_CONNECT_BLOCK:
FD_SET(sock->fd,writefds);
break;
case SOCKET_CLOSE:
del = sock;
break;
default:
break;
}
sock = (SLPDSocket*)sock->listitem.next;
if(del)
{
SLPDSocketFree((SLPDSocket*)SLPListUnlink(socklist,(SLPListItem*)del));
del = 0;
}
}
}
/*------------------------------------------------------------------------*/
void HandleSigTerm()
/*------------------------------------------------------------------------*/
{
struct timeval timeout;
fd_set readfds;
fd_set writefds;
int highfd = 0;
int fdcount = 0;
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon shutting down\n");
SLPDLog("****************************************\n");
/* close all incoming sockets */
SLPDIncomingDeinit();
/* unregister with all DAs */
SLPDKnownDADeinit();
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* Do a dead DA passive advert to tell everyone we're goin' down */
SLPDKnownDAPassiveDAAdvert(0, 1);
/* if possible wait until all outgoing socket are done and closed */
while(SLPDOutgoingDeinit(1))
{
FD_ZERO(&writefds);
FD_ZERO(&readfds);
LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds,&writefds);
fdcount = select(highfd+1,&readfds,&writefds,0,&timeout);
if(fdcount == 0)
{
break;
}
SLPDOutgoingHandler(&fdcount,&readfds,&writefds);
}
SLPDOutgoingDeinit(0);
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon shut down\n");
SLPDLog("****************************************\n");
#ifdef DEBUG
#ifdef ENABLE_SLPv2_SECURITY
SLPDSpiDeinit();
#endif
SLPDDatabaseDeinit();
SLPDPropertyDeinit();
SLPDLogFileClose();
xmalloc_deinit();
#endif
}
/*------------------------------------------------------------------------*/
void HandleSigHup()
/*------------------------------------------------------------------------*/
{
/* Reinitialize */
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon reset by SIGHUP\n");
SLPDLog("****************************************\n\n");
/* unregister with all DAs */
SLPDKnownDADeinit();
/* re-read properties */
SLPDPropertyInit(G_SlpdCommandLine.cfgfile);
#ifdef ENABLE_SLPv2_SECURITY
/* Re-initialize SPI stuff*/
SLPDSpiInit(G_SlpdCommandLine.spifile);
#endif
/* Re-read the static registration file (slp.reg)*/
SLPDDatabaseReInit(G_SlpdCommandLine.regfile);
/* Rebuild Known DA database */
SLPDKnownDAInit();
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon reset finished\n");
SLPDLog("****************************************\n\n");
}
/*------------------------------------------------------------------------*/
void HandleSigAlrm()
/*------------------------------------------------------------------------*/
{
SLPDIncomingAge(SLPD_AGE_INTERVAL);
SLPDOutgoingAge(SLPD_AGE_INTERVAL);
SLPDKnownDAImmortalRefresh(SLPD_AGE_INTERVAL);
SLPDKnownDAPassiveDAAdvert(SLPD_AGE_INTERVAL,0);
SLPDKnownDAActiveDiscovery(SLPD_AGE_INTERVAL);
SLPDDatabaseAge(SLPD_AGE_INTERVAL,G_SlpdProperty.isDA);
}
#ifdef DEBUG
/*--------------------------------------------------------------------------*/
void HandleSigInt()
/*--------------------------------------------------------------------------*/
{
SLPDIncomingSocketDump();
SLPDOutgoingSocketDump();
SLPDKnownDADump();
SLPDDatabaseDump();
}
#endif
#ifndef _WIN32
/*-------------------------------------------------------------------------*/
int CheckPid(const char* pidfile)
/* Check a pid file to see if slpd is already running */
/* */
/* Returns: 0 on success. non-zero on failure */
/*-------------------------------------------------------------------------*/
{
pid_t pid;
FILE* fd;
char pidstr[14];
/*------------------------------------------*/
/* make sure that we're not running already */
/*------------------------------------------*/
/* read the pid from the file */
fd = fopen(pidfile,"r");
if(fd)
{
memset(pidstr,0,14);
fread(pidstr,13,1,fd);
pid = atoi(pidstr);
if(pid)
{
if(kill(pid,0) == 0)
{
/* we are already running */
return -1;
}
}
fclose(fd);
}
return 0;
}
/*-------------------------------------------------------------------------*/
int WritePid(const char* pidfile, pid_t pid)
/* Write the pid file */
/* */
/* Returns: 0 on success. non-zero on failure */
/*-------------------------------------------------------------------------*/
{
FILE* fd;
char pidstr[14];
/* write my pid to the pidfile */
fd = fopen(pidfile,"w");
if(fd)
{
sprintf(pidstr,"%i",(int)pid);
fwrite(pidstr,strlen(pidstr),1,fd);
fclose(fd);
}
return 0;
}
/*-------------------------------------------------------------------------*/
int Daemonize(const char* pidfile)
/* Turn the calling process into a daemon (detach from tty setuid(), etc */
/* */
/* Returns: zero on success non-zero if slpd could not daemonize (or if */
/* slpd is already running . */
/*-------------------------------------------------------------------------*/
{
FILE* fd;
struct passwd* pwent;
pid_t pid;
char pidstr[14];
/* fork() if we should detach */
if(G_SlpdCommandLine.detach)
{
pid = fork();
}
else
{
pid = getpid();
}
/* parent or child? */
switch(pid)
{
case -1:
return -1;
case 0:
/* child lives */
break;
default:
/* parent writes pid (or child) pid file and dies */
fd = fopen(pidfile,"w");
if(fd)
{
sprintf(pidstr,"%i",(int)pid);
fwrite(pidstr,strlen(pidstr),1,fd);
fclose(fd);
}
if(G_SlpdCommandLine.detach)
{
exit(0);
}
break;
}
close(0);
close(1);
close(2);
setsid(); /* will only fail if we are already the process group leader */
/*----------------*/
/* suid to daemon */
/*----------------*/
/* TODO: why do the following lines mess up my signal handlers? */
pwent = getpwnam("daemon");
if(pwent)
{
if(setgroups(1, &pwent->pw_gid) < 0 ||
setgid(pwent->pw_gid) < 0 ||
setuid(pwent->pw_uid) < 0)
{
/* TODO: should we log here and return fail */
exit(1);
}
}
else
exit(1);
/*--------------------*/
/* Set cwd to / (root)*/
/*--------------------*/
chdir("/");
return 0;
}
/*--------------------------------------------------------------------------*/
void SignalHandler(int signum)
/*--------------------------------------------------------------------------*/
{
switch(signum)
{
case SIGALRM:
G_SIGALRM = 1;
break;
case SIGTERM:
G_SIGTERM = 1;
break;
case SIGHUP:
G_SIGHUP = 1;
break;
#ifdef DEBUG
case SIGINT:
G_SIGINT = 1;
break;
#endif
case SIGPIPE:
default:
break;
}
}
/*-------------------------------------------------------------------------*/
int SetUpSignalHandlers()
/*-------------------------------------------------------------------------*/
{
int result;
struct sigaction sa;
sa.sa_handler = SignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;//SA_ONESHOT;
#if defined(HAVE_SA_RESTORER)
sa.sa_restorer = 0;
#endif
result = sigaction(SIGALRM,&sa,0);
result |= sigaction(SIGTERM,&sa,0);
result |= sigaction(SIGPIPE,&sa,0);
#ifdef DEBUG
result |= sigaction(SIGINT,&sa,0);
#endif
signal(SIGHUP,SignalHandler);
//result |= sigaction(SIGHUP,&sa,0);
return result;
}
/*=========================================================================*/
int main(int argc, char* argv[])
/*=========================================================================*/
{
fd_set readfds;
fd_set writefds;
int highfd;
int fdcount = 0;
#ifdef DEBUG
xmalloc_init("/var/log/slpd_xmalloc.log",0);
#endif
/*------------------------*/
/* Parse the command line */
/*------------------------*/
if(SLPDParseCommandLine(argc,argv))
{
SLPDFatal("Invalid command line\n");
}
/*------------------------------*/
/* Make sure we are root */
/*------------------------------*/
if(getuid() != 0)
{
SLPDFatal("slpd must be started by root\n");
}
/*--------------------------------------*/
/* Make sure we are not already running */
/*--------------------------------------*/
if(CheckPid(G_SlpdCommandLine.pidfile))
{
SLPDFatal("slpd is already running. Check %s\n",
G_SlpdCommandLine.pidfile);
}
/*------------------------------*/
/* Initialize the log file */
/*------------------------------*/
if(SLPDLogFileOpen(G_SlpdCommandLine.logfile, 1))
{
SLPDFatal("Could not open logfile %s\n",G_SlpdCommandLine.logfile);
}
/*------------------------*/
/* Seed the XID generator */
/*------------------------*/
SLPXidSeed();
/*---------------------*/
/* Log startup message */
/*---------------------*/
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon started\n");
SLPDLog("****************************************\n");
SLPDLog("Command line = %s\n",argv[0]);
SLPDLog("Using configuration file = %s\n",G_SlpdCommandLine.cfgfile);
SLPDLog("Using registration file = %s\n",G_SlpdCommandLine.regfile);
#ifdef ENABLE_SLPv2_SECURITY
SLPDLog("Using SPI file = %s\n",G_SlpdCommandLine.spifile);
#endif
/*--------------------------------------------------*/
/* Initialize for the first time */
/*--------------------------------------------------*/
if(SLPDPropertyInit(G_SlpdCommandLine.cfgfile) ||
#ifdef ENABLE_SLPv2_SECURITY
SLPDSpiInit(G_SlpdCommandLine.spifile) ||
#endif
SLPDDatabaseInit(G_SlpdCommandLine.regfile) ||
SLPDIncomingInit() ||
SLPDOutgoingInit() ||
SLPDKnownDAInit())
{
SLPDFatal("slpd initialization failed\n");
}
SLPDLog("Agent Interfaces = %s\n",G_SlpdProperty.interfaces);
SLPDLog("Agent URL = %s\n",G_SlpdProperty.myUrl);
/*---------------------------*/
/* make slpd run as a daemon */
/*---------------------------*/
if(Daemonize(G_SlpdCommandLine.pidfile))
{
SLPDFatal("Could not daemonize\n");
}
/*-----------------------*/
/* Setup signal handlers */
/*-----------------------*/
if(SetUpSignalHandlers())
{
SLPDFatal("Error setting up signal handlers.\n");
}
/*------------------------------*/
/* Set up alarm to age database */
/*------------------------------*/
alarm(SLPD_AGE_INTERVAL);
/*-----------*/
/* Main loop */
/*-----------*/
SLPDLog("Startup complete entering main run loop ...\n\n");
G_SIGALRM = 0;
G_SIGTERM = 0;
G_SIGHUP = 0;
#ifdef DEBUG
G_SIGINT = 0;
#endif
while(G_SIGTERM == 0)
{
/*--------------------------------------------------------*/
/* Load the fdsets up with all valid sockets in the list */
/*--------------------------------------------------------*/
highfd = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
LoadFdSets(&G_IncomingSocketList, &highfd, &readfds,&writefds);
LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds,&writefds);
/*--------------------------------------------------*/
/* Before select(), check to see if we got a signal */
/*--------------------------------------------------*/
if(G_SIGALRM || G_SIGHUP)
{
goto HANDLE_SIGNAL;
}
/*-------------*/
/* Main select */
/*-------------*/
fdcount = select(highfd+1,&readfds,&writefds,0,0);
if(fdcount > 0) /* fdcount will be < 0 when interrupted by a signal */
{
SLPDIncomingHandler(&fdcount,&readfds,&writefds);
SLPDOutgoingHandler(&fdcount,&readfds,&writefds);
}
/*----------------*/
/* Handle signals */
/*----------------*/
HANDLE_SIGNAL:
if(G_SIGHUP)
{
HandleSigHup();
G_SIGHUP = 0;
}
if(G_SIGALRM)
{
HandleSigAlrm();
G_SIGALRM = 0;
alarm(SLPD_AGE_INTERVAL);
}
#ifdef DEBUG
if (G_SIGINT)
{
HandleSigInt();
G_SIGINT = 0;
}
#endif
} /* End of main loop */
/* Got SIGTERM */
HandleSigTerm();
return 0;
}
#endif /*ifndef _WIN32 */