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
6 processes. Each child process configures itself, daemonizes itself, and then (via a
7 call to osrfRouterRun()) goes into an infinite loop to route messages among clients
10 The first command-line parameter is the name of the configuration file.
12 The second command-line parameter is the context -- an XML tag identifying the subset
13 of the configuration file that is relevant to this application (since a configuration
14 file may include information for multiple applications).
16 Any subsequent command-line parameters are silently ignored.
19 #include "osrf_router.h"
20 #include <opensrf/osrfConfig.h>
21 #include <opensrf/utils.h>
22 #include <opensrf/log.h>
23 #include <opensrf/osrf_json.h>
27 An osrfRouter contains various bits and scraps that the router uses for networking.
29 static osrfRouter* router = NULL;
31 static sig_atomic_t stop_signal = 0;
33 static void setupRouter(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 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, */
86 /* so we can safely overlay it */
88 init_proc_title( argc, argv );
89 set_proc_title( "OpenSRF Router" );
91 /* Spawn child process(es) */
94 for(i = 0; i < configInfo->size; i++) {
95 jsonObject* configChunk = jsonObjectGetIndex(configInfo, i);
96 if( ! jsonObjectGetKey( configChunk, "transport" ) )
98 // In searching the configuration file for a given context, we may have found a
99 // spurious hit on an unrelated part of the configuration file that happened to use
100 // the same XML tag. In fact this happens routinely in practice.
102 // If we don't see a member for "transport" then this is presumably such a spurious
103 // hit, so we silently ignore it.
105 // It is also possible that it's the right part of the configuration file but it has a
106 // typo or other such error, making it look spurious. In that case, well, too bad.
109 if(fork() == 0) { /* create a new child to run this router instance */
110 setupRouter(configChunk);
111 break; /* We're a child; don't spawn any more children here */
116 // Interrupted by a signal? Re raise so the parent can see it.
117 osrfLogWarning( OSRF_LOG_MARK, "Interrupted by signal %d; re-raising",
119 raise( stop_signal );
126 @brief Configure and run a child process.
127 @param configChunk Pointer to a subset of the loaded configuration.
129 Configure oneself, daemonize, and then call osrfRouterRun() to go into an infinite
130 loop. Do not return unless something goes wrong.
132 static void setupRouter(jsonObject* configChunk) {
134 jsonObject* transport_cfg = jsonObjectGetKey( configChunk, "transport" );
136 const char* server = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "server" ) );
137 const char* port = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "port" ) );
138 const char* username = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "username" ) );
139 const char* password = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "password" ) );
140 const char* resource = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "resource" ) );
142 const char* level = jsonObjectGetString( jsonObjectGetKey( configChunk, "loglevel" ) );
143 const char* log_file = jsonObjectGetString( jsonObjectGetKey( configChunk, "logfile" ) );
144 const char* facility = jsonObjectGetString( jsonObjectGetKey( configChunk, "syslog" ) );
147 if(level) llevel = atoi(level);
151 fprintf(stderr, "Log file name not specified for router\n");
155 if(!strcmp(log_file, "syslog")) {
156 osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "router", llevel );
157 osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
160 osrfLogInit( OSRF_LOG_TYPE_FILE, "router", llevel );
161 osrfLogSetFile( log_file );
164 osrfLogInfo( OSRF_LOG_MARK, "Router connecting as: server: %s port: %s "
165 "user: %s resource: %s", server, port, username, resource );
168 if(port) iport = atoi( port );
170 osrfStringArray* tclients = osrfNewStringArray(4);
171 osrfStringArray* tservers = osrfNewStringArray(4);
173 jsonObject* tclientsList = jsonObjectFindPath(configChunk, "/trusted_domains/client");
174 jsonObject* tserversList = jsonObjectFindPath(configChunk, "/trusted_domains/server");
178 if(tserversList->type == JSON_ARRAY) {
179 for( i = 0; i != tserversList->size; i++ ) {
180 const char* serverDomain = jsonObjectGetString(jsonObjectGetIndex(tserversList, i));
181 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
182 osrfStringArrayAdd(tservers, serverDomain);
185 const char* serverDomain = jsonObjectGetString(tserversList);
186 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
187 osrfStringArrayAdd(tservers, serverDomain);
190 if(tclientsList->type == JSON_ARRAY) {
191 for( i = 0; i != tclientsList->size; i++ ) {
192 const char* clientDomain = jsonObjectGetString(jsonObjectGetIndex(tclientsList, i));
193 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
194 osrfStringArrayAdd(tclients, clientDomain);
197 const char* clientDomain = jsonObjectGetString(tclientsList);
198 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
199 osrfStringArrayAdd(tclients, clientDomain);
203 if( tclients->size == 0 || tservers->size == 0 ) {
204 osrfLogError( OSRF_LOG_MARK, "We need trusted servers and trusted client to run the router...");
205 osrfStringArrayFree( tservers );
206 osrfStringArrayFree( tclients );
210 router = osrfNewRouter( server,
211 username, resource, password, iport, tclients, tservers );
213 signal(SIGHUP,routerSignalHandler);
214 signal(SIGINT,routerSignalHandler);
215 signal(SIGTERM,routerSignalHandler);
217 if( (osrfRouterConnect(router)) != 0 ) {
218 fprintf(stderr, "Unable to connect router to jabber server %s... exiting\n", server );
219 osrfRouterFree(router);
224 osrfRouterRun( router );
226 // Shouldn't get here, since osrfRouterRun()
227 // should go into an infinite loop
229 osrfRouterFree(router);
232 osrfLogInfo( OSRF_LOG_MARK, "Router freed" );