Exemple #1
0
/*
	Resource free.
*/	
RC_TYPE dyn_dns_destruct(DYN_DNS_CLIENT *p_self)
{
	RC_TYPE rc;
	if (p_self == NULL)
	{
		return RC_OK;
	}

	if (p_self->initialized == TRUE)
	{
		dyn_dns_shutdown(p_self);
	}

	rc = http_client_destruct(&p_self->http_to_ip_server);
	if (rc != RC_OK)
	{		
		
	}

	rc = http_client_destruct(&p_self->http_to_dyndns);
	if (rc != RC_OK)
	{	
		
	}

	if (p_self->p_work_buffer != NULL)
	{
		free(p_self->p_work_buffer);
		p_self->p_work_buffer = NULL;
	}

	if (p_self->p_req_buffer != NULL)
	{
		free(p_self->p_req_buffer);
		p_self->p_req_buffer = NULL;
	}

	if (p_self->info.credentials.p_enc_usr_passwd_buffer != NULL)
	{
		free(p_self->info.credentials.p_enc_usr_passwd_buffer);
		p_self->info.credentials.p_enc_usr_passwd_buffer = NULL;
	}


	free(p_self);
	p_self = NULL;

	return RC_OK;
}
Exemple #2
0
/**
   Resource free.
*/
static int free_context(ddns_t *ctx)
{
	int i;

	if (!ctx)
		return 0;

	if (ctx->initialized == 1)
		dyn_dns_shutdown(ctx);

	http_client_destruct(ctx->http_to_ip_server, DYNDNS_MAX_SERVER_NUMBER);
	http_client_destruct(ctx->http_to_dyndns, DYNDNS_MAX_SERVER_NUMBER);

	free(ctx->work_buf);
	ctx->work_buf = NULL;

	free(ctx->request_buf);
	ctx->request_buf = NULL;

	for (i = 0; i < DYNDNS_MAX_SERVER_NUMBER; i++) {
		ddns_info_t *info = &ctx->info[i];

		free(info->creds.encoded_password);
		info->creds.encoded_password = NULL;
	}

	free(ctx->cfgfile);
	ctx->cfgfile = NULL;

	free(ctx->pidfile);
	ctx->pidfile = NULL;

	free(ctx->external_command);
	ctx->external_command = NULL;

	free(ctx->bind_interface);
	ctx->bind_interface = NULL;

	free(ctx->check_interface);
	ctx->check_interface = NULL;

	free(ctx->cache_file);
	ctx->cache_file = NULL;

	free(ctx);

	return 0;
}
Exemple #3
0
/** MAIN - Dyn DNS update entry point
    Actions:
    - read the configuration options
    - perform various init actions as specified in the options
    - create and init dyn_dns object.
    - launch the IP update action loop
*/
int dyn_dns_main(DYN_DNS_CLIENT *p_dyndns, int argc, char* argv[])
{
	FILE *fp;
	RC_TYPE rc = RC_OK;
	int i, s;
	int iterations_err = 0;
	char name[DYNDNS_SERVER_NAME_LENGTH];

	if (p_dyndns == NULL)
	{
		return RC_INVALID_POINTER;
	}

	/* Create pid and cache file repository. */
	mkdir(DYNDNS_RUNTIME_DATA_DIR, 0755);

	/* read cmd line options and set object properties */
	rc = get_config_data(p_dyndns, argc, argv);
	if (rc != RC_OK || p_dyndns->abort)
	{
		return rc;
	}

	if (p_dyndns->change_persona)
	{
		OS_USER_INFO os_usr_info;

		memset(&os_usr_info, 0, sizeof(os_usr_info));
		os_usr_info.gid = p_dyndns->sys_usr_info.gid;
		os_usr_info.uid = p_dyndns->sys_usr_info.uid;
		rc = os_change_persona(&os_usr_info);
		if (rc != RC_OK)
		{
			return rc;
		}
	}

	/* if logfile provided, redirect output to log file */
	if (strlen(p_dyndns->dbg.p_logfilename) != 0)
	{
		rc = os_open_dbg_output(DBG_FILE_LOG, "", p_dyndns->dbg.p_logfilename);
		if (rc != RC_OK)
		{
			return rc;
		}
	}

	if (p_dyndns->debug_to_syslog == TRUE || (p_dyndns->run_in_background == TRUE))
	{
		if (get_dbg_dest() == DBG_STD_LOG) /* avoid file and syslog output */
		{
			rc = os_open_dbg_output(DBG_SYS_LOG, "inadyn", NULL);
			if (rc != RC_OK)
			{
				return rc;
			}
		}
	}

	/* if silent required, close console window */
	if (p_dyndns->run_in_background == TRUE)
	{
		rc = close_console_window();
		if (rc != RC_OK)
		{
			return rc;
		}
		if (get_dbg_dest() == DBG_SYS_LOG)
		{
			fclose(stdout);
		}
	}

	/* Create files with permissions 0644 */
	umask(S_IWGRP | S_IWOTH);

	/* write pid file */
	fp = fopen(p_dyndns->pidfile, "w");
	if (!fp)
	{
		logit(LOG_ERR, MODULE_TAG "Failed opening pidfile %s for writing: %s", p_dyndns->pidfile, strerror(errno));
		return RC_ERROR;
	}
	fprintf(fp, "%u", getpid());
	fclose(fp);

	dyn_dns_print_hello();

	/* At boot, or when restarting inadyn at runtime, the memory struct holding
	 * our current IP# is empty.  We want to avoid unnecessary updates of our
	 * DDNS server record, since we might get locked out for abuse, so we "seed"
	 * each of the DDNS records of our struct with the cached IP# from our cache
	 * file, or from a regular DNS query. */
	fp = fopen(p_dyndns->cachefile, "r");
	if (!fp)
	{
		struct addrinfo hints;
		struct addrinfo *result;

		/* Clear DNS cache before querying for the IP below. */
		res_init();

		/* Try a DNS lookup of our last known IP#. */
		for (i = 0; i < p_dyndns->info_count; i++)
		{
			if (p_dyndns->info[i].alias_count &&
			    /* exception for tunnelbroker.net - no name to lookup */
			    strcmp(p_dyndns->info[i].p_dns_system->p_key, "*****@*****.**"))
			{
				/* DNS Lookup */
				memset(&hints, 0, sizeof(struct addrinfo));
				hints.ai_family = AF_INET;    /* IPv4 */
				hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
				hints.ai_flags = 0;
				hints.ai_protocol = 0;          /* Any protocol */

				if (!(s = getaddrinfo(p_dyndns->info[i].alias_info[0].names.name, NULL, &hints, &result)))
				{
					/* DNS reply for alias found, convert to IP# */
					if (!getnameinfo(result->ai_addr, result->ai_addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
					{
						/* Update local record for next checkip call. */
						strncpy(p_dyndns->info[i].my_ip_address.name, name, sizeof(p_dyndns->info[i].my_ip_address.name));
						logit(LOG_INFO, MODULE_TAG "Resolving hostname %s => IP# %s", p_dyndns->info[i].alias_info[0].names.name, name);
					}
					freeaddrinfo(result);
				}
				else
					logit(LOG_WARNING, MODULE_TAG "Failed resolving hostname %s: %s", p_dyndns->info[i].alias_info[0].names.name, gai_strerror(s));
			}
		}
	}
	else
	{
		/* Read cached IP# from inadyn cache file. */
		if (fgets(name, sizeof(name), fp))
		{
			logit(LOG_INFO, MODULE_TAG "Cached IP# %s from previous invocation.", name);

			/* Update local record for next checkip call. */
			for (i = 0; i < p_dyndns->info_count; i++)
			{
				strncpy(p_dyndns->info[i].my_ip_address.name, name, sizeof(p_dyndns->info[i].my_ip_address.name));
			}
		}
		fclose(fp);
	}

	do
	{
		rc = dyn_dns_init(p_dyndns);
		if (rc != RC_OK)
		{
			break;
		}

		rc = get_encoded_user_passwd(p_dyndns);
		if (rc != RC_OK)
		{
			break;
		}

		/* DDNS client main loop */
		while (1)
		{
			rc = dyn_dns_update_ip(p_dyndns);
			if (rc != RC_OK)
			{
				if (p_dyndns->cmd == CMD_RESTART)
				{
					logit(LOG_DEBUG, "RESTART command received. Restarting.");
					rc = RC_RESTART;
					break;
				}
				
				if (rc == RC_DYNDNS_RSP_NOTOK && p_dyndns->total_iterations == 1)
				{
					logit(LOG_ERR, MODULE_TAG "Error response from DDNS server, exiting!");
					break;
				}
				
				iterations_err++;
			}
			else
			{
				/* count only the successful iterations */
				p_dyndns->num_iterations++;
				iterations_err = 0;
			}

			/* check if the user wants us to stop */
			if (p_dyndns->total_iterations != 0 && p_dyndns->num_iterations >= p_dyndns->total_iterations)
			{
				break;
			}

			if (p_dyndns->total_iterations != 1)
			{
				if (rc == RC_DYNDNS_RSP_RETRY_LATER || rc == RC_DYNDNS_RSP_NOTOK)
					p_dyndns->sleep_sec = p_dyndns->error_update_period_sec;
				else
					p_dyndns->sleep_sec = p_dyndns->normal_update_period_sec;
			}
			else
				p_dyndns->sleep_sec = DYNDNS_MIN_SLEEP;

			if (rc != RC_OK)
			{
				/* dyn_dns_update_ip() failed above, and we've not reached MAX iterations. 
				 * Time to inform the user the (network) error is not fatal and that we
				 * will try again in a short while. */
				logit(LOG_WARNING, MODULE_TAG "Will retry again in %d sec...", p_dyndns->sleep_sec);
			}

			/* Now sleep a while. Using the time set in sleep_sec data member */
			dyn_dns_wait_for_cmd(p_dyndns);
			if (p_dyndns->cmd == CMD_STOP)
			{
				logit(LOG_DEBUG, MODULE_TAG "STOP command received, exiting.");
				rc = RC_OK;
				break;
			}
			else if (p_dyndns->cmd == CMD_RESTART)
			{
				if (p_dyndns->dbg.level > 0)
					logit(LOG_DEBUG, "RESTART command received, restarting.");
				rc = RC_RESTART;
				break;
			}

			if (p_dyndns->total_iterations > 0 && iterations_err > p_dyndns->total_iterations)
			{
				rc = RC_OK;
				break;
			}

			if (p_dyndns->dbg.level > 0)
			{
				logit(LOG_DEBUG, ".");
//				logit(LOG_DEBUG, "Time since last update: %d", p_dyndns->time_since_last_update);
			}
			p_dyndns->time_since_last_update += p_dyndns->sleep_sec;
		}
	}
	while (0);

	/* if everything ok here we should exit. End of program */
	if (rc == RC_OK)
	{
	    rc = dyn_dns_shutdown(p_dyndns);
	}

	return rc;
}
Exemple #4
0
/**
   Resource free.
*/
RC_TYPE dyn_dns_destruct(DYN_DNS_CLIENT *p_self)
{
	int i;
	RC_TYPE rc;

	if (p_self == NULL)
	{
		return RC_OK;
	}

	if (p_self->initialized == TRUE)
	{
		dyn_dns_shutdown(p_self);
	}

	rc = http_client_destruct(p_self->http_to_ip_server, DYNDNS_MAX_SERVER_NUMBER);
	if (rc != RC_OK)
	{
		/* XXX */
	}

	rc = http_client_destruct(p_self->http_to_dyndns, DYNDNS_MAX_SERVER_NUMBER);
	if (rc != RC_OK)
	{
		/* XXX */
	}

	free(p_self->p_work_buffer);
	p_self->p_work_buffer = NULL;

	free(p_self->p_req_buffer);
	p_self->p_req_buffer = NULL;

	i = 0;
	while (i < DYNDNS_MAX_SERVER_NUMBER)
	{
		DYNDNS_INFO_TYPE *info = &p_self->info[i];

		free(info->credentials.p_enc_usr_passwd_buffer);
		info->credentials.p_enc_usr_passwd_buffer = NULL;

		i++;
	}

	free(p_self->cfgfile);
	p_self->cfgfile = NULL;

	free(p_self->pidfile);
	p_self->pidfile = NULL;

	free(p_self->cachefile);
	p_self->cachefile = NULL;

	free(p_self->external_command);
	p_self->external_command = NULL;

	free(p_self->bind_interface);
	p_self->bind_interface = NULL;

	free(p_self->check_interface);
	p_self->check_interface = NULL;

	/* Save old value, if restarted by SIGHUP */
	cached_time_since_last_update = p_self->time_since_last_update;
	cached_num_iterations = p_self->num_iterations;

	free(p_self);
	p_self = NULL;

	return RC_OK;
}
Exemple #5
0
/* 
	Actions:
		- read the configuration options
		- perform various init actions as specified in the options
		- create and init dyn_dns object.
		- launch the IP update action loop
*/		
int dyn_dns_main(DYN_DNS_CLIENT *p_dyndns, int argc, char* argv[])
{
	RC_TYPE rc = RC_OK;
	int iterations = 0;
	BOOL quit_flag = FALSE;
	BOOL init_flag;
	BOOL os_handler_installed = FALSE;
	FILE *fp;

	if (p_dyndns == NULL)
	{
		return RC_INVALID_POINTER;
	}

	/* read cmd line options and set object properties*/
	rc = get_config_data(p_dyndns, argc, argv);
	if (rc != RC_OK || p_dyndns->abort)
	{
		return rc;
	}

    /*if logfile provided, redirect output to log file*/
    if (strlen(p_dyndns->dbg.p_logfilename) != 0)
    {
        rc = os_open_dbg_output(DBG_FILE_LOG, "", p_dyndns->dbg.p_logfilename);
        if (rc != RC_OK)
        {
            return rc;
        }
    }

	if (p_dyndns->debug_to_syslog == TRUE ||
       (p_dyndns->run_in_background == TRUE))
	{
		if (get_dbg_dest() == DBG_STD_LOG) /*avoid file and syslog output */
        {
            rc = os_open_dbg_output(DBG_SYS_LOG, "INADYN", NULL);
            if (rc != RC_OK)
            {
                return rc;
            }
        }
	}

	if (p_dyndns->change_persona)
	{
		OS_USER_INFO os_usr_info;
		memset(&os_usr_info, 0, sizeof(os_usr_info));
		os_usr_info.gid = p_dyndns->sys_usr_info.gid;
		os_usr_info.uid = p_dyndns->sys_usr_info.uid;
		rc = os_change_persona(&os_usr_info);
		if (rc != RC_OK)
		{
			return rc;
		}
	}

    /*if silent required, close console window*/
    if (p_dyndns->run_in_background == TRUE)
    {
        rc = close_console_window();
        if (rc != RC_OK)
        {
            return rc;
        }       
        if (get_dbg_dest() == DBG_SYS_LOG)
        {
            fclose(stdout);
        }
    }

    dyn_dns_print_hello(NULL);

    if ((fp=fopen(p_dyndns->ip_cache, "r")))
    {
	fgets (p_dyndns->info.my_ip_address.name, sizeof (p_dyndns->info.my_ip_address.name),fp);
	fclose(fp);
	DBG_PRINTF((LOG_INFO, MODULE_TAG "IP read from cache file is '%s'. No update required.\n", p_dyndns->info.my_ip_address.name));
    }

	/* the real work here */
	do
	{
		/* init object */			
		init_flag = FALSE;
		rc = dyn_dns_init(p_dyndns);
		if (rc != RC_OK)
		{
			break;
		}		
		init_flag = TRUE;				

		rc = get_encoded_user_passwd(p_dyndns);
		if (rc != RC_OK)
		{
			break;
		}

		if (!os_handler_installed)
		{
			rc = os_install_signal_handler(p_dyndns);
			if (rc != RC_OK)
			{
				DBG_PRINTF((LOG_WARNING,"DYNDNS: Error '%s' (0x%x) installing OS signal handler\n",
					errorcode_get_name(rc), rc));
				break;
			}
			os_handler_installed = TRUE;
		}
		
		/*update IP address in a loop*/
		while(1)
		{
			rc = dyn_dns_update_ip(p_dyndns);
			if (rc != RC_OK)
			{
				DBG_PRINTF((LOG_WARNING,"W:'%s' (0x%x) updating the IPs. (it %d)\n",
					errorcode_get_name(rc), rc, iterations));			
				
			}
			/* check if the user wants us to stop */
			++iterations;
			if (iterations >= p_dyndns->total_iterations &&
				p_dyndns->total_iterations != 0)
			{
				break;
			}
			p_dyndns->sleep_sec = rc == RC_DYNDNS_RSP_RETRY_LATER ? DYNDNS_ERROR_UPDATE_PERIOD : DYNDNS_DEFAULT_SLEEP;

			/* also sleep the time set in the ->sleep_sec data memeber*/
			dyn_dns_wait_for_cmd(p_dyndns);
			if (p_dyndns->cmd == CMD_STOP)
			{
				DBG_PRINTF((LOG_DEBUG,"STOP command received. Exiting.\n"));
				rc = RC_OK;
				break;
			}
			
			if (rc == RC_OK)
			{
				if (p_dyndns->dbg.level > 0)
				{
					DBG_PRINTF((LOG_DEBUG,"."));
				}
				p_dyndns->times_since_last_update ++;
			}
			else
			{
			    dyn_dns_shutdown(p_dyndns);
			    init_flag = FALSE;
			    break;
			}
									
		}	
		
		/*if everything ok here we should exit. End of program*/
		if (rc == RC_OK)
		{
		    break;
		} 	
	}
	while(quit_flag == FALSE);	

	if (init_flag == TRUE)
	{
	    /* dyn_dns_shutdown object */			
	    rc = dyn_dns_shutdown(p_dyndns);
	}
	
	return rc;
}
Exemple #6
0
/** MAIN - Dyn DNS update entry point
    Actions:
    - read the configuration options
    - perform various init actions as specified in the options
    - create and init dyn_dns object.
    - launch the IP update action loop
*/
int dyn_dns_main(ddns_t *ctx, int argc, char *argv[])
{
	FILE *fp;
	int rc = 0;
	int i, s;
	char name[DYNDNS_SERVER_NAME_LEN];
	static int first_startup = 1;

	if (!ctx)
		return RC_INVALID_POINTER;

	/* Create pid and cache file repository. */
	mkdir(DYNDNS_RUNTIME_DATA_DIR, 0755);

	/* read cmd line options and set object properties */
	rc = get_config_data(ctx, argc, argv);
	if (rc != 0 || ctx->abort)
		return rc;

	if (ctx->change_persona) {
		ddns_user_t user;

		memset(&user, 0, sizeof(user));
		user.gid = ctx->sys_usr_info.gid;
		user.uid = ctx->sys_usr_info.uid;
		rc = os_change_persona(&user);
		if (rc != 0)
			return rc;
	}

	/* if logfile provided, redirect output to log file */
	if (strlen(ctx->dbg.p_logfilename) != 0) {
		rc = os_open_dbg_output(DBG_FILE_LOG, "", ctx->dbg.p_logfilename);
		if (rc != 0) {
			return rc;
		}
	}

	if (ctx->debug_to_syslog == 1 || (ctx->run_in_background == 1)) {
		if (get_dbg_dest() == DBG_STD_LOG) {	/* avoid file and syslog output */
			rc = os_open_dbg_output(DBG_SYS_LOG, "inadyn", NULL);
			if (rc != 0) {
				return rc;
			}
		}
	}

	/* if silent required, close console window */
	if (ctx->run_in_background == 1) {
		rc = close_console_window();
		if (rc != 0) {
			return rc;
		}
		if (get_dbg_dest() == DBG_SYS_LOG) {
			fclose(stdout);
		}
	}

	/* Create files with permissions 0644 */
	umask(S_IWGRP | S_IWOTH);

	/* write pid file */
	fp = fopen(ctx->pidfile, "w");
	if (!fp) {
		logit(LOG_ERR, "Failed opening pidfile %s for writing: %s", ctx->pidfile, strerror(errno));
		return RC_ERROR;
	}
	fprintf(fp, "%u\n", getpid());
	fclose(fp);

	/* "Hello!" Let user know we've started up OK */
	logit(LOG_INFO, "%s", DYNDNS_VERSION_STRING);

	/* On first startup only, optionally wait for network and any NTP daemon
	 * to set system time correctly.  Intended for devices without battery
	 * backed real time clocks as initialization of time since last update
	 * requires the correct time.  Sleep can be cancelled with any signal,
	 * but it is recommended to use SIGUSR1. */
	if (first_startup && ctx->startup_delay_sec) {
		logit(LOG_NOTICE, "Startup delay: %d sec ...", ctx->startup_delay_sec);
		os_sleep_ms(1000 * ctx->startup_delay_sec);
		first_startup = 0;
	}

	/* At boot, or when restarting inadyn at runtime, the memory struct holding
	 * our current IP# is empty.  We want to avoid unnecessary updates of our
	 * DDNS server record, since we might get locked out for abuse, so we "seed"
	 * each of the DDNS records of our struct with the cached IP# from our cache
	 * file, or from a regular DNS query. */
	fp = fopen(ctx->cache_file, "r");
	if (!fp) {
		struct addrinfo hints;
		struct addrinfo *result;

		/* Clear DNS cache before querying for the IP below. */
		res_init();

		/* Try a DNS lookup of our last known IP#. */
		for (i = 0; i < ctx->info_count; i++) {
			if (ctx->info[i].alias_count &&
			    /* exception for tunnelbroker.net - no name to lookup */
			    strcmp(ctx->info[i].system->key, "*****@*****.**")) {
				/* DNS Lookup */
				memset(&hints, 0, sizeof(struct addrinfo));
				hints.ai_family = AF_INET;	/* IPv4 */
				hints.ai_socktype = SOCK_DGRAM;	/* Datagram socket */
				hints.ai_flags = 0;
				hints.ai_protocol = 0;	/* Any protocol */

				if (!(s = getaddrinfo(ctx->info[i].alias[0].names.name, NULL, &hints, &result))) {
					/* DNS reply for alias found, convert to IP# */
					if (!getnameinfo
					    (result->ai_addr,
					     result->ai_addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) {
						/* Update local record for next checkip call. */
						strncpy(ctx->info[i].my_ip_address.name,
							name, sizeof(ctx->info[i].my_ip_address.name));
						logit(LOG_INFO,
						      "Resolving hostname %s => IP# %s",
						      ctx->info[i].alias[0].names.name, name);
					}
					freeaddrinfo(result);
				} else {
					logit(LOG_WARNING,
					      "Failed resolving hostname %s: %s",
					      ctx->info[i].alias[0].names.name, gai_strerror(s));
				}
			}
		}
	} else {
		struct stat statbuf;

		/* Read cached IP# from inadyn cache file. */
		if (fgets(name, sizeof(name), fp)) {
			logit(LOG_INFO, "Cached IP# %s from previous invocation.", name);

			/* Update local record for next checkip call. */
			for (i = 0; i < ctx->info_count; i++) {
				strncpy(ctx->info[i].my_ip_address.name, name,
					sizeof(ctx->info[i].my_ip_address.name));
			}
		}

		/* Initialize time since last update from modification time of cache file. */
		if (fstat(fileno(fp), &statbuf) == 0) {
			time_t now = time(NULL);

			if (now != -1 && now > statbuf.st_mtime) {
				cached_time_since_last_update = (int)(now - statbuf.st_mtime);
				logit(LOG_INFO,
				      "Cached time since last update %d (seconds) from previous invocation.",
				      cached_time_since_last_update);
			}
		}

		fclose(fp);
	}

	do {
		rc = dyn_dns_init(ctx);
		if (rc != 0)
			break;

		rc = get_encoded_user_passwd(ctx);
		if (rc != 0)
			break;

		if (ctx->update_once == 1)
			ctx->force_addr_update = 1;

		/* DDNS client main loop */
		while (1) {
			rc = dyn_dns_update_ip(ctx);
			if (rc != 0) {
				if (ctx->cmd == CMD_RESTART) {
					logit(LOG_INFO, "RESTART command received. Restarting.");
					rc = RC_RESTART;
					ctx->cmd = NO_CMD;
					break;
				}

				if (rc == RC_DYNDNS_RSP_NOTOK) {
					logit(LOG_ERR, "Error response from DDNS server, exiting!");
					break;
				}
			} else {
				/* count only the successful iterations */
				ctx->num_iterations++;
			}

			/* check if the user wants us to stop */
			if (ctx->total_iterations != 0 && ctx->num_iterations >= ctx->total_iterations)
				break;

			ctx->sleep_sec =
			    rc ==
			    RC_DYNDNS_RSP_RETRY_LATER ? ctx->error_update_period_sec :
			    ctx->normal_update_period_sec;

			if (rc != 0) {
				/* dyn_dns_update_ip() failed above, and we've not reached MAX iterations. 
				 * Time to inform the user the (network) error is not fatal and that we
				 * will try again in a short while. */
				logit(LOG_WARNING, "Will retry again in %d sec...", ctx->sleep_sec);
			}

			/* Now sleep a while. Using the time set in sleep_sec data member */
			dyn_dns_wait_for_cmd(ctx);

			if (ctx->cmd == CMD_STOP) {
				logit(LOG_INFO, "STOP command received, exiting.");
				rc = 0;
				ctx->cmd = NO_CMD;
				break;
			}
			if (ctx->cmd == CMD_RESTART) {
				logit(LOG_INFO, "RESTART command received, restarting.");
				rc = RC_RESTART;
				ctx->cmd = NO_CMD;
				break;
			}
			if (ctx->cmd == CMD_FORCED_UPDATE) {
				logit(LOG_INFO, "FORCED_UPDATE command received, updating now.");
				ctx->force_addr_update = 1;
				ctx->cmd = NO_CMD;
				continue;
			}

			if (ctx->dbg.level > 0) {
				logit(LOG_DEBUG, ".");
//                              logit(LOG_DEBUG, "Time since last update: %d", ctx->time_since_last_update);
			}
			ctx->time_since_last_update += ctx->sleep_sec;
		}

		/* Save old value, if restarted by SIGHUP */
		cached_time_since_last_update = ctx->time_since_last_update;
		cached_num_iterations = ctx->num_iterations;
	}
	while (0);

	/* if everything ok here we should exit. End of program */
	if (rc == 0)
		rc = dyn_dns_shutdown(ctx);

	return rc;
}