Exemple #1
0
/* the main application entry point */
int main(int argc, char *argv[])
{
	char pid_path[PATH_MAX] = "";	/* full path to the pid file */
	char pid_buffer[32] = "";	/* pid string */
	char old_pid_buffer[32] = "";	/* pid string */
	switch_size_t pid_len, old_pid_len;
	const char *err = NULL;		/* error value for return from freeswitch initialization */
#ifndef WIN32
	switch_bool_t nf = SWITCH_FALSE;				/* TRUE if we are running in nofork mode */
	switch_bool_t do_wait = SWITCH_FALSE;
	char *runas_user = NULL;
	char *runas_group = NULL;
	int fds[2] = { 0, 0 };
#else
	switch_bool_t win32_service = SWITCH_FALSE;
#endif
	switch_bool_t nc = SWITCH_FALSE;				/* TRUE if we are running in noconsole mode */
	pid_t pid = 0;
	int i, x;
	char *opts;
	char opts_str[1024] = "";
	char *local_argv[1024] = { 0 };
	int local_argc = argc;
	char *arg_argv[128] = { 0 };
	int alt_dirs = 0, log_set = 0, run_set = 0, do_kill = 0;
	int priority = 0;
#ifdef __sun
	switch_core_flag_t flags = SCF_USE_SQL;
#else
	switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT | SCF_USE_NAT_MAPPING | SCF_CALIBRATE_CLOCK | SCF_USE_CLOCK_RT;
#endif
	int ret = 0;
	switch_status_t destroy_status;
	switch_file_t *fd;
	switch_memory_pool_t *pool = NULL;
#ifdef HAVE_SETRLIMIT
#ifndef FS_64BIT
	switch_bool_t waste = SWITCH_FALSE;
#endif
#endif

	for (x = 0; x < argc; x++) {
		local_argv[x] = argv[x];
	}

	if ((opts = getenv("FREESWITCH_OPTS"))) {
		strncpy(opts_str, opts, sizeof(opts_str) - 1);
		i = switch_separate_string(opts_str, ' ', arg_argv, (sizeof(arg_argv) / sizeof(arg_argv[0])));
		for (x = 0; x < i; x++) {
			local_argv[local_argc++] = arg_argv[x];
		}
	}

	if (local_argv[0] && strstr(local_argv[0], "freeswitchd")) {
		nc = SWITCH_TRUE;
	}

	for (x = 1; x < local_argc; x++) {

		if (switch_strlen_zero(local_argv[x]))
			continue;

		if (!strcmp(local_argv[x], "-help") || !strcmp(local_argv[x], "-h") || !strcmp(local_argv[x], "-?")) {
			printf("%s\n", usage);
			exit(EXIT_SUCCESS);
		}
#ifdef WIN32
		if (x == 1 && !strcmp(local_argv[x], "-service")) {
			/* New installs will always have the service name specified, but keep a default for compat */
			x++;
			if (!switch_strlen_zero(local_argv[x])) {
				switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
			} else {
				switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
			}

			win32_service = SWITCH_TRUE;
			continue;
		}

		else if (x == 1 && !strcmp(local_argv[x], "-install")) {
			char servicePath[PATH_MAX];
			char exePath[PATH_MAX];
			SC_HANDLE hService;
			SC_HANDLE hSCManager;
			SERVICE_DESCRIPTION desc;
			desc.lpDescription = "The FreeSWITCH service.";

			x++;
			if (!switch_strlen_zero(local_argv[x])) {
				switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
			} else {
				switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
			}

			GetModuleFileName(NULL, exePath, sizeof(exePath));
			snprintf(servicePath, sizeof(servicePath), "%s -service %s", exePath, service_name);

			/* Perform service installation */

			hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
			if (!hSCManager) {
				fprintf(stderr, "Could not open service manager (%u).\n", GetLastError());
				exit(EXIT_FAILURE);
			}

			hService = CreateService(hSCManager, service_name, service_name, GENERIC_READ | GENERIC_EXECUTE | SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
						 servicePath, NULL, NULL, NULL, NULL, /* Service start name */ NULL);
			if (!hService) {
				fprintf(stderr, "Error creating freeswitch service (%u).\n", GetLastError());
				CloseServiceHandle(hSCManager);
				exit(EXIT_FAILURE);
			}

			/* Set desc, and don't care if it succeeds */
			if (!ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &desc)) {
				fprintf(stderr, "FreeSWITCH installed, but could not set the service description (%u).\n", GetLastError());
			}

			CloseServiceHandle(hService);
			CloseServiceHandle(hSCManager);
			exit(EXIT_SUCCESS);
		}

		else if (x == 1 && !strcmp(local_argv[x], "-uninstall")) {
			SC_HANDLE hService;
			SC_HANDLE hSCManager;
			BOOL deleted;

			x++;
			if (!switch_strlen_zero(local_argv[x])) {
				switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
			} else {
				switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
			}

			/* Do the uninstallation */
			hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
			if (!hSCManager) {
				fprintf(stderr, "Could not open service manager (%u).\n", GetLastError());
				exit(EXIT_FAILURE);
			}

			hService = OpenService(hSCManager, service_name, DELETE);
			if (!hService) {
				fprintf(stderr, "Error opening service (%u).\n", GetLastError());
				CloseServiceHandle(hSCManager);
				exit(EXIT_FAILURE);
			}

			/* remove the service! */
			deleted = DeleteService(hService);
			if (!deleted) {
				fprintf(stderr, "Error deleting service (%u).\n", GetLastError());
			}

			CloseServiceHandle(hService);
			CloseServiceHandle(hSCManager);
			exit(deleted ? EXIT_SUCCESS : EXIT_FAILURE);
		}

		else if (!strcmp(local_argv[x], "-monotonic-clock")) {
			flags |= SCF_USE_WIN32_MONOTONIC;
		}
#else
		else if (!strcmp(local_argv[x], "-u")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "Option '%s' requires an argument!\n", local_argv[x - 1]);
				exit(EXIT_FAILURE);
			}
			runas_user = local_argv[x];
		}

		else if (!strcmp(local_argv[x], "-g")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "Option '%s' requires an argument!\n", local_argv[x - 1]);
				exit(EXIT_FAILURE);
			}
			runas_group = local_argv[x];
		}

		else if (!strcmp(local_argv[x], "-nf")) {
			nf = SWITCH_TRUE;
		}

		else if (!strcmp(local_argv[x], "-version")) {
			fprintf(stdout, "FreeSWITCH version: %s (%s)\n", SWITCH_VERSION_FULL, SWITCH_VERSION_REVISION_HUMAN);
			exit(EXIT_SUCCESS);
		}
#endif
#ifdef HAVE_SETRLIMIT
		else if (!strcmp(local_argv[x], "-core")) {
			struct rlimit rlp;
			memset(&rlp, 0, sizeof(rlp));
			rlp.rlim_cur = RLIM_INFINITY;
			rlp.rlim_max = RLIM_INFINITY;
			setrlimit(RLIMIT_CORE, &rlp);
		}

		else if (!strcmp(local_argv[x], "-waste")) {
#ifndef FS_64BIT
			fprintf(stderr, "WARNING: Wasting up to 8 megs of memory per thread.\n");
			sleep(2);
			waste = SWITCH_TRUE;
#endif
		}

		else if (!strcmp(local_argv[x], "-no-auto-stack")) {
#ifndef FS_64BIT
			waste = SWITCH_TRUE;
#endif
		}
#endif
		else if (!strcmp(local_argv[x], "-hp") || !strcmp(local_argv[x], "-rp")) {
			priority = 2;
		}

		else if (!strcmp(local_argv[x], "-lp")) {
			priority = -1;
		}

		else if (!strcmp(local_argv[x], "-np")) {
			priority = 1;
		}

		else if (!strcmp(local_argv[x], "-nosql")) {
			flags &= ~SCF_USE_SQL;
		}

		else if (!strcmp(local_argv[x], "-nonat")) {
			flags &= ~SCF_USE_AUTO_NAT;
		}

		else if (!strcmp(local_argv[x], "-nonatmap")) {
			flags &= ~SCF_USE_NAT_MAPPING;
		}

		else if (!strcmp(local_argv[x], "-heavy-timer")) {
			flags |= SCF_USE_HEAVY_TIMING;
		}

		else if (!strcmp(local_argv[x], "-nort")) {
			flags &= ~SCF_USE_CLOCK_RT;
		}

		else if (!strcmp(local_argv[x], "-nocal")) {
			flags &= ~SCF_CALIBRATE_CLOCK;
		}

		else if (!strcmp(local_argv[x], "-vg")) {
			flags |= SCF_VG;
		}

		else if (!strcmp(local_argv[x], "-stop")) {
			do_kill = SWITCH_TRUE;
		}

		else if (!strcmp(local_argv[x], "-nc")) {
			nc = SWITCH_TRUE;
		}
#ifndef WIN32
		else if (!strcmp(local_argv[x], "-ncwait")) {
			nc = SWITCH_TRUE;
			do_wait = SWITCH_TRUE;
		}
#endif
		else if (!strcmp(local_argv[x], "-c")) {
			nc = SWITCH_FALSE;
		}

		else if (!strcmp(local_argv[x], "-conf")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -conf you must specify a config directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.conf_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.conf_dir, local_argv[x]);
			alt_dirs++;
		}

		else if (!strcmp(local_argv[x], "-mod")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -mod you must specify a module directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.mod_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.mod_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-log")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -log you must specify a log directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.log_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.log_dir, local_argv[x]);
			alt_dirs++;
			log_set = SWITCH_TRUE;
		}

		else if (!strcmp(local_argv[x], "-run")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -run you must specify a pid directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.run_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.run_dir, local_argv[x]);
			run_set = SWITCH_TRUE;
		}

		else if (!strcmp(local_argv[x], "-db")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -db you must specify a db directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.db_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.db_dir, local_argv[x]);
			alt_dirs++;
		}

		else if (!strcmp(local_argv[x], "-scripts")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -scripts you must specify a scripts directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.script_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.script_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-htdocs")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -htdocs you must specify a htdocs directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.htdocs_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.htdocs_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-base")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -base you must specify a base directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.base_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.base_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.base_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-temp")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -temp you must specify a temp directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.temp_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.temp_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.temp_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-storage")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -storage you must specify a storage directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.storage_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.storage_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.storage_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-recordings")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -recordings you must specify a recording directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.recordings_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.recordings_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.recordings_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-grammar")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -grammar you must specify a grammar directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.grammar_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.grammar_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.grammar_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-sounds")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -sounds you must specify a sounds directory\n");
				return 255;
			}

			SWITCH_GLOBAL_dirs.sounds_dir = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_dirs.sounds_dir) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_dirs.sounds_dir, local_argv[x]);
		}

		else if (!strcmp(local_argv[x], "-cfgname")) {
			x++;
			if (switch_strlen_zero(local_argv[x]) || is_option(local_argv[x])) {
				fprintf(stderr, "When using -cfgname you must specify a filename\n");
				return 255;
			}

			SWITCH_GLOBAL_filenames.conf_name = (char *) malloc(strlen(local_argv[x]) + 1);
			if (!SWITCH_GLOBAL_filenames.conf_name) {
				fprintf(stderr, "Allocation error\n");
				return 255;
			}
			strcpy(SWITCH_GLOBAL_filenames.conf_name, local_argv[x]);
		}

		/* Unknown option (always last!) */
		else {
			fprintf(stderr, "Unknown option '%s', see '%s -help' for a list of valid options\n",
				local_argv[x], local_argv[0]);
			exit(EXIT_FAILURE);
		}
	}

	if (log_set && !run_set) {
		SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(SWITCH_GLOBAL_dirs.log_dir) + 1);
		if (!SWITCH_GLOBAL_dirs.run_dir) {
			fprintf(stderr, "Allocation error\n");
			return 255;
		}
		strcpy(SWITCH_GLOBAL_dirs.run_dir, SWITCH_GLOBAL_dirs.log_dir);
	}

	if (do_kill) {
		return freeswitch_kill_background();
	}

	if (apr_initialize() != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "FATAL ERROR! Could not initialize APR\n");
		return 255;
	}

	if (alt_dirs && alt_dirs != 3) {
		fprintf(stderr, "You must specify all or none of -conf, -log, and -db\n");
		return 255;
	}

#ifndef FS_64BIT
#if defined(HAVE_SETRLIMIT) && !defined(__sun)
	if (!waste && !(flags & SCF_VG)) {
		struct rlimit rlp;

		memset(&rlp, 0, sizeof(rlp));
		getrlimit(RLIMIT_STACK, &rlp);

		if (rlp.rlim_cur != SWITCH_THREAD_STACKSIZE) {
			char buf[1024] = "";
			int i = 0;

			memset(&rlp, 0, sizeof(rlp));
			rlp.rlim_cur = SWITCH_THREAD_STACKSIZE;
			rlp.rlim_max = SWITCH_SYSTEM_THREAD_STACKSIZE;
			setrlimit(RLIMIT_STACK, &rlp);

			apr_terminate();
			ret = (int) execv(argv[0], argv);

			for (i = 0; i < argc; i++) {
				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s ", argv[i]);
			}

			return system(buf);
		}
	}
#endif
#endif
	signal(SIGILL, handle_SIGILL);
	signal(SIGTERM, handle_SIGILL);
#ifndef WIN32
	if (do_wait) {
		if (pipe(fds)) {
			fprintf(stderr, "System Error!\n");
			exit(-1);
		}

		signal(SIGCHLD, handle_SIGCHLD);
	}
#endif

	if (nc) {
#ifdef WIN32
		FreeConsole();
#else
		if (!nf) {
			daemonize(do_wait ? fds : NULL);
		}
#endif
	}

	switch (priority) {
	case 2:
		set_realtime_priority();
		break;
	case 1:
		set_normal_priority();
		break;
	case -1:
		set_low_priority();
		break;
	default:
		set_auto_priority();
		break;
	}
	
	switch_core_setrlimits();


#ifndef WIN32
	if (runas_user || runas_group) {
		if (change_user_group(runas_user, runas_group) < 0) {
			fprintf(stderr, "Failed to switch user [%s] / group [%s]\n",
				switch_strlen_zero(runas_user)  ? "-" : runas_user,
				switch_strlen_zero(runas_group) ? "-" : runas_group);
			return 255;
		}
	}
#else
	if (win32_service) {
		/* Attempt to start service */
		SERVICE_TABLE_ENTRY dispatchTable[] = {
			{service_name, &service_main}
			,
			{NULL, NULL}
		};
		service_flags = flags; /* copy parsed flags for service startup */

		if (StartServiceCtrlDispatcher(dispatchTable) == 0) {
			/* Not loaded as a service */
			fprintf(stderr, "Error Freeswitch loaded as a console app with -service option\n");
			fprintf(stderr, "To install the service load freeswitch with -install\n");
		}
		exit(EXIT_SUCCESS);
	}
#endif

	switch_core_set_globals();

	pid = getpid();

	memset(pid_buffer, 0, sizeof(pid_buffer));
	switch_snprintf(pid_path, sizeof(pid_path), "%s%s%s", SWITCH_GLOBAL_dirs.run_dir, SWITCH_PATH_SEPARATOR, pfile);
	switch_snprintf(pid_buffer, sizeof(pid_buffer), "%d", pid);
	pid_len = strlen(pid_buffer);

	apr_pool_create(&pool, NULL);

	switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, pool);

	if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) {

		old_pid_len = sizeof(old_pid_buffer);
		switch_file_read(fd, old_pid_buffer, &old_pid_len);
		switch_file_close(fd);
	}

	if (switch_file_open(&fd,
						 pid_path,
						 SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE | SWITCH_FOPEN_TRUNCATE,
						 SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot open pid file %s.\n", pid_path);
		return 255;
	}

	if (switch_file_lock(fd, SWITCH_FLOCK_EXCLUSIVE | SWITCH_FLOCK_NONBLOCK) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot lock pid file %s.\n", pid_path);
		old_pid_len = strlen(old_pid_buffer);
		if (strlen(old_pid_buffer)) {
			switch_file_write(fd, old_pid_buffer, &old_pid_len);
		}
		return 255;
	}

	switch_file_write(fd, pid_buffer, &pid_len);

	if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot Initialize [%s]\n", err);
		return 255;
	}

#ifndef WIN32
	if (do_wait) {
		if (fds[1] > -1) {
			int i, v = 1;

			if ((i = write(fds[1], &v, sizeof(v))) < 0) {
				fprintf(stderr, "System Error [%s]\n", strerror(errno));
			} else {
				i = read(fds[1], &v, sizeof(v));
			}
		
			shutdown(fds[1], 2);
			close(fds[1]);
			fds[1] = -1;
		}
	}
#endif

	switch_core_runtime_loop(nc);

	destroy_status = switch_core_destroy();

	switch_file_close(fd);
	apr_pool_destroy(pool);

	if (unlink(pid_path) != 0) {
		fprintf(stderr, "Failed to delete pid file [%s]\n", pid_path);
	}

	if (destroy_status == SWITCH_STATUS_RESTART) {
		char buf[1024] = "";
		int j = 0;

		switch_sleep(1000000);
		ret = (int) execv(argv[0], argv);
		fprintf(stderr, "Restart Failed [%s] resorting to plan b\n", strerror(errno));

		for (j = 0; j < argc; j++) {
			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s ", argv[j]);
		}

		ret = system(buf);
	}

	return ret;
}
Exemple #2
0
/* the main application entry point */
int main(int argc, char *argv[])
{
	char pid_path[256] = "";	/* full path to the pid file */
	char pid_buffer[32] = "";	/* pid string */
	char old_pid_buffer[32] = "";	/* pid string */
	switch_size_t pid_len, old_pid_len;
	const char *err = NULL;		/* error value for return from freeswitch initialization */
#ifndef WIN32
	int nf = 0;					/* TRUE if we are running in nofork mode */
	char *runas_user = NULL;
	char *runas_group = NULL;
#else
	int win32_service = 0;
#endif
	int nc = 0;					/* TRUE if we are running in noconsole mode */
	pid_t pid = 0;
	int i, x;
	char *opts;
	char opts_str[1024] = "";
	char *local_argv[1024] = { 0 };
	int local_argc = argc;
	char *arg_argv[128] = { 0 };
	char *usageDesc;
	int alt_dirs = 0, log_set = 0, run_set = 0, kill = 0;
	int known_opt;
	int high_prio = 0;
#ifdef __sun
	switch_core_flag_t flags = SCF_USE_SQL;
#else
	switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT | SCF_CALIBRATE_CLOCK | SCF_USE_CLOCK_RT;
#endif
	int ret = 0;
	switch_status_t destroy_status;
	switch_file_t *fd;
	switch_memory_pool_t *pool = NULL;
#ifdef HAVE_SETRLIMIT
	struct rlimit rlp;
	int waste = 0;
#endif

	for (x = 0; x < argc; x++) {
		local_argv[x] = argv[x];
	}

	if ((opts = getenv("FREESWITCH_OPTS"))) {
		strncpy(opts_str, opts, sizeof(opts_str) - 1);
		i = switch_separate_string(opts_str, ' ', arg_argv, (sizeof(arg_argv) / sizeof(arg_argv[0])));
		for (x = 0; x < i; x++) {
			local_argv[local_argc++] = arg_argv[x];
		}
	}


	if (local_argv[0] && strstr(local_argv[0], "freeswitchd")) {
		nc++;
	}

	usageDesc = "these are the optional arguments you can pass to freeswitch\n"
#ifdef WIN32
		"\t-service [name]        -- start freeswitch as a service, cannot be used if loaded as a console app\n"
		"\t-install [name]        -- install freeswitch as a service, with optional service name\n"
		"\t-uninstall             -- remove freeswitch as a service\n"
#else
		"\t-nf                    -- no forking\n"
		"\t-u [user]              -- specify user to switch to\n" "\t-g [group]             -- specify group to switch to\n"
#endif
		"\t-help                  -- this message\n" "\t-version               -- print the version and exit\n"
#ifdef HAVE_SETRLIMIT
		"\t-waste                 -- allow memory waste\n" "\t-core                  -- dump cores\n"
#endif
		"\t-hp                    -- enable high priority settings\n"
		"\t-vg                    -- run under valgrind\n"
		"\t-nosql                 -- disable internal sql scoreboard\n"
		"\t-heavy-timer           -- Heavy Timer, possibly more accurate but at a cost\n"
		"\t-nonat                 -- disable auto nat detection\n"
		"\t-nocal                 -- disable clock calibration\n"
		"\t-nort                  -- disable clock clock_realtime\n"
		"\t-stop                  -- stop freeswitch\n"
		"\t-nc                    -- do not output to a console and background\n"
		"\t-c                     -- output to a console and stay in the foreground\n"
		"\t-conf [confdir]        -- specify an alternate config dir\n"
		"\t-log [logdir]          -- specify an alternate log dir\n"
		"\t-run [rundir]          -- specify an alternate run dir\n"
		"\t-db [dbdir]            -- specify an alternate db dir\n"
		"\t-mod [moddir]          -- specify an alternate mod dir\n"
		"\t-htdocs [htdocsdir]    -- specify an alternate htdocs dir\n" "\t-scripts [scriptsdir]  -- specify an alternate scripts dir\n";

	for (x = 1; x < local_argc; x++) {
		known_opt = 0;
#ifdef WIN32
		if (x == 1) {
			if (local_argv[x] && !strcmp(local_argv[x], "-service")) {
				/* New installs will always have the service name specified, but keep a default for compat */
				x++;
				if (local_argv[x] && strlen(local_argv[x])) {
					switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
				} else {
					switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
				}
				known_opt++;
				win32_service++;
				continue;
			}
			if (local_argv[x] && !strcmp(local_argv[x], "-install")) {
				char exePath[1024];
				char servicePath[1024];
				x++;
				if (local_argv[x] && strlen(local_argv[x])) {
					switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
				} else {
					switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
				}
				known_opt++;
				GetModuleFileName(NULL, exePath, 1024);
				snprintf(servicePath, sizeof(servicePath), "%s -service %s", exePath, service_name);
				{				/* Perform service installation */
					SC_HANDLE hService;
					SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
					if (!hSCManager) {
						fprintf(stderr, "Could not open service manager (%d).\n", GetLastError());
						exit(1);
					}
					hService = CreateService(hSCManager, service_name, service_name, GENERIC_READ | GENERIC_EXECUTE | SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, servicePath, NULL, NULL, NULL, NULL,	/* Service start name */
											 NULL);
					if (!hService) {
						fprintf(stderr, "Error creating freeswitch service (%d).\n", GetLastError());
					} else {
						/* Set desc, and don't care if it succeeds */
						SERVICE_DESCRIPTION desc;
						desc.lpDescription = "The FreeSWITCH service.";
						if (!ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &desc)) {
							fprintf(stderr, "FreeSWITCH installed, but could not set the service description (%d).\n", GetLastError());
						}
						CloseServiceHandle(hService);
					}
					CloseServiceHandle(hSCManager);
					exit(0);
				}
			}

			if (local_argv[x] && !strcmp(local_argv[x], "-uninstall")) {
				x++;
				if (local_argv[x] && strlen(local_argv[x])) {
					switch_copy_string(service_name, local_argv[x], SERVICENAME_MAXLEN);
				} else {
					switch_copy_string(service_name, SERVICENAME_DEFAULT, SERVICENAME_MAXLEN);
				}
				{				/* Do the uninstallation */
					SC_HANDLE hService;
					SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
					if (!hSCManager) {
						fprintf(stderr, "Could not open service manager (%d).\n", GetLastError());
						exit(1);
					}
					hService = OpenService(hSCManager, service_name, DELETE);
					known_opt++;
					if (hService != NULL) {
						/* remove the service! */
						if (!DeleteService(hService)) {
							fprintf(stderr, "Error deleting service (%d).\n", GetLastError());
						}
						CloseServiceHandle(hService);
					} else {
						fprintf(stderr, "Error opening service (%d).\n", GetLastError());
					}
					CloseServiceHandle(hSCManager);
					exit(0);
				}
			}
		}
#else
		if (local_argv[x] && !strcmp(local_argv[x], "-u")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				runas_user = local_argv[x];
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-g")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				runas_group = local_argv[x];
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nf")) {
			nf++;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-version")) {
			fprintf(stdout, "FreeSWITCH version: %s\n", SWITCH_VERSION_FULL);
			return 0;
			known_opt++;
		}
#endif
#ifdef HAVE_SETRLIMIT
		if (local_argv[x] && !strcmp(local_argv[x], "-core")) {
			memset(&rlp, 0, sizeof(rlp));
			rlp.rlim_cur = RLIM_INFINITY;
			rlp.rlim_max = RLIM_INFINITY;
			setrlimit(RLIMIT_CORE, &rlp);
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-waste")) {
			waste++;
			known_opt++;
		}
#endif

		if (local_argv[x] && !strcmp(local_argv[x], "-hp")) {
			high_prio++;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nosql")) {
			flags &= ~SCF_USE_SQL;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nonat")) {
			flags &= ~SCF_USE_AUTO_NAT;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-heavy-timer")) {
			flags |= SCF_USE_HEAVY_TIMING;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nort")) {
			flags &= ~SCF_USE_CLOCK_RT;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nocal")) {
			flags &= ~SCF_CALIBRATE_CLOCK;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-vg")) {
			flags |= SCF_VG;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-stop")) {
			kill++;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-nc")) {
			nc++;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-c")) {
			nc = 0;
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-conf")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.conf_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.conf_dir, local_argv[x]);
				alt_dirs++;
			} else {
				fprintf(stderr, "When using -conf you must specify a config directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-mod")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.mod_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.mod_dir, local_argv[x]);
			} else {
				fprintf(stderr, "When using -mod you must specify a module directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-log")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.log_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.log_dir, local_argv[x]);
				alt_dirs++;
				log_set++;
			} else {
				fprintf(stderr, "When using -log you must specify a log directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-run")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.run_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.run_dir, local_argv[x]);
				run_set++;
			} else {
				fprintf(stderr, "When using -run you must specify a pid directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-db")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.db_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.db_dir, local_argv[x]);
				alt_dirs++;
			} else {
				fprintf(stderr, "When using -db you must specify a db directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-scripts")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.script_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.script_dir, local_argv[x]);
			} else {
				fprintf(stderr, "When using -scripts you must specify a scripts directory\n");
				return 255;
			}
			known_opt++;
		}

		if (local_argv[x] && !strcmp(local_argv[x], "-htdocs")) {
			x++;
			if (local_argv[x] && strlen(local_argv[x])) {
				SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(strlen(local_argv[x]) + 1);
				if (!SWITCH_GLOBAL_dirs.htdocs_dir) {
					fprintf(stderr, "Allocation error\n");
					return 255;
				}
				strcpy(SWITCH_GLOBAL_dirs.htdocs_dir, local_argv[x]);
			} else {
				fprintf(stderr, "When using -htdocs you must specify a htdocs directory\n");
				return 255;
			}
			known_opt++;
		}

		if (!known_opt || (local_argv[x] && (!strcmp(local_argv[x], "-help") || !strcmp(local_argv[x], "-h") || !strcmp(local_argv[x], "-?")))) {
			printf("%s\n", usageDesc);
			exit(0);
		}
	}

	if (log_set && !run_set) {
		SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(SWITCH_GLOBAL_dirs.log_dir) + 1);
		if (!SWITCH_GLOBAL_dirs.run_dir) {
			fprintf(stderr, "Allocation error\n");
			return 255;
		}
		strcpy(SWITCH_GLOBAL_dirs.run_dir, SWITCH_GLOBAL_dirs.log_dir);
	}

	if (kill) {
		return freeswitch_kill_background();
	}

	if (apr_initialize() != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "FATAL ERROR! Could not initialize APR\n");
		return 255;
	}

	if (alt_dirs && alt_dirs != 3) {
		fprintf(stderr, "You must specify all or none of -conf, -log, and -db\n");
		return 255;
	}

	signal(SIGILL, handle_SIGILL);
	signal(SIGTERM, handle_SIGILL);

	if (nc) {
#ifdef WIN32
		FreeConsole();
#else
		if (!nf) {
			daemonize();
		}
#endif
	}
#if defined(HAVE_SETRLIMIT) && !defined(__sun)
	if (!waste && !(flags & SCF_VG)) {
		memset(&rlp, 0, sizeof(rlp));
		getrlimit(RLIMIT_STACK, &rlp);
		if (rlp.rlim_max > SWITCH_THREAD_STACKSIZE) {
			char buf[1024] = "";
			int i = 0;

			fprintf(stderr, "Error: stacksize %d is too large: run ulimit -s %d or run %s -waste.\nauto-adjusting stack size for optimal performance...\n",
					(int) (rlp.rlim_max / 1024), SWITCH_THREAD_STACKSIZE / 1024, local_argv[0]);

			memset(&rlp, 0, sizeof(rlp));
			rlp.rlim_cur = SWITCH_THREAD_STACKSIZE;
			rlp.rlim_max = SWITCH_THREAD_STACKSIZE;
			setrlimit(RLIMIT_STACK, &rlp);

			apr_terminate();
			ret = (int) execv(argv[0], argv);

			for (i = 0; i < argc; i++) {
				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s ", argv[i]);
			}

			return system(buf);

		}
	}
#endif




	if (high_prio) {
		set_high_priority();
	}

	switch_core_setrlimits();


#ifndef WIN32
	if (runas_user || runas_group) {
		if (change_user_group(runas_user, runas_group) < 0) {
			fprintf(stderr, "Failed to switch user / group\n");
			return 255;
		}
	}
#else
	if (win32_service) {
		{						/* Attempt to start service */
			SERVICE_TABLE_ENTRY dispatchTable[] = {
				{service_name, &service_main}
				,
				{NULL, NULL}
			};
			if (StartServiceCtrlDispatcher(dispatchTable) == 0) {
				/* Not loaded as a service */
				fprintf(stderr, "Error Freeswitch loaded as a console app with -service option\n");
				fprintf(stderr, "To install the service load freeswitch with -install\n");
			}
			exit(0);
		}
	}
#endif

	switch_core_set_globals();

	pid = getpid();

	memset(pid_buffer, 0, sizeof(pid_buffer));
	switch_snprintf(pid_path, sizeof(pid_path), "%s%s%s", SWITCH_GLOBAL_dirs.run_dir, SWITCH_PATH_SEPARATOR, pfile);
	switch_snprintf(pid_buffer, sizeof(pid_buffer), "%d", pid);
	pid_len = strlen(pid_buffer);

	apr_pool_create(&pool, NULL);

	switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, pool);

	if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) {

		old_pid_len = sizeof(old_pid_buffer);
		switch_file_read(fd, old_pid_buffer, &old_pid_len);
		switch_file_close(fd);
	}

	if (switch_file_open(&fd,
						 pid_path,
						 SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE | SWITCH_FOPEN_TRUNCATE,
						 SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot open pid file %s.\n", pid_path);
		return 255;
	}

	if (switch_file_lock(fd, SWITCH_FLOCK_EXCLUSIVE | SWITCH_FLOCK_NONBLOCK) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot lock pid file %s.\n", pid_path);
		old_pid_len = strlen(old_pid_buffer);
		if (strlen(old_pid_buffer)) {
			switch_file_write(fd, old_pid_buffer, &old_pid_len);
		}
		return 255;
	}

	switch_file_write(fd, pid_buffer, &pid_len);

	if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
		fprintf(stderr, "Cannot Initialize [%s]\n", err);
		return 255;
	}

	switch_core_runtime_loop(nc);

	destroy_status = switch_core_destroy();

	switch_file_close(fd);

	if (unlink(pid_path) != 0) {
		fprintf(stderr, "Failed to delete pid file [%s]\n", pid_path);
	}

	if (destroy_status == SWITCH_STATUS_RESTART) {
		char buf[1024] = "";
		int j = 0;

		switch_sleep(1000000);
		ret = (int) execv(argv[0], argv);
		fprintf(stderr, "Restart Failed [%s] resorting to plan b\n", strerror(errno));

		for (j = 0; j < argc; j++) {
			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s ", argv[j]);
		}

		ret = system(buf);
	}

	return ret;
}