main.c 10.2 KB
Newer Older
Sebastien Decugis's avatar
Sebastien Decugis committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2009, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

36
#include "fD.h"
Sebastien Decugis's avatar
Sebastien Decugis committed
37

Sebastien Decugis's avatar
Sebastien Decugis committed
38
39
#include <signal.h>
#include <getopt.h>
Sebastien Decugis's avatar
Sebastien Decugis committed
40
#include <locale.h>
41
#include <gcrypt.h>
Sebastien Decugis's avatar
Sebastien Decugis committed
42

43
44
45
/* forward declarations */
static void * sig_hdl(void * arg);
static int main_cmdline(int argc, char *argv[]);
46
47
static void main_version(void);
static void main_help( void );
48
49
50
51
52

/* The static configuration structure */
static struct fd_config conf;
struct fd_config * fd_g_config = &conf;

Sebastien Decugis's avatar
Sebastien Decugis committed
53
54
GCRY_THREAD_OPTION_PTHREAD_IMPL;

55
56
57
58
59
60
61
62
63
64
65
66
67
/* freeDiameter starting point */
int main(int argc, char * argv[])
{
	int ret;
	pthread_t sig_th;
	sigset_t sig_all;
	
	memset(fd_g_config, 0, sizeof(struct fd_config));
	sigfillset(&sig_all);
	CHECK_POSIX(  pthread_sigmask(SIG_BLOCK, &sig_all, NULL)  );
	
	/* Initialize the library */
	CHECK_FCT( fd_lib_init() );
Sebastien Decugis's avatar
Sebastien Decugis committed
68
	TRACE_DEBUG(INFO, "libfreeDiameter initialized.");
69
70
71
72
73
74
75
76
77
78
	
	/* Name this thread */
	fd_log_threadname("Main");
	
	/* Initialize the config */
	CHECK_FCT( fd_conf_init() );

	/* Parse the command-line */
	CHECK_FCT(  main_cmdline(argc, argv)  );
	
Sebastien Decugis's avatar
Sebastien Decugis committed
79
	/* Initialize gcrypt and gnutls */
80
	(void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
Sebastien Decugis's avatar
Sebastien Decugis committed
81
	(void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
Sebastien Decugis's avatar
Sebastien Decugis committed
82
83
84
85
86
87
88
89
	CHECK_GNUTLS_DO( gnutls_global_init(), return EINVAL );
	if ( ! gnutls_check_version(GNUTLS_VERSION) ) {
		fprintf(stderr, "The GNUTLS library is too old; found '%s', need '" GNUTLS_VERSION "'\n", gnutls_check_version(NULL));
		return EINVAL;
	} else {
		TRACE_DEBUG(INFO, "GNUTLS library '%s' initialized.", gnutls_check_version(NULL));
	}
	
90
91
92
93
94
95
96
97
98
	/* Allow SIGINT and SIGTERM from this point */
	CHECK_POSIX(  pthread_create(&sig_th, NULL, sig_hdl, NULL)  );
	
	/* Add definitions of the base protocol */
	CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) );
	
	/* Initialize other modules */
	CHECK_FCT(  fd_queues_init()  );
	CHECK_FCT(  fd_msg_init()  );
99
	CHECK_FCT(  fd_p_expi_init()  );
100
101
102
103
104
105
106
107
	
	/* Parse the configuration file */
	CHECK_FCT( fd_conf_parse() );
	
	/* Load the dynamic extensions */
	CHECK_FCT(  fd_ext_load()  );
	
	/* Start the peer state machines */
108
	CHECK_FCT( fd_psm_start() );
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
	
	/* Now, just wait for events */
	TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
	fd_conf_dump();
	while (1) {
		int code;
		CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, NULL),  break  );
		switch (code) {
			case FDEV_DUMP_DICT:
				fd_dict_dump(fd_g_config->cnf_dict);
				break;
			
			case FDEV_DUMP_EXT:
				fd_ext_dump();
				break;
			
125
126
127
128
			case FDEV_DUMP_SERV:
				fd_servers_dump();
				break;
			
129
130
131
132
133
134
135
136
137
138
			case FDEV_DUMP_QUEUES:
				fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk);
				fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk);
				fd_fifo_dump(0, "Local messages",    fd_g_local,    fd_msg_dump_walk);
				break;
			
			case FDEV_DUMP_CONFIG:
				fd_conf_dump();
				break;
			
139
			case FDEV_DUMP_PEERS:
140
				fd_peer_dump_list(FULL);
141
				break;
142
143
144
145
146
147
148
149
150
151
152
153
154
155
			
			case FDEV_TERMINATE:
				ret = 0;
				goto end;
			
			default:
				TRACE_DEBUG(INFO, "Unexpected event in the daemon (%d), ignored.\n", code);
		}
	}
	
end:
	TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon is stopping...");
	
	/* cleanups */
156
157
158
159
160
161
	TODO("Stop dispatch thread(s) properly (no cancel yet)");
	CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
	TODO("Stop dispatch & routing threads");
	CHECK_FCT_DO( fd_ext_fini(), /* Cleaup all extensions */ );
	TODO("Cleanup queues (dump all remaining messages ?)");
	
162
163
	CHECK_FCT_DO( fd_thr_term(&sig_th), /* continue */ );
	
Sebastien Decugis's avatar
Sebastien Decugis committed
164
165
	gnutls_global_deinit();
	
166
167
	return ret;
}
Sebastien Decugis's avatar
Sebastien Decugis committed
168

169
const char * fd_ev_str(int event)
Sebastien Decugis's avatar
Sebastien Decugis committed
170
{
171
172
173
174
175
176
	switch (event) {
	#define case_str( _val )\
		case _val : return #_val
		case_str(FDEV_TERMINATE);
		case_str(FDEV_DUMP_DICT);
		case_str(FDEV_DUMP_EXT);
177
		case_str(FDEV_DUMP_SERV);
178
179
180
181
182
183
184
185
		case_str(FDEV_DUMP_QUEUES);
		case_str(FDEV_DUMP_CONFIG);
		case_str(FDEV_DUMP_PEERS);
		
		default:
			TRACE_DEBUG(FULL, "Unknown event : %d", event);
			return "Unknown event";
	}
Sebastien Decugis's avatar
Sebastien Decugis committed
186
187
188
189
190
191
192
}

/* Parse the command-line */
static int main_cmdline(int argc, char *argv[])
{
	int c;
	int option_index = 0;
Sebastien Decugis's avatar
Sebastien Decugis committed
193
	char * locale;
Sebastien Decugis's avatar
Sebastien Decugis committed
194
195
	
      	struct option long_options[] = {
Sebastien Decugis's avatar
Sebastien Decugis committed
196
197
198
199
200
201
202
		{ "help",	no_argument, 		NULL, 'h' },
		{ "version",	no_argument, 		NULL, 'V' },
		{ "config",	required_argument, 	NULL, 'c' },
		{ "debug",	no_argument, 		NULL, 'd' },
		{ "quiet",	no_argument, 		NULL, 'q' },
		{ "dbglocale",	optional_argument, 	NULL, 'l' },
		{ NULL,		0, 			NULL, 0 }
Sebastien Decugis's avatar
Sebastien Decugis committed
203
204
205
206
207
208
	};
	
	TRACE_ENTRY("%d %p", argc, argv);
	
	/* Loop on arguments */
	while (1) {
Sebastien Decugis's avatar
Sebastien Decugis committed
209
		c = getopt_long (argc, argv, "hVc:dql:", long_options, &option_index);
Sebastien Decugis's avatar
Sebastien Decugis committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
		if (c == -1) 
			break;	/* Exit from the loop.  */
		
		switch (c) {
			case 'h':	/* Print help and exit.  */
				main_help();
				exit(0);

			case 'V':	/* Print version and exit.  */
				main_version();
				exit(0);

			case 'c':	/* Read configuration from this file instead of the default location..  */
				CHECK_PARAMS( optarg );
224
				fd_g_config->cnf_file = optarg;
Sebastien Decugis's avatar
Sebastien Decugis committed
225
226
				break;

Sebastien Decugis's avatar
Sebastien Decugis committed
227
228
229
230
231
232
233
234
235
236
			case 'l':	/* Change the locale.  */
				locale = setlocale(LC_ALL, optarg?:"");
				if (locale) {
					TRACE_DEBUG(INFO, "Locale set to: %s", optarg ?: locale);
				} else {
					TRACE_DEBUG(INFO, "Unable to set locale (%s)", optarg);
					return EINVAL;
				}
				break;

Sebastien Decugis's avatar
Sebastien Decugis committed
237
238
239
240
241
242
243
244
245
246
			case 'd':	/* Increase verbosity of debug messages.  */
				fd_g_debug_lvl++;
				break;
				
			case 'q':	/* Decrease verbosity then remove debug messages.  */
				fd_g_debug_lvl--;
				break;

			case '?':	/* Invalid option.  */
				/* `getopt_long' already printed an error message.  */
Sebastien Decugis's avatar
Sebastien Decugis committed
247
				TRACE_DEBUG(INFO, "getopt_long found an invalid character");
Sebastien Decugis's avatar
Sebastien Decugis committed
248
249
250
				return EINVAL;

			default:	/* bug: option not considered.  */
Sebastien Decugis's avatar
Sebastien Decugis committed
251
				TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c", c);
Sebastien Decugis's avatar
Sebastien Decugis committed
252
253
254
255
256
257
				ASSERT(0);
				return EINVAL;
		}
	}
		
	return 0;
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
}

/* Display package version */
static void main_version_core(void)
{
	printf("%s, version %d.%d.%d"
#ifdef HG_VERSION
		" (r%s"
# ifdef PACKAGE_HG_REVISION
		"/%s"
# endif /* PACKAGE_HG_VERSION */
		")"
#endif /* HG_VERSION */
		"\n", 
		FD_PROJECT_NAME, FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, FD_PROJECT_VERSION_REV
#ifdef HG_VERSION
		, HG_VERSION
# ifdef PACKAGE_HG_REVISION
		, PACKAGE_HG_REVISION
# endif /* PACKAGE_HG_VERSION */
#endif /* HG_VERSION */
		);
}

/* Display package version and general info */
static void main_version(void)
{
	main_version_core();
	printf( "%s\n", FD_PROJECT_COPYRIGHT);
	printf( "\nSee " FD_PROJECT_NAME " homepage at http://aaa.koganei.wide.ad.jp/\n"
		" for information, updates and bug reports on this software.\n");
}

/* Print command-line options */
static void main_help( void )
{
	main_version_core();
	printf(	"  This daemon is an implementation of the Diameter protocol\n"
		"  used for Authentication, Authorization, and Accounting (AAA).\n");
	printf("\nUsage:  " FD_PROJECT_BINARY " [OPTIONS]...\n");
	printf( "  -h, --help             Print help and exit\n"
  		"  -V, --version          Print version and exit\n"
  		"  -c, --config=filename  Read configuration from this file instead of the \n"
		"                           default location (%s).\n", DEFAULT_CONF_FILE);
 	printf( "\nDebug:\n"
  		"  These options are mostly useful for developers\n"
Sebastien Decugis's avatar
Sebastien Decugis committed
304
  		"  -l, --dbglocale        Set the locale for error messages\n"
305
306
  		"  -d, --debug            Increase verbosity of debug messages\n"
  		"  -q, --quiet            Decrease verbosity then remove debug messages\n");
Sebastien Decugis's avatar
Sebastien Decugis committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
}

#ifdef HAVE_SIGNALENT_H
const char *const signalstr[] = {
# include "signalent.h"
};
const int nsignalstr = sizeof signalstr / sizeof signalstr[0];
# define SIGNALSTR(sig) (((sig) < nsignalstr) ? signalstr[(sig)] : "unknown")
#else /* HAVE_SIGNALENT_H */
# define SIGNALSTR(sig) ("")
#endif /* HAVE_SIGNALENT_H */

/* signal handler */
static void * sig_hdl(void * arg)
{
	sigset_t sig_main;
	int sig = 0;
	
	TRACE_ENTRY();
	fd_log_threadname("Main signal handler");
	
	sigemptyset(&sig_main);
	sigaddset(&sig_main, SIGINT);
	sigaddset(&sig_main, SIGTERM);
	
	CHECK_SYS_DO(  sigwait(&sig_main, &sig), TRACE_DEBUG(INFO, "Error in sigwait function") );
	
	TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig);
335
	CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );
Sebastien Decugis's avatar
Sebastien Decugis committed
336
337
338
	return NULL;
}