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