main.c 10.5 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
/* forward declarations */
44
static void fd_shutdown(int signal);
45
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
/* gcrypt functions to support posix threads */
Sebastien Decugis's avatar
Sebastien Decugis committed
54
55
GCRY_THREAD_OPTION_PTHREAD_IMPL;

56
57
58
59
60
61
/* freeDiameter starting point */
int main(int argc, char * argv[])
{
	int ret;
	
	memset(fd_g_config, 0, sizeof(struct fd_config));
62
	
63
	/* Initialize the library -- must come first since it initializes the debug facility */
64
	CHECK_FCT( fd_lib_init(1) );
Sebastien Decugis's avatar
Sebastien Decugis committed
65
	TRACE_DEBUG(INFO, "libfreeDiameter initialized.");
66
67
68
69
	
	/* Name this thread */
	fd_log_threadname("Main");
	
Sebastien Decugis's avatar
Sebastien Decugis committed
70
	/* Initialize gcrypt and gnutls */
71
72
	GNUTLS_TRACE( (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) );
	GNUTLS_TRACE( (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0) );
Sebastien Decugis's avatar
Sebastien Decugis committed
73
74
75
76
77
	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 {
78
		TRACE_DEBUG(INFO, "libgnutls '%s', libgcrypt '%s', initialized.", gnutls_check_version(NULL), gcry_check_version(NULL) );
Sebastien Decugis's avatar
Sebastien Decugis committed
79
80
	}
	
81
82
83
84
85
86
	/* Initialize the config */
	CHECK_FCT( fd_conf_init() );

	/* Parse the command-line */
	CHECK_FCT(  main_cmdline(argc, argv)  );
	
87
88
89
	/* Allow SIGINT and SIGTERM from this point to terminate the application */
	CHECK_FCT( fd_sig_register(SIGINT,  "freeDiameter.main", fd_shutdown) );
	CHECK_FCT( fd_sig_register(SIGTERM, "freeDiameter.main", fd_shutdown) );
90
91
92
93
94
95
96
	
	/* 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()  );
97
	CHECK_FCT(  fd_p_expi_init()  );
98
99
100
101
	
	/* Parse the configuration file */
	CHECK_FCT( fd_conf_parse() );
	
102
103
104
	/* Create the daemon's threads */
	CHECK_FCT(  fd_rtdisp_init()  );
	
105
106
107
	/* Load the dynamic extensions */
	CHECK_FCT(  fd_ext_load()  );
	
108
	fd_conf_dump();
109
	fd_sig_dump(FULL, 1);
110
	
Sebastien Decugis's avatar
Sebastien Decugis committed
111
112
113
	/* Start the servers */
	CHECK_FCT( fd_servers_start() );
	
114
	/* Start the peer state machines */
115
	CHECK_FCT( fd_psm_start() );
116
117
118
119
	
	/* Now, just wait for events */
	TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
	while (1) {
120
121
		int code; size_t sz; void * data;
		CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
122
123
124
125
126
127
128
129
130
		switch (code) {
			case FDEV_DUMP_DICT:
				fd_dict_dump(fd_g_config->cnf_dict);
				break;
			
			case FDEV_DUMP_EXT:
				fd_ext_dump();
				break;
			
131
132
133
134
			case FDEV_DUMP_SERV:
				fd_servers_dump();
				break;
			
135
136
137
138
139
140
141
142
143
144
			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;
			
145
			case FDEV_DUMP_PEERS:
146
				fd_peer_dump_list(FULL);
147
				break;
148
149
150
151
152
153
154
155
156
157
158
159
160
161
			
			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 */
Sebastien Decugis's avatar
Sebastien Decugis committed
162
	CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
163
	CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
164
	CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
165
	CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
166
	
167
168
	CHECK_FCT_DO( fd_ext_fini(), /* Cleanup all extensions */ );
	CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ );
Sebastien Decugis's avatar
Sebastien Decugis committed
169
	
170
	GNUTLS_TRACE( gnutls_global_deinit() );
Sebastien Decugis's avatar
Sebastien Decugis committed
171
	
Sebastien Decugis's avatar
Sebastien Decugis committed
172
	fd_log_debug(FD_PROJECT_BINARY " daemon is terminated.\n");
173
174
175
	
	fd_lib_fini();
	
176
177
	return ret;
}
Sebastien Decugis's avatar
Sebastien Decugis committed
178
179
180
181
182
183

/* 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
184
	char * locale;
Sebastien Decugis's avatar
Sebastien Decugis committed
185
186
	
      	struct option long_options[] = {
Sebastien Decugis's avatar
Sebastien Decugis committed
187
188
189
190
191
192
		{ "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' },
193
194
		{ "dbg_func",	required_argument, 	NULL, 'f' },
		{ "dbg_file",	required_argument, 	NULL, 'F' },
Sebastien Decugis's avatar
Sebastien Decugis committed
195
		{ NULL,		0, 			NULL, 0 }
Sebastien Decugis's avatar
Sebastien Decugis committed
196
197
198
199
200
201
	};
	
	TRACE_ENTRY("%d %p", argc, argv);
	
	/* Loop on arguments */
	while (1) {
Sebastien Decugis's avatar
Sebastien Decugis committed
202
		c = getopt_long (argc, argv, "hVc:dql:", long_options, &option_index);
Sebastien Decugis's avatar
Sebastien Decugis committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
		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 );
217
				fd_g_config->cnf_file = optarg;
Sebastien Decugis's avatar
Sebastien Decugis committed
218
219
				break;

Sebastien Decugis's avatar
Sebastien Decugis committed
220
221
222
223
224
225
226
227
228
229
			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
230
231
232
233
			case 'd':	/* Increase verbosity of debug messages.  */
				fd_g_debug_lvl++;
				break;
				
234
			case 'f':	/* Full debug for the function with this name.  */
235
				#ifdef DEBUG
236
				fd_debug_one_function = optarg;
237
238
239
240
				#else /* DEBUG */
				TRACE_DEBUG(INFO, "Error: must compile with DEBUG support to use this feature");
				return EINVAL;
				#endif /* DEBUG */
241
242
243
				break;
				
			case 'F':	/* Full debug for the file with this name.  */
244
245
246
247
248
249
				#ifdef DEBUG
				fd_debug_one_file = basename(optarg);
				#else /* DEBUG */
				TRACE_DEBUG(INFO, "Error: must compile with DEBUG support to use this feature");
				return EINVAL;
				#endif /* DEBUG */
250
251
				break;
				
Sebastien Decugis's avatar
Sebastien Decugis committed
252
253
254
255
256
257
			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
258
				TRACE_DEBUG(INFO, "getopt_long found an invalid character");
Sebastien Decugis's avatar
Sebastien Decugis committed
259
260
261
				return EINVAL;

			default:	/* bug: option not considered.  */
Sebastien Decugis's avatar
Sebastien Decugis committed
262
				TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c", c);
Sebastien Decugis's avatar
Sebastien Decugis committed
263
264
265
266
267
268
				ASSERT(0);
				return EINVAL;
		}
	}
		
	return 0;
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
304
305
306
307
308
309
310
311
312
313
314
}

/* 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
315
  		"  -l, --dbglocale        Set the locale for error messages\n"
316
317
  		"  -d, --debug            Increase verbosity of debug messages\n"
  		"  -q, --quiet            Decrease verbosity then remove debug messages\n");
Sebastien Decugis's avatar
Sebastien Decugis committed
318
319
}

320
321
/* Terminate the application */
static void fd_shutdown(int signal)
Sebastien Decugis's avatar
Sebastien Decugis committed
322
{
323
	TRACE_ENTRY("%d", signal);
Sebastien Decugis's avatar
Sebastien Decugis committed
324
	
325
	TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", fd_sig_abbrev(signal), signal);
326

327
	CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) );
Sebastien Decugis's avatar
Sebastien Decugis committed
328
	
329
330
	return;
}