123 lines
3.7 KiB
C++
123 lines
3.7 KiB
C++
/// \file server_setup.cpp
|
|
/// Contains generic functions for setting up a DDVTECH Connector.
|
|
|
|
#ifndef MAINHANDLER
|
|
/// Handler that is called for accepted incoming connections.
|
|
#define MAINHANDLER NoHandler
|
|
#error "No handler was set!"
|
|
#endif
|
|
|
|
|
|
#ifndef DEFAULT_PORT
|
|
/// Default port for this server.
|
|
#define DEFAULT_PORT 0
|
|
#error "No default port was set!"
|
|
#endif
|
|
|
|
|
|
#ifndef CONFIGSECT
|
|
/// Configuration file section for this server.
|
|
#define CONFIGSECT None
|
|
#error "No configuration file section was set!"
|
|
#endif
|
|
|
|
#include "socket.h" //Socket library
|
|
#include "util.h" //utilities for process spawning and config management
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <pwd.h>
|
|
#include <fstream>
|
|
Socket::Server server_socket; ///< Placeholder for the server socket
|
|
|
|
/// Basic signal handler. Disconnects the server_socket if it receives
|
|
/// a SIGINT, SIGHUP or SIGTERM signal, but does nothing for SIGPIPE.
|
|
/// Disconnecting the server_socket will terminate the main listening loop
|
|
/// and cleanly shut down the process.
|
|
void signal_handler (int signum){
|
|
switch (signum){
|
|
case SIGINT:
|
|
#if DEBUG >= 1
|
|
fprintf(stderr, "Received SIGINT - closing server socket.\n");
|
|
#endif
|
|
break;
|
|
case SIGHUP:
|
|
#if DEBUG >= 1
|
|
fprintf(stderr, "Received SIGHUP - closing server socket.\n");
|
|
#endif
|
|
break;
|
|
case SIGTERM:
|
|
#if DEBUG >= 1
|
|
fprintf(stderr, "Received SIGTERM - closing server socket.\n");
|
|
#endif
|
|
break;
|
|
case SIGCHLD:
|
|
wait(0);
|
|
return;
|
|
break;
|
|
default: return; break;
|
|
}
|
|
if (!server_socket.connected()) return;
|
|
server_socket.close();
|
|
}//signal_handler
|
|
|
|
/// Generic main entry point and loop for DDV Connectors.
|
|
/// This sets up the proper termination handler, checks commandline options,
|
|
/// parses config files and opens a listening socket on the requested port.
|
|
/// Any incoming connections will be accepted and start up the function #MAINHANDLER,
|
|
/// which should be defined before including server_setup.cpp.
|
|
/// The default port is set by define #DEFAULT_PORT.
|
|
/// The configuration file section is set by define #CONFIGSECT.
|
|
int main(int argc, char ** argv){
|
|
Socket::Connection S;//placeholder for incoming connections
|
|
|
|
//setup signal handler
|
|
struct sigaction new_action;
|
|
new_action.sa_handler = signal_handler;
|
|
sigemptyset (&new_action.sa_mask);
|
|
new_action.sa_flags = 0;
|
|
sigaction(SIGINT, &new_action, NULL);
|
|
sigaction(SIGHUP, &new_action, NULL);
|
|
sigaction(SIGTERM, &new_action, NULL);
|
|
sigaction(SIGPIPE, &new_action, NULL);
|
|
sigaction(SIGCHLD, &new_action, NULL);
|
|
|
|
//set and parse configuration
|
|
Util::Config C;
|
|
C.confsection = TOSTRING(CONFIGSECT);
|
|
C.listen_port = DEFAULT_PORT;
|
|
C.parseArgs(argc, argv);
|
|
C.parseFile();
|
|
|
|
//setup a new server socket, for the correct interface and port
|
|
server_socket = Socket::Server(C.listen_port, C.interface);
|
|
#if DEBUG >= 3
|
|
fprintf(stderr, "Made a listening socket on %s:%i...\n", C.interface.c_str(), C.listen_port);
|
|
#endif
|
|
if (!server_socket.connected()){
|
|
#if DEBUG >= 1
|
|
fprintf(stderr, "Error: could not make listening socket\n");
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
Util::setUser(C.username);
|
|
if (C.daemon_mode){Util::Daemonize();}
|
|
|
|
while (server_socket.connected()){
|
|
S = server_socket.accept();
|
|
if (S.connected()){//check if the new connection is valid
|
|
pid_t myid = fork();
|
|
if (myid == 0){//if new child, start MAINHANDLER
|
|
return MAINHANDLER(S);
|
|
}else{//otherwise, do nothing or output debugging text
|
|
#if DEBUG >= 3
|
|
fprintf(stderr, "Spawned new process %i for socket %i\n", (int)myid, S.getSocket());
|
|
#endif
|
|
}
|
|
}
|
|
}//while connected
|
|
#if DEBUG >= 1
|
|
fprintf(stderr, "Server socket closed, exiting.\n");
|
|
#endif
|
|
return 0;
|
|
}//main
|