Initial revision
[OpenSRF.git] / src / libtransport / generic_utils.c
1 #include "generic_utils.h"
2 #include <stdio.h>
3 #include "pthread.h"
4
5 int _init_log();
6
7 int balance = 0;
8
9 #define LOG_ERROR 1
10 #define LOG_WARNING 2
11 #define LOG_INFO 3
12
13 void get_timestamp( char buf_25chars[]) {
14         time_t epoch = time(NULL);      
15         char* localtime = strdup( ctime( &epoch ) );
16         strcpy( buf_25chars, localtime );
17         buf_25chars[ strlen(localtime)-1] = '\0'; // remove newline
18         free(localtime);
19 }
20
21
22 inline void* safe_malloc( int size ) {
23         void* ptr = (void*) malloc( size );
24         if( ptr == NULL ) 
25                 fatal_handler("safe_malloc(): Out of Memory" );
26         memset( ptr, 0, size );
27         return ptr;
28 }
29
30 // ---------------------------------------------------------------------------------
31 // Here we define how we want to handle various error levels.
32 // ---------------------------------------------------------------------------------
33
34
35 static FILE* log_file = NULL;
36 static int log_level = -1;
37 pthread_mutex_t mutex;
38
39 void log_free() { if( log_file != NULL ) fclose(log_file ); }
40
41 void fatal_handler( char* msg, ... ) {
42                 
43         char buf[25];
44         memset( buf, 0, 25 );
45         get_timestamp( buf );
46         pid_t  pid = getpid();
47         va_list args;
48
49         if( _init_log() ) {
50
51                 if( log_level < LOG_ERROR )
52                         return;
53
54                 pthread_mutex_lock( &(mutex) );
55                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "ERR " );
56         
57                 va_start(args, msg);
58                 vfprintf(log_file, msg, args);
59                 va_end(args);
60         
61                 fprintf(log_file, "\n");
62                 fflush( log_file );
63                 pthread_mutex_unlock( &(mutex) );
64
65         }
66         
67         /* also log to stderr  for ERRORS*/
68         fprintf( stderr, "[%s %d] [%s] ", buf, pid, "ERR " );
69         va_start(args, msg);
70         vfprintf(stderr, msg, args);
71         va_end(args);
72         fprintf( stderr, "\n" );
73
74         exit(99);
75 }
76
77 void warning_handler( char* msg, ... ) {
78
79         char buf[25];
80         memset( buf, 0, 25 );
81         get_timestamp( buf );
82         pid_t  pid = getpid();
83         va_list args;
84         
85         if( _init_log() ) {
86
87                 if( log_level < LOG_WARNING )
88                         return;
89
90                 pthread_mutex_lock( &(mutex) );
91                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "WARN" );
92         
93                 va_start(args, msg);
94                 vfprintf(log_file, msg, args);
95                 va_end(args);
96         
97                 fprintf(log_file, "\n");
98                 fflush( log_file );
99                 pthread_mutex_unlock( &(mutex) );
100
101         } else {
102
103                 fprintf( stderr, "[%s %d] [%s] ", buf, pid, "WARN" );
104                 va_start(args, msg);
105                 vfprintf(stderr, msg, args);
106                 va_end(args);
107                 fprintf( stderr, "\n" );
108         }
109
110 }
111
112 void info_handler( char* msg, ... ) {
113
114         char buf[25];
115         memset( buf, 0, 25 );
116         get_timestamp( buf );
117         pid_t  pid = getpid();
118         va_list args;
119
120         if( _init_log() ) {
121
122                 if( log_level < LOG_INFO )
123                         return;
124                 pthread_mutex_lock( &(mutex) );
125                 fprintf( log_file, "[%s %d] [%s] ", buf, pid, "INFO" );
126
127                 va_start(args, msg);
128                 vfprintf(log_file, msg, args);
129                 va_end(args);
130         
131                 fprintf(log_file, "\n");
132                 fflush( log_file );
133                 pthread_mutex_unlock( &(mutex) );
134
135         } else {
136
137                 fprintf( stderr, "[%s %d] [%s] ", buf, pid, "INFO" );
138                 va_start(args, msg);
139                 vfprintf(stderr, msg, args);
140                 va_end(args);
141                 fprintf( stderr, "\n" );
142                 fflush(stderr);
143
144         }
145 }
146
147
148 int _init_log() {
149
150         if( log_level != -1 )
151                 return 1;
152
153
154         pthread_mutex_init( &(mutex), NULL );
155
156         /* load the log level setting if we haven't already */
157
158         if( conf_reader == NULL ) {
159                 return 0;
160                 //fprintf( stderr, "No config file specified" );
161         }
162
163         char* log_level_str = config_value( "//router/log/level");
164         if( log_level_str == NULL ) {
165         //      fprintf( stderr, "No log level specified" );
166                 return 0;
167         }
168         log_level = atoi(log_level_str);
169         free(log_level_str);
170
171         /* see if we have a log file yet */
172         char* f = config_value("//router/log/file");
173
174         if( f == NULL ) {
175                 // fprintf( stderr, "No log file specified" );
176                 return 0;
177         }
178
179         log_file = fopen( f, "a" );
180         if( log_file == NULL ) {
181                 fprintf( stderr, "Unable to open log file %s for appending\n", f );
182                 return 0;
183         }
184         free(f);
185         return 1;
186                                 
187 }
188
189
190
191 // ---------------------------------------------------------------------------------
192 // Flesh out a ubiqitous growing string buffer
193 // ---------------------------------------------------------------------------------
194
195 growing_buffer* buffer_init(int num_initial_bytes) {
196
197         if( num_initial_bytes > BUFFER_MAX_SIZE ) {
198                 return NULL;
199         }
200
201
202         size_t len = sizeof(growing_buffer);
203
204         growing_buffer* gb = (growing_buffer*) safe_malloc(len);
205
206         gb->n_used = 0;/* nothing stored so far */
207         gb->size = num_initial_bytes;
208         gb->buf = (char *) safe_malloc(gb->size + 1);
209
210         return gb;
211 }
212
213 int buffer_add(growing_buffer* gb, char* data) {
214
215
216         if( ! gb || ! data  ) { return 0; }
217         int data_len = strlen( data );
218
219         if( data_len == 0 ) { return 0; }
220         int total_len = data_len + gb->n_used;
221
222         while( total_len >= gb->size ) {
223                 gb->size *= 2;
224         }
225
226         if( gb->size > BUFFER_MAX_SIZE ) {
227                 warning_handler( "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE );
228                 buffer_free( gb );
229                 return 0;
230         }
231
232         char* new_data = (char*) safe_malloc( gb->size );
233
234         strcpy( new_data, gb->buf );
235         free( gb->buf );
236         gb->buf = new_data;
237
238         strcat( gb->buf, data );
239         gb->n_used = total_len;
240         return total_len;
241 }
242
243
244 int buffer_reset( growing_buffer *gb){
245         if( gb == NULL ) { return 0; }
246         if( gb->buf == NULL ) { return 0; }
247         memset( gb->buf, 0, gb->size );
248         gb->n_used = 0;
249         return 1;
250 }
251
252 int buffer_free( growing_buffer* gb ) {
253         if( gb == NULL ) 
254                 return 0;
255         free( gb->buf );
256         free( gb );
257         return 1;
258 }
259
260 char* buffer_data( growing_buffer *gb) {
261         return strdup( gb->buf );
262 }
263
264
265
266
267
268 // ---------------------------------------------------------------------------------
269 // Config module
270 // ---------------------------------------------------------------------------------
271
272
273 // ---------------------------------------------------------------------------------
274 // Allocate and build the conf_reader.  This only has to happen once in a given
275 // system.  Repeated calls are ignored.
276 // ---------------------------------------------------------------------------------
277 void config_reader_init( char* config_file ) {
278         if( conf_reader == NULL ) {
279
280                 if( config_file == NULL || strlen(config_file) == 0 ) {
281                         fatal_handler( "config_reader_init(): No config file specified" );
282                         return;
283                 }
284
285                 size_t len = sizeof( config_reader );
286                 conf_reader = (config_reader*) safe_malloc( len );
287
288                 conf_reader->config_doc = xmlParseFile( config_file ); 
289                 conf_reader->xpathCx = xmlXPathNewContext( conf_reader->config_doc );
290                 if( conf_reader->xpathCx == NULL ) {
291                         fatal_handler( "config_reader_init(): Unable to create xpath context");
292                         return;
293                 }
294         }
295 }
296
297 char* config_value( const char* xp_query, ... ) {
298
299         if( conf_reader == NULL || xp_query == NULL ) {
300                 fatal_handler( "config_value(): NULL param(s)" );
301                 return NULL;
302         }
303
304         int slen = strlen(xp_query) + 512;/* this is unsafe ... */
305         char xpath_query[ slen ]; 
306         memset( xpath_query, 0, slen );
307         va_list va_args;
308         va_start(va_args, xp_query);
309         vsprintf(xpath_query, xp_query, va_args);
310         va_end(va_args);
311
312
313         char* val;
314         int len = strlen(xpath_query) + 100;
315         char alert_buffer[len];
316         memset( alert_buffer, 0, len );
317
318         // build the xpath object
319         xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST xpath_query, conf_reader->xpathCx );
320
321         if( xpathObj == NULL ) {
322                 sprintf( alert_buffer, "Could not build xpath object: %s", xpath_query );
323                 fatal_handler( alert_buffer );
324                 return NULL;
325         }
326
327
328         if( xpathObj->type == XPATH_NODESET ) {
329
330                 // ----------------------------------------------------------------------------
331                 // Grab nodeset from xpath query, then first node, then first text node and 
332                 // finaly the text node's value
333                 // ----------------------------------------------------------------------------
334                 xmlNodeSet* node_list = xpathObj->nodesetval;
335                 if( node_list == NULL ) {
336                         sprintf( alert_buffer, "Could not build xpath object: %s", xpath_query );
337                         warning_handler(alert_buffer);
338                         return NULL;
339                 }
340
341                 if( node_list->nodeNr == 0 ) {
342                         sprintf( alert_buffer, "Config XPATH query  returned 0 results: %s", xpath_query );
343                         warning_handler(alert_buffer);
344                         return NULL;
345                 }
346
347
348                 xmlNodePtr element_node = *(node_list)->nodeTab;
349                 if( element_node == NULL ) {
350                         sprintf( alert_buffer, "Config XPATH query  returned 0 results: %s", xpath_query );
351                         warning_handler(alert_buffer);
352                         return NULL;
353                 }
354
355                 xmlNodePtr text_node = element_node->children;
356                 if( text_node == NULL ) {
357                         sprintf( alert_buffer, "Config variable has no value: %s", xpath_query );
358                         warning_handler(alert_buffer);
359                         return NULL;
360                 }
361
362                 val = text_node->content;
363                 if( val == NULL ) {
364                         sprintf( alert_buffer, "Config variable has no value: %s", xpath_query );
365                         warning_handler(alert_buffer);
366                         return NULL;
367                 }
368
369
370         } else { 
371                 sprintf( alert_buffer, "Xpath evaluation failed: %s", xpath_query );
372                 warning_handler(alert_buffer);
373                 return NULL;
374         }
375
376         char* value = strdup(val);
377         if( value == NULL ) { fatal_handler( "config_value(): Out of Memory!" ); }
378
379         // Free XPATH structures
380         if( xpathObj != NULL ) xmlXPathFreeObject( xpathObj );
381
382         return value;
383 }
384
385
386 void config_reader_free() {
387         if( conf_reader == NULL ) { return; }
388         xmlXPathFreeContext( conf_reader->xpathCx );
389         xmlFreeDoc( conf_reader->config_doc );
390         free( conf_reader );
391         conf_reader = NULL;
392 }