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