2 @file osrf_router_main.c
3 @brief top level of OSRF Router
5 This top level loads a configuration file and forks into one or more child processes.
6 Each child process configures itself, daemonizes itself, and then (via a call to
7 osrfRouterRun()) goes into an infinite loop to route messages among clients and servers.
9 The first command-line parameter is the name of the configuration file.
11 The second command-line parameter is the context -- an XML tag identifying the subset
12 of the configuration file that is relevant to this application (since a configuration
13 file may include information for multiple applications).
15 Any subsequent command-line parameters are silently ignored.
19 #include <sys/types.h>
22 #include "opensrf/utils.h"
23 #include "opensrf/log.h"
24 #include "opensrf/osrf_list.h"
25 #include "opensrf/string_array.h"
26 #include "opensrf/osrfConfig.h"
27 #include "osrf_router.h"
29 static osrfRouter* router = NULL;
31 static volatile sig_atomic_t stop_signal = 0;
33 static void setupRouter( const jsonObject* configChunk );
36 @brief Respond to signal by setting a switch that will interrupt the main loop.
37 @param signo The signal number.
39 Signal handler. We not only interrupt the main loop but also remember the signal
40 number so that we can report it later and re-raise it.
42 void routerSignalHandler( int signo ) {
44 signal( signo, routerSignalHandler );
45 router_stop( router );
50 @brief The top-level function of the router program.
51 @param argc Number of items in command line.
52 @param argv Pointer to array of items on command line.
53 @return System return code.
55 Load a configuration file, spawn zero or more child processes, and exit.
57 int main( int argc, char* argv[] ) {
60 osrfLogError( OSRF_LOG_MARK,
61 "Usage: %s <path_to_config_file> <config_context>", argv[0] );
65 const char* config_file = argv[1];
66 const char* context = argv[2];
68 /* Get a set of router definitions from a config file */
70 osrfConfig* cfg = osrfConfigInit(config_file, context);
72 osrfLogError( OSRF_LOG_MARK, "Router can't load config file %s", config_file );
76 osrfConfigSetDefaultConfig(cfg);
77 jsonObject* configInfo = osrfConfigGetValueObject(NULL, "/router");
79 if( configInfo->size < 1 || NULL == jsonObjectGetIndex( configInfo, 1 ) ) {
80 osrfLogError( OSRF_LOG_MARK, "No routers defined in config file %s, context \"%s\"",
81 config_file, context );
85 /* We're done with the command line now, so we can safely overlay it */
87 init_proc_title( argc, argv );
88 set_proc_title( "OpenSRF Router" );
90 /* Spawn child process(es) */
92 int rc = EXIT_SUCCESS;
93 int parent = 1; // boolean
95 for(i = 0; i < configInfo->size; i++) {
96 const jsonObject* configChunk = jsonObjectGetIndex( configInfo, i );
97 if( ! jsonObjectGetKeyConst( configChunk, "transport" ) )
99 // In searching the configuration file for a given context, we may have found a
100 // spurious hit on an unrelated part of the configuration file that happened to use
101 // the same XML tag. In fact this happens routinely in practice.
103 // If we don't see a member for "transport" then this is presumably such a spurious
104 // hit, so we silently ignore it.
106 // It is also possible that it's the right part of the configuration file but it has a
107 // typo or other such error, making it look spurious. In that case, well, too bad.
110 if(fork() == 0) { /* create a new child to run this router instance */
111 setupRouter(configChunk);
113 break; /* We're a child; don't spawn any more children here */
118 // Wait for all child processes to terminate; report their fates
119 while( 1 ) { // Loop until all children terminate
122 pid_t child_pid = wait( &status );
123 if( -1 == child_pid ) {
124 // ECHILD means no children are left. Anything else we ignore.
125 if( ECHILD == errno )
127 } else if( WIFEXITED( status ) ) {
128 // Relatively normal exit, i.e. via calling exit()
129 // or _exit(), or by returning from main()
130 int child_rc = WEXITSTATUS( status );
132 osrfLogWarning( OSRF_LOG_MARK,
133 "Child router process %ld exited with return status %d",
134 (long) child_pid, child_rc );
137 ; // Terminated successfully; silently ignore
139 } else if( WIFSIGNALED( status ) ) {
140 // Killed by a signal
141 int signo = WTERMSIG( status );
142 const char* extra = "";
144 if( WCOREDUMP( status ) )
145 extra = "with core dump ";
147 osrfLogWarning( OSRF_LOG_MARK, "Child router process %ld killed %sby signal %d",
148 (long) child_pid, extra, signo );
156 // Interrupted by a signal? Re-raise so the parent can see it.
157 osrfLogDebug(OSRF_LOG_MARK,
158 "Router received signal %d; re-raising", (int) stop_signal);
159 signal( stop_signal, SIG_DFL );
160 raise( stop_signal );
167 @brief Configure and run a child process.
168 @param configChunk Pointer to a subset of the loaded configuration.
170 Configure oneself, daemonize, and then call osrfRouterRun() to go into a
171 near-endless loop. Return when interrupted by a signal, or when something goes wrong.
173 static void setupRouter( const jsonObject* configChunk ) {
175 const jsonObject* transport_cfg = jsonObjectGetKeyConst( configChunk, "transport" );
177 const char* server = jsonObjectGetString( jsonObjectGetKeyConst( transport_cfg, "server" ));
178 const char* port = jsonObjectGetString( jsonObjectGetKeyConst( transport_cfg, "port" ));
179 const char* username = jsonObjectGetString( jsonObjectGetKeyConst( transport_cfg, "username" ));
180 const char* password = jsonObjectGetString( jsonObjectGetKeyConst( transport_cfg, "password" ));
181 const char* resource = jsonObjectGetString( jsonObjectGetKeyConst( transport_cfg, "resource" ));
183 const char* level = jsonObjectGetString( jsonObjectGetKeyConst( configChunk, "loglevel" ));
184 const char* log_file = jsonObjectGetString( jsonObjectGetKeyConst( configChunk, "logfile" ));
185 const char* facility = jsonObjectGetString( jsonObjectGetKeyConst( configChunk, "syslog" ));
188 if(level) llevel = atoi(level);
192 osrfLogError( OSRF_LOG_MARK, "Log file name not specified for router" );
196 if(!strcmp(log_file, "syslog")) {
197 osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "router", llevel );
198 osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
201 osrfLogInit( OSRF_LOG_TYPE_FILE, "router", llevel );
202 osrfLogSetFile( log_file );
205 osrfLogInfo( OSRF_LOG_MARK, "Router connecting as: server: %s port: %s "
206 "user: %s resource: %s", server, port, username, resource );
210 iport = atoi( port );
212 osrfStringArray* tclients = osrfNewStringArray(4);
213 osrfStringArray* tservers = osrfNewStringArray(4);
215 jsonObject* tclientsList = jsonObjectFindPath(configChunk, "/trusted_domains/client");
216 jsonObject* tserversList = jsonObjectFindPath(configChunk, "/trusted_domains/server");
220 if(tserversList->type == JSON_ARRAY) {
221 for( i = 0; i != tserversList->size; i++ ) {
222 const char* serverDomain = jsonObjectGetString(jsonObjectGetIndex(tserversList, i));
223 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
224 osrfStringArrayAdd(tservers, serverDomain);
227 const char* serverDomain = jsonObjectGetString(tserversList);
228 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
229 osrfStringArrayAdd(tservers, serverDomain);
232 if(tclientsList->type == JSON_ARRAY) {
233 for( i = 0; i != tclientsList->size; i++ ) {
234 const char* clientDomain = jsonObjectGetString(jsonObjectGetIndex(tclientsList, i));
235 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
236 osrfStringArrayAdd(tclients, clientDomain);
239 const char* clientDomain = jsonObjectGetString(tclientsList);
240 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
241 osrfStringArrayAdd(tclients, clientDomain);
245 if( tclients->size == 0 || tservers->size == 0 ) {
246 osrfLogError( OSRF_LOG_MARK,
247 "We need trusted servers and trusted client to run the router...");
248 osrfStringArrayFree( tservers );
249 osrfStringArrayFree( tclients );
253 router = osrfNewRouter( server,
254 username, resource, password, iport, tclients, tservers );
256 signal(SIGHUP,routerSignalHandler);
257 signal(SIGINT,routerSignalHandler);
258 signal(SIGTERM,routerSignalHandler);
260 if( (osrfRouterConnect(router)) != 0 ) {
261 osrfLogError( OSRF_LOG_MARK, "Unable to connect router to jabber server %s... exiting",
263 osrfRouterFree(router);
267 // Done configuring? Let's get to work.
270 osrfRouterRun( router );
272 osrfRouterFree(router);
274 osrfLogInfo( OSRF_LOG_MARK, "Router freed" );