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 "opensrf/utils.h"
20 #include "opensrf/log.h"
21 #include "opensrf/osrf_list.h"
22 #include "opensrf/string_array.h"
23 #include "opensrf/osrfConfig.h"
24 #include "osrf_router.h"
26 static osrfRouter* router = NULL;
28 static sig_atomic_t stop_signal = 0;
30 static void setupRouter(jsonObject* configChunk);
33 @brief Respond to signal by setting a switch that will interrupt the main loop.
34 @param signo The signal number.
36 Signal handler. We not only interrupt the main loop but also remember the signal
37 number so that we can report it later and re-raise it.
39 void routerSignalHandler( int signo ) {
41 signal( signo, routerSignalHandler );
42 router_stop( router );
47 @brief The top-level function of the router program.
48 @param argc Number of items in command line.
49 @param argv Pointer to array of items on command line.
50 @return System return code.
52 Load a configuration file, spawn zero or more child processes, and exit.
54 int main( int argc, char* argv[] ) {
57 osrfLogError( OSRF_LOG_MARK,
58 "Usage: %s <path_to_config_file> <config_context>", argv[0] );
62 const char* config_file = argv[1];
63 const char* context = argv[2];
65 /* Get a set of router definitions from a config file */
67 osrfConfig* cfg = osrfConfigInit(config_file, context);
69 osrfLogError( OSRF_LOG_MARK, "Router can't load config file %s", config_file );
73 osrfConfigSetDefaultConfig(cfg);
74 jsonObject* configInfo = osrfConfigGetValueObject(NULL, "/router");
76 if( configInfo->size < 1 || NULL == jsonObjectGetIndex( configInfo, 1 ) ) {
77 osrfLogError( OSRF_LOG_MARK, "No routers defined in config file %s, context \"%s\"",
78 config_file, context );
82 /* We're done with the command line now, so we can safely overlay it */
84 init_proc_title( argc, argv );
85 set_proc_title( "OpenSRF Router" );
87 /* Spawn child process(es) */
90 for(i = 0; i < configInfo->size; i++) {
91 jsonObject* configChunk = jsonObjectGetIndex(configInfo, i);
92 if( ! jsonObjectGetKey( configChunk, "transport" ) )
94 // In searching the configuration file for a given context, we may have found a
95 // spurious hit on an unrelated part of the configuration file that happened to use
96 // the same XML tag. In fact this happens routinely in practice.
98 // If we don't see a member for "transport" then this is presumably such a spurious
99 // hit, so we silently ignore it.
101 // It is also possible that it's the right part of the configuration file but it has a
102 // typo or other such error, making it look spurious. In that case, well, too bad.
105 if(fork() == 0) { /* create a new child to run this router instance */
106 setupRouter(configChunk);
107 break; /* We're a child; don't spawn any more children here */
112 // Interrupted by a signal? Re raise so the parent can see it.
113 osrfLogWarning( OSRF_LOG_MARK, "Interrupted by signal %d; re-raising",
115 raise( stop_signal );
122 @brief Configure and run a child process.
123 @param configChunk Pointer to a subset of the loaded configuration.
125 Configure oneself, daemonize, and then call osrfRouterRun() to go into a
126 near-endless loop. Return when interrupted by a signal, or when something goes wrong.
128 static void setupRouter(jsonObject* configChunk) {
130 jsonObject* transport_cfg = jsonObjectGetKey( configChunk, "transport" );
132 const char* server = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "server" ) );
133 const char* port = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "port" ) );
134 const char* username = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "username" ) );
135 const char* password = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "password" ) );
136 const char* resource = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "resource" ) );
138 const char* level = jsonObjectGetString( jsonObjectGetKey( configChunk, "loglevel" ) );
139 const char* log_file = jsonObjectGetString( jsonObjectGetKey( configChunk, "logfile" ) );
140 const char* facility = jsonObjectGetString( jsonObjectGetKey( configChunk, "syslog" ) );
143 if(level) llevel = atoi(level);
147 fprintf(stderr, "Log file name not specified for router\n");
151 if(!strcmp(log_file, "syslog")) {
152 osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "router", llevel );
153 osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
156 osrfLogInit( OSRF_LOG_TYPE_FILE, "router", llevel );
157 osrfLogSetFile( log_file );
160 osrfLogInfo( OSRF_LOG_MARK, "Router connecting as: server: %s port: %s "
161 "user: %s resource: %s", server, port, username, resource );
165 iport = atoi( port );
167 osrfStringArray* tclients = osrfNewStringArray(4);
168 osrfStringArray* tservers = osrfNewStringArray(4);
170 jsonObject* tclientsList = jsonObjectFindPath(configChunk, "/trusted_domains/client");
171 jsonObject* tserversList = jsonObjectFindPath(configChunk, "/trusted_domains/server");
175 if(tserversList->type == JSON_ARRAY) {
176 for( i = 0; i != tserversList->size; i++ ) {
177 const char* serverDomain = jsonObjectGetString(jsonObjectGetIndex(tserversList, i));
178 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
179 osrfStringArrayAdd(tservers, serverDomain);
182 const char* serverDomain = jsonObjectGetString(tserversList);
183 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted server: %s", serverDomain);
184 osrfStringArrayAdd(tservers, serverDomain);
187 if(tclientsList->type == JSON_ARRAY) {
188 for( i = 0; i != tclientsList->size; i++ ) {
189 const char* clientDomain = jsonObjectGetString(jsonObjectGetIndex(tclientsList, i));
190 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
191 osrfStringArrayAdd(tclients, clientDomain);
194 const char* clientDomain = jsonObjectGetString(tclientsList);
195 osrfLogInfo( OSRF_LOG_MARK, "Router adding trusted client: %s", clientDomain);
196 osrfStringArrayAdd(tclients, clientDomain);
200 if( tclients->size == 0 || tservers->size == 0 ) {
201 osrfLogError( OSRF_LOG_MARK,
202 "We need trusted servers and trusted client to run the router...");
203 osrfStringArrayFree( tservers );
204 osrfStringArrayFree( tclients );
208 router = osrfNewRouter( server,
209 username, resource, password, iport, tclients, tservers );
211 signal(SIGHUP,routerSignalHandler);
212 signal(SIGINT,routerSignalHandler);
213 signal(SIGTERM,routerSignalHandler);
215 if( (osrfRouterConnect(router)) != 0 ) {
216 fprintf(stderr, "Unable to connect router to jabber server %s... exiting\n", server );
217 osrfRouterFree(router);
221 // Done configuring? Let's get to work.
224 osrfRouterRun( router );
226 osrfRouterFree(router);
228 osrfLogInfo( OSRF_LOG_MARK, "Router freed" );