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
/* 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
62
/* freeDiameter starting point */
int main(int argc, char * argv[])
{
	int ret;
	pthread_t sig_th;
	sigset_t sig_all;
	
63
	/* Block all signals */
64
65
66
67
68
69
	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
70
	TRACE_DEBUG(INFO, "libfreeDiameter initialized.");
71
72
73
74
75
76
77
78
79
80
	
	/* 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
81
	/* Initialize gcrypt and gnutls */
82
	(void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
Sebastien Decugis's avatar
Sebastien Decugis committed
83
	(void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
Sebastien Decugis's avatar
Sebastien Decugis committed
84
85
86
87
88
89
90
91
	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));
	}
	
92
93
94
95
96
97
98
99
100
	/* 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()  );
101
	CHECK_FCT(  fd_p_expi_init()  );
102
	CHECK_FCT(  fd_rtdisp_init()  );
103
104
105
106
107
108
109
	
	/* Parse the configuration file */
	CHECK_FCT( fd_conf_parse() );
	
	/* Load the dynamic extensions */
	CHECK_FCT(  fd_ext_load()  );
	
110
111
	fd_conf_dump();
	
Sebastien Decugis's avatar
Sebastien Decugis committed
112
113
114
	/* Start the servers */
	CHECK_FCT( fd_servers_start() );
	
115
	/* Start the peer state machines */
116
	CHECK_FCT( fd_psm_start() );
117
118
119
120
	
	/* Now, just wait for events */
	TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
	while (1) {
121
122
		int code; size_t sz; void * data;
		CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
123
124
125
126
127
128
129
130
131
		switch (code) {
			case FDEV_DUMP_DICT:
				fd_dict_dump(fd_g_config->cnf_dict);
				break;
			
			case FDEV_DUMP_EXT:
				fd_ext_dump();
				break;
			
132
133
134
135
			case FDEV_DUMP_SERV:
				fd_servers_dump();
				break;
			
136
137
138
139
140
141
142
143
144
145
			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;
			
146
			case FDEV_DUMP_PEERS:
147
				fd_peer_dump_list(FULL);
148
				break;
149
150
151
152
153
154
155
156
157
158
159
160
161
162
			
			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
163
	CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
164
	CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
165
	CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
166
	CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
167
	
168
169
	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
170
	
171
	CHECK_FCT_DO( fd_thr_term(&sig_th), /* reclaim resources of the signal thread */ );
172
	
Sebastien Decugis's avatar
Sebastien Decugis committed
173
174
	gnutls_global_deinit();
	
175
176
	return ret;
}
Sebastien Decugis's avatar
Sebastien Decugis committed
177
178
179
180
181
182

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

Sebastien Decugis's avatar
Sebastien Decugis committed
217
218
219
220
221
222
223
224
225
226
			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
227
228
229
230
231
232
233
234
235
236
			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
237
				TRACE_DEBUG(INFO, "getopt_long found an invalid character");
Sebastien Decugis's avatar
Sebastien Decugis committed
238
239
240
				return EINVAL;

			default:	/* bug: option not considered.  */
Sebastien Decugis's avatar
Sebastien Decugis committed
241
				TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c", c);
Sebastien Decugis's avatar
Sebastien Decugis committed
242
243
244
245
246
247
				ASSERT(0);
				return EINVAL;
		}
	}
		
	return 0;
248
249
250
251
252
253
254
255
256
257
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
}

/* 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
294
  		"  -l, --dbglocale        Set the locale for error messages\n"
295
296
  		"  -d, --debug            Increase verbosity of debug messages\n"
  		"  -q, --quiet            Decrease verbosity then remove debug messages\n");
Sebastien Decugis's avatar
Sebastien Decugis committed
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
}

#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);
325
	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
326
327
328
	return NULL;
}