]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/router/osrf_router_main.c
We routinely grab a chunk of configuration file that doesn't
[OpenSRF.git] / src / router / osrf_router_main.c
1 /**
2         @file osrf_router_main.c
3         @brief top level of OSRF Router
4
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
8         and servers.
9
10         The first command-line parameter is the name of the configuration file.
11         
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).
15
16         Any subsequent command-line parameters are silently ignored.
17 */
18
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>
24 #include <signal.h>
25
26 /**
27         An osrfRouter contains various bits and scraps that the router uses for networking.
28 */
29 static osrfRouter* router = NULL;
30
31 /**
32         @brief Respond to signal by exiting immediately.
33         @param signo The signal number.
34 */
35 void routerSignalHandler( int signo ) {
36         osrfLogWarning( OSRF_LOG_MARK, "Received signal [%d], cleaning up...", signo );
37
38     /* for now, just forcibly exit.  This is not a friendly way to clean up, but
39      * there is a bug in osrfRouterFree() (in particular with cleaning up sockets),
40      * that can cause the router process to stick around.  If we do this, we
41      * are guaranteed to exit.
42      */
43     _exit(0);
44
45         osrfConfigCleanup();
46         osrfRouterFree(router);
47         router = NULL;
48
49         // Exit by re-raising the signal so that the parent
50         // process can detect it
51         
52         signal( signo, SIG_DFL );
53         raise( signo );
54 }
55
56 static void setupRouter(jsonObject* configChunk);
57
58
59 /**
60         @brief The top-level function of the router program.
61         @param argc Number of items in command line.
62         @param argv Pointer to array of items on command line.
63         @return System return code.
64
65         Load configuration file, spawn zero or more child processes, and exit.
66 */
67 int main( int argc, char* argv[] ) {
68
69         if( argc < 3 ) {
70                 osrfLogError( OSRF_LOG_MARK,
71                         "Usage: %s <path_to_config_file> <config_context>", argv[0] );
72                 exit( EXIT_FAILURE );
73         }
74
75         const char* config_file = argv[1];
76         const char* context = argv[2];
77
78         /* Get a set of router definitions from a config file */
79         
80         osrfConfig* cfg = osrfConfigInit(config_file, context);
81         if( NULL == cfg ) {
82                 osrfLogError( OSRF_LOG_MARK, "Router can't load config file %s", config_file );
83                 exit( EXIT_FAILURE );
84         }
85         
86         osrfConfigSetDefaultConfig(cfg);
87     jsonObject* configInfo = osrfConfigGetValueObject(NULL, "/router");
88         
89         if( configInfo->size < 1 || NULL == jsonObjectGetIndex( configInfo, 1 ) ) {
90                 osrfLogError( OSRF_LOG_MARK, "No routers defined in config file %s, context \"%s\"",
91                         config_file, context );
92                 exit( EXIT_FAILURE );
93         }
94         
95         /* We're done with the command line now, */
96         /* so we can safely overlay it */
97         
98         init_proc_title( argc, argv );
99         set_proc_title( "OpenSRF Router" );
100
101         /* Spawn child process(es) */
102         
103     int i;
104     for(i = 0; i < configInfo->size; i++) {
105         jsonObject* configChunk = jsonObjectGetIndex(configInfo, i);
106                 if( ! jsonObjectGetKey( configChunk, "transport" ) )
107                 {
108                         // In searching the configuration file for a given context, we may have found a spurious
109                         // hit on an unrelated part of the configuration file that happened to use the same XML
110                         // tag.  In fact this happens routinely in practice.
111                         
112                         // If we don't see a member for "transport" then this is presumably such a spurious hit,
113                         // so we silently ignore it.
114                         
115                         // It is also possible that it's the right part of the configuration file but it has a
116                         // typo or other such error, making it look spurious.  In that case, well, too bad.
117                         continue;
118                 }
119         if(fork() == 0) { /* create a new child to run this router instance */
120             setupRouter(configChunk);
121                         break;  /* We're a child; don't spawn any more children here */
122                 }
123     }
124
125         return EXIT_SUCCESS;
126 }
127
128 /**
129         @brief Configure and run a child process.
130         @param configChunk Pointer to a subset of the loaded configuration.
131
132         Configure oneself, daemonize, and then call osrfRouterRun() to go into an infinite
133         loop.  Do not return unless something goes wrong.
134 */
135 static void setupRouter(jsonObject* configChunk) {
136
137         jsonObject* transport_cfg = jsonObjectGetKey( configChunk, "transport" );
138
139         const char* server   = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "server" ) );
140         const char* port     = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "port" ) );
141         const char* username = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "username" ) );
142         const char* password = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "password" ) );
143         const char* resource = jsonObjectGetString( jsonObjectGetKey( transport_cfg, "resource" ) );
144
145         const char* level    = jsonObjectGetString( jsonObjectGetKey( configChunk, "loglevel" ) );
146         const char* log_file = jsonObjectGetString( jsonObjectGetKey( configChunk, "logfile" ) );
147         const char* facility = jsonObjectGetString( jsonObjectGetKey( configChunk, "syslog" ) );
148
149         int llevel = 1;
150         if(level) llevel = atoi(level);
151
152         if(!log_file)
153         { 
154                 fprintf(stderr, "Log file name not specified for router\n");
155                 return;
156         }
157
158         if(!strcmp(log_file, "syslog")) {
159                 osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "router", llevel );
160                 osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
161
162         } else {
163                 osrfLogInit( OSRF_LOG_TYPE_FILE, "router", llevel );
164                 osrfLogSetFile( log_file );
165         }
166
167         osrfLogInfo( OSRF_LOG_MARK, "Router connecting as: server: %s port: %s "
168                 "user: %s resource: %s", server, port, username, resource );
169
170         int iport = 0;
171         if(port)        iport = atoi( port );
172
173         osrfStringArray* tclients = osrfNewStringArray(4);
174         osrfStringArray* tservers = osrfNewStringArray(4);
175
176     jsonObject* tclientsList = jsonObjectFindPath(configChunk, "/trusted_domains/client");
177     jsonObject* tserversList = jsonObjectFindPath(configChunk, "/trusted_domains/server");
178
179         int i;
180
181     if(tserversList->type == JSON_ARRAY) {
182             for( i = 0; i != tserversList->size; i++ ) {
183             const char* serverDomain = jsonObjectGetString(jsonObjectGetIndex(tserversList, i));
184                     osrfLogInfo( OSRF_LOG_MARK,  "Router adding trusted server: %s", serverDomain);
185             osrfStringArrayAdd(tservers, serverDomain);
186         }
187     } else {
188         const char* serverDomain = jsonObjectGetString(tserversList);
189         osrfLogInfo( OSRF_LOG_MARK,  "Router adding trusted server: %s", serverDomain);
190         osrfStringArrayAdd(tservers, serverDomain);
191     }
192
193     if(tclientsList->type == JSON_ARRAY) {
194             for( i = 0; i != tclientsList->size; i++ ) {
195             const char* clientDomain = jsonObjectGetString(jsonObjectGetIndex(tclientsList, i));
196                     osrfLogInfo( OSRF_LOG_MARK,  "Router adding trusted client: %s", clientDomain);
197             osrfStringArrayAdd(tclients, clientDomain);
198         }
199     } else {
200         const char* clientDomain = jsonObjectGetString(tclientsList);
201         osrfLogInfo( OSRF_LOG_MARK,  "Router adding trusted client: %s", clientDomain);
202         osrfStringArrayAdd(tclients, clientDomain);
203     }
204
205
206         if( tclients->size == 0 || tservers->size == 0 ) {
207                 osrfLogError( OSRF_LOG_MARK, "We need trusted servers and trusted client to run the router...");
208                 osrfStringArrayFree( tservers );
209                 osrfStringArrayFree( tclients );
210                 return;
211         }
212
213         router = osrfNewRouter( server,
214                         username, resource, password, iport, tclients, tservers );
215         
216         signal(SIGHUP,routerSignalHandler);
217         signal(SIGINT,routerSignalHandler);
218         signal(SIGTERM,routerSignalHandler);
219
220         if( (osrfRouterConnect(router)) != 0 ) {
221                 fprintf(stderr, "Unable to connect router to jabber server %s... exiting\n", server );
222                 osrfRouterFree(router);
223                 return;
224         }
225
226         daemonize();
227         osrfRouterRun( router );
228
229         // Shouldn't get here, since osrfRouterRun()
230         // should go into an infinite loop
231
232         osrfRouterFree(router);
233         router = NULL;
234
235         return;
236 }
237
238