예제 #1
0
static int send_packet(struct rtmp_stream *stream,
		struct encoder_packet *packet, bool is_header, size_t idx)
{
	uint8_t *data;
	size_t  size;
	int     recv_size = 0;
	int     ret = 0;

#ifdef _WIN32
	ret = ioctlsocket(stream->rtmp.m_sb.sb_socket, FIONREAD,
			(u_long*)&recv_size);
#else
	ret = ioctl(stream->rtmp.m_sb.sb_socket, FIONREAD, &recv_size);
#endif

	if (ret >= 0 && recv_size > 0) {
		if (!discard_recv_data(stream, (size_t)recv_size))
			return -1;
	}

	flv_packet_mux(packet, &data, &size, is_header);
#ifdef TEST_FRAMEDROPS
	os_sleep_ms(rand() % 40);
#endif
	ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx);
	bfree(data);

	obs_free_encoder_packet(packet);

	stream->total_bytes_sent += size;
	return ret;
}
예제 #2
0
static void *audio_thread(void *param)
{
	struct audio_output *audio = param;
	uint64_t buffer_time = audio->info.buffer_ms * 1000000;
	uint64_t prev_time = os_gettime_ns() - buffer_time;
	uint64_t audio_time;

	os_set_thread_name("audio-io: audio thread");

	const char *audio_thread_name =
		profile_store_name(obs_get_profiler_name_store(),
				"audio_thread(%s)", audio->info.name);
	
	while (os_event_try(audio->stop_event) == EAGAIN) {
		os_sleep_ms(AUDIO_WAIT_TIME);

		profile_start(audio_thread_name);
		pthread_mutex_lock(&audio->line_mutex);

		audio_time = os_gettime_ns() - buffer_time;
		audio_time = mix_and_output(audio, audio_time, prev_time);
		prev_time  = audio_time;

		pthread_mutex_unlock(&audio->line_mutex);
		profile_end(audio_thread_name);

		profile_reenable_thread();
	}

	return NULL;
}
예제 #3
0
파일: dyndns.c 프로젝트: eckyecky/rt-n56u
/*************PRIVATE FUNCTIONS ******************/
static RC_TYPE dyn_dns_wait_for_cmd(DYN_DNS_CLIENT *p_self)
{
	int counter;
	DYN_DNS_CMD old_cmd;

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

	old_cmd = p_self->cmd;
	if (old_cmd != NO_CMD)
	{
		return RC_OK;
	}

	counter = p_self->sleep_sec / p_self->cmd_check_period;
	while (counter --)
	{
		if (p_self->cmd != old_cmd)
		{
			break;
		}
		os_sleep_ms(p_self->cmd_check_period * 1000);
	}

	return RC_OK;
}
예제 #4
0
void Statistics::Start()
{
    if (isStarted_)
        return;
    auto w = [this]() {
        int vCount = 0; //每一次循环加1
        while(!quit_) {
            os_sleep_ms(1000);
            std::lock_guard<std::mutex> lock(mutex_);

            perSecond_[vCount % interval_] = curVideoStatByte_;
            vCount++;

            int base = vCount < interval_ ? vCount : interval_;
            int tmp = 0;
            for(int i = 0; i < interval_; i++) {
                tmp += perSecond_[i];
            }
            statInfo_.videoBitrate = tmp / base;

            statInfo_.videoFps = videoFrameCount_;
            statInfo_.audioFps = audioFrameCount_;
            statInfo_.audioBitrate = curAudioStatByte_;

            curVideoStatByte_ = 0;
            curAudioStatByte_ = 0;
            videoFrameCount_ = 0;
            audioFrameCount_ = 0;
        }
    };
    statThread = std::thread(w);
    isStarted_ = true;
}
예제 #5
0
static int send_packet(struct rtmp_stream *stream,
		struct encoder_packet *packet, bool is_header, size_t idx)
{
	uint8_t *data;
	size_t  size;
	int     ret = 0;

	flv_packet_mux(packet, &data, &size, is_header);
#ifdef TEST_FRAMEDROPS
	os_sleep_ms(rand() % 40);
#endif
	ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx);
	bfree(data);

	obs_free_encoder_packet(packet);

	stream->total_bytes_sent += size;
	return ret;
}
예제 #6
0
static void *audio_thread(void *param)
{
	struct audio_output *audio = param;
	size_t rate = audio->info.samples_per_sec;
	uint64_t samples = 0;
	uint64_t start_time = os_gettime_ns();
	uint64_t prev_time = start_time;
	uint64_t audio_time = prev_time;
	uint32_t audio_wait_time =
		(uint32_t)(audio_frames_to_ns(rate, AUDIO_OUTPUT_FRAMES) /
				1000000);

	os_set_thread_name("audio-io: audio thread");

	const char *audio_thread_name =
		profile_store_name(obs_get_profiler_name_store(),
				"audio_thread(%s)", audio->info.name);

	while (os_event_try(audio->stop_event) == EAGAIN) {
		uint64_t cur_time;

		os_sleep_ms(audio_wait_time);

		profile_start(audio_thread_name);

		cur_time = os_gettime_ns();
		while (audio_time <= cur_time) {
			samples += AUDIO_OUTPUT_FRAMES;
			audio_time = start_time +
				audio_frames_to_ns(rate, samples);

			input_and_output(audio, audio_time, prev_time);
			prev_time = audio_time;
		}

		profile_end(audio_thread_name);

		profile_reenable_thread();
	}

	return NULL;
}
예제 #7
0
static void *audio_thread(void *param)
{
	struct audio_output *audio = param;
	uint64_t buffer_time = audio->info.buffer_ms * 1000000;
	uint64_t prev_time = os_gettime_ns() - buffer_time;
	uint64_t audio_time;

	while (os_event_try(audio->stop_event) == EAGAIN) {
		os_sleep_ms(AUDIO_WAIT_TIME);

		pthread_mutex_lock(&audio->line_mutex);

		audio_time = os_gettime_ns() - buffer_time;
		audio_time = mix_and_output(audio, audio_time, prev_time);
		prev_time  = audio_time;

		pthread_mutex_unlock(&audio->line_mutex);
	}

	return NULL;
}
예제 #8
0
/*************PRIVATE FUNCTIONS ******************/
static int dyn_dns_wait_for_cmd(ddns_t *ctx)
{
	int counter;
	ddns_cmd_t old_cmd;

	if (!ctx)
		return RC_INVALID_POINTER;

	old_cmd = ctx->cmd;
	if (old_cmd != NO_CMD)
		return 0;

	counter = ctx->sleep_sec / ctx->cmd_check_period;
	while (counter--) {
		if (ctx->cmd != old_cmd)
			break;

		os_sleep_ms(ctx->cmd_check_period * 1000);
	}

	return 0;
}
예제 #9
0
void os_sleepto_ns(uint64_t time_target)
{
	uint64_t t = os_gettime_ns();
	uint32_t milliseconds;

	if (t >= time_target)
		return;

	milliseconds = (uint32_t)((time_target - t)/1000000);
	if (milliseconds > 1)
		os_sleep_ms(milliseconds);

	for (;;) {
		t = os_gettime_ns();
		if (t >= time_target)
			return;

#if 1
		Sleep(1);
#else
		Sleep(0);
#endif
	}
}
예제 #10
0
파일: dyndns.c 프로젝트: eckyecky/rt-n56u
static RC_TYPE do_update_alias_table(DYN_DNS_CLIENT *p_self)
{
	int i, j;
	RC_TYPE rc = RC_OK, rc2;
	HTTP_TRANSACTION http_tr;
	int anychange = 0;

	for (i = 0; i < p_self->info_count; i++)
	{
		DYNDNS_INFO_TYPE *info = &p_self->info[i];

		for (j = 0; j < info->alias_count; j++)
		{
			if (info->alias_info[j].update_required != TRUE)
			{
				continue;
			}

			rc = http_client_init(&p_self->http_to_dyndns[i], "Sending IP# update to DDNS server");
			if (rc != RC_OK)
			{
				break;
			}

			/* Build dyndns transaction */
			http_tr.req_len = info->p_dns_system->p_dns_update_req_func(
				(struct _DYN_DNS_CLIENT*) p_self, i, j);
			http_tr.p_req = (char*) p_self->p_req_buffer;
			http_tr.p_rsp = (char*) p_self->p_work_buffer;
			http_tr.max_rsp_len = p_self->work_buffer_size - 1; /* Save place for a \0 at the end */
			http_tr.rsp_len = 0;

			rc = http_client_transaction(&p_self->http_to_dyndns[i], &http_tr);
			http_tr.p_rsp[http_tr.rsp_len] = 0;

			if (p_self->dbg.level > 2)
			{
				p_self->p_req_buffer[http_tr.req_len] = 0;
				logit(LOG_DEBUG, MODULE_TAG "Sending alias table update to DDNS server:");
				logit(LOG_DEBUG, MODULE_TAG "%s", p_self->p_req_buffer);
			}

			if (rc == RC_OK)
			{
				rc = info->p_dns_system->p_rsp_ok_func((struct _DYN_DNS_CLIENT*)p_self,
										&http_tr, i);
				if (rc == RC_OK)
				{
					info->alias_info[j].update_required = FALSE;

					logit(LOG_INFO, MODULE_TAG "Successful alias table update for %s => new IP# %s",
					      info->alias_info[j].names.name, info->my_ip_address.name);
					p_self->time_since_last_update = 0;
					anychange++; /* Adjust forced update period on success */
				}
				else
				{
					logit(LOG_WARNING, MODULE_TAG "%s error in DDNS server response:",
						  rc == RC_DYNDNS_RSP_RETRY_LATER ? "Temporary" : "Fatal");
					logit(LOG_WARNING, MODULE_TAG "[%d %s] %s",
					      http_tr.status, http_tr.status_desc,
					      http_tr.p_rsp_body != http_tr.p_rsp ? http_tr.p_rsp_body : "");
				}

				if (p_self->dbg.level > 2)
				{
					logit(LOG_DEBUG, MODULE_TAG "DDNS server response:");
					logit(LOG_DEBUG, MODULE_TAG "%s", http_tr.p_rsp);
				}
			}

			rc2 = http_client_shutdown(&p_self->http_to_dyndns[i]);
			if (rc == RC_OK)
			{
				/* Only overwrite rc with of http_client_shutdown() rc if previous call, in
				 * e.g., http_client_transaction() or the p_rsp_ok_func() callback was OK. */
				rc = rc2;
			}
			if (rc != RC_OK)
			{
				break;
			}
			os_sleep_ms(1000);
		}
	}

	/* Successful change or when cache file does not yet exist! */
	if (anychange || access(p_self->cachefile, F_OK))
	{
		FILE *fp;

		/* Update cache with new IP */
		fp = fopen(p_self->cachefile, "w"); 
		if (fp)
		{
			fprintf(fp, "%s", p_self->info[0].my_ip_address.name);
			fclose(fp);
		}

		if (anychange && p_self->external_command)
		{
			/* Run external command hook on update. */
			os_shell_execute(p_self->external_command);
		}
	}

	return rc;
}
예제 #11
0
static RC_TYPE do_update_alias_table(DYN_DNS_CLIENT *p_self)
{
	int i;
	int shutdown = 0;
	RC_TYPE rc = RC_OK;
	FILE *fp;
	
	do 
	{			
		for (i = 0; i < p_self->alias_info.count; ++i)
		{
			if (p_self->alias_info.update_required[i] != TRUE)
			{
				continue;
			}	
			
			rc = http_client_init(&p_self->http_to_dyndns);
			if (rc != RC_OK)
			{
				break;
			}
			
			/*build dyndns transaction*/
			{
				HTTP_TRANSACTION http_tr;
				http_tr.req_len = p_self->info.p_dns_system->p_dns_update_req_func(
                        (struct _DYN_DNS_CLIENT*) p_self,i,
						(struct DYNDNS_SYSTEM*) p_self->info.p_dns_system);
				http_tr.p_req = (char*) p_self->p_req_buffer;
				http_tr.p_rsp = (char*) p_self->p_work_buffer;
				http_tr.max_rsp_len = p_self->work_buffer_size - 1;/*save place for a \0 at the end*/
				http_tr.rsp_len = 0;
				p_self->p_work_buffer[http_tr.rsp_len+1] = 0;
				
				/*send it*/
				rc = http_client_transaction(&p_self->http_to_dyndns, &http_tr);					

				if (p_self->dbg.level > 2)
				{
					p_self->p_req_buffer[http_tr.req_len] = 0;
					DBG_PRINTF((LOG_DEBUG,"DYNDNS my Request:\n%s\n", p_self->p_req_buffer));
				}

				if (rc == RC_OK)
				{
					int rc = p_self->info.p_dns_system->p_rsp_ok_func((struct _DYN_DNS_CLIENT*)p_self, http_tr.p_rsp, 
							p_self->info.p_dns_system->p_success_string);
					if (rc == RC_OK)
					{
			                        p_self->alias_info.update_required[i] = FALSE;

						DBG_PRINTF((LOG_WARNING,"I:" MODULE_TAG "Alias '%s' to IP '%s' updated successfully.\n", 
							p_self->alias_info.names[i].name,
							p_self->info.my_ip_address.name));                        
						p_self->times_since_last_update = 0;
						/*recalc forced update period*/
						p_self->forced_update_period_sec = p_self->forced_update_period_sec_orig;
						p_self->forced_update_times = p_self->forced_update_period_sec / p_self->sleep_sec;

						if ((fp=fopen(p_self->ip_cache, "w")))
						{
							fprintf(fp,"%s", p_self->info.my_ip_address.name);
							fclose(fp);
						}
						if ((fp=fopen(p_self->time_cache, "w")))
						{
							fprintf(fp,"%ld", time (NULL));
							fclose(fp);
						}
						if (strlen(p_self->external_command) > 0)
							os_shell_execute(p_self->external_command);
					}
					else
					{
						DBG_PRINTF((LOG_WARNING,"W:" MODULE_TAG "Response Code: %d\n", rc));
						DBG_PRINTF((LOG_WARNING,"W:" MODULE_TAG "Error validating DYNDNS svr answer. Check usr,pass,hostname! (%s)\n", http_tr.p_rsp));
						shutdown++;
					}
					if (p_self->dbg.level > 2)
					{							
						http_tr.p_rsp[http_tr.rsp_len] = 0;
						DBG_PRINTF((LOG_WARNING,"W:" MODULE_TAG "DYNDNS Server response:\n%s\n", http_tr.p_rsp));
					}
				}
			}
			
			{
				RC_TYPE rc2 = http_client_shutdown(&p_self->http_to_dyndns);
				if (rc == RC_OK)
				{
					rc = rc2;
				}			
			}
			if (rc != RC_OK || shutdown>2)
			{
				break;
			}
			os_sleep_ms(1000);
		}
		if (rc != RC_OK)
		{
			break;
		}
	}
	while(0);
	return rc;
}
예제 #12
0
static RC_TYPE do_update_alias_table(DYN_DNS_CLIENT *p_self)
{
	int i;
	RC_TYPE rc = RC_OK;
	
	do 
	{			
		for (i = 0; i < p_self->alias_info.count; ++i)
		{
			if (p_self->alias_info.update_required[i] != TRUE)
			{
				continue;
			}	
			
			rc = http_client_init(&p_self->http_to_dyndns);
			if (rc != RC_OK)
			{
				break;
			}
			
			/*build dyndns transaction*/
			{
				HTTP_TRANSACTION http_tr;
				http_tr.req_len = p_self->info.p_dns_system->p_dns_update_req_func(
                        (struct _DYN_DNS_CLIENT*) p_self,i,
						(struct DYNDNS_SYSTEM*) p_self->info.p_dns_system);
				http_tr.p_req = (char*) p_self->p_req_buffer;
				http_tr.p_rsp = (char*) p_self->p_work_buffer;
				http_tr.max_rsp_len = p_self->work_buffer_size - 1;/*save place for a \0 at the end*/
				http_tr.rsp_len = 0;
				p_self->p_work_buffer[http_tr.rsp_len+1] = 0;
				
				/*send it*/
				rc = http_client_transaction(&p_self->http_to_dyndns, &http_tr);					

				if (p_self->dbg.level > 2)
				{
					p_self->p_req_buffer[http_tr.req_len] = 0;
					DBG_PRINTF((LOG_DEBUG,"DYNDNS my Request:\n%s\n", p_self->p_req_buffer));
				}

				if (rc == RC_OK)
				{
					BOOL update_ok = 
                        p_self->info.p_dns_system->p_rsp_ok_func((struct _DYN_DNS_CLIENT*)p_self, 
                            http_tr.p_rsp, 
							p_self->info.p_dns_system->p_success_string);
					if (update_ok)
					{
			                        p_self->alias_info.update_required[i] = FALSE;

						DBG_PRINTF((LOG_WARNING,"I:" MODULE_TAG "Alias '%s' to IP '%s' updated successful.\n", 
							p_self->alias_info.names[i].name,
							p_self->info.my_ip_address.name));                        
						p_self->times_since_last_update = 0;
							
					}
					else
					{
						DBG_PRINTF((LOG_WARNING,"W:" MODULE_TAG "Error validating DYNDNS svr answer. Check usr,pass,hostname!\n", http_tr.p_rsp));
					}
					if (p_self->dbg.level > 2)
					{							
						http_tr.p_rsp[http_tr.rsp_len] = 0;
						DBG_PRINTF((LOG_WARNING,"W:" MODULE_TAG "DYNDNS Server response:\n%s\n", http_tr.p_rsp));
					}
				}
			}
			
			{
				RC_TYPE rc2 = http_client_shutdown(&p_self->http_to_dyndns);
				if (rc == RC_OK)
				{
					rc = rc2;
				}			
			}
			if (rc != RC_OK)
			{
				break;
			}
			os_sleep_ms(1000);
		}
		if (rc != RC_OK)
		{
			break;
		}
	}
	while(0);
	return rc;
}
예제 #13
0
int main(int argc, char* argv[])
{
   if (argc < 2)
   {
      puts("Serial port missing");
      return 1;
   }

   if (argc < 3)
   {
      puts("Bluetooth address missing");
      return 1;
   }

   uint8_t peerAddress[6];
   if (! utl_parseAddress(argv[2], peerAddress))
   {
      printf("Failed to parse input address: %s\n", argv[2]);
      return 1;
   }

   if (lb_initialize() < 0)
   {
      puts("Failed to initialize lightBLUE library");
      return 2;
   }

   io_setDebugLevel(0);
   lb_setDebugLevel(0);

   struct LB_Controller* controller = lb_connect(argv[1]);

   if (! controller)
   {
      printf("Failed to connect to %s.\n", argv[1]);
      return 3;
   }

   if (LB_OK != lb_initializeHCI(controller))
   {
      goto done;
   }

   if (LB_OK != lb_configureAsCentral(controller))
   {
      goto done;
   }

   if (LB_OK != lb_openDeviceConnection(controller, peerAddress, &peerConnectionHandle))
   {
      goto done;
   }

   printf("Connected to ");
   utl_printAddress(peerAddress);
   printf(" using: %p\n", peerConnectionHandle);

   puts("Waiting for events. Press Ctrl-C to quit.");
   os_waitForKeyboardInterrupt();

   lb_closeDeviceConnection(peerConnectionHandle);

   os_sleep_ms(2000);

done:

   lb_disconnect(controller);

   lb_cleanup();

   return 0;
}
예제 #14
0
static int do_update_alias_table(ddns_t *ctx)
{
	int i, j;
	int rc = 0, rc2;
	http_trans_t http_tr;
	int anychange = 0;

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

		for (j = 0; j < info->alias_count; j++) {
			if (info->alias[j].update_required != 1) {
				continue;
			}

			rc = http_client_init(&ctx->http_to_dyndns[i], "Sending IP# update to DDNS server");
			if (rc != 0) {
				break;
			}

			/* Build dyndns transaction */
			http_tr.req_len = info->system->update_request_func(ctx, i, j);
			http_tr.p_req = (char *)ctx->request_buf;
			http_tr.p_rsp = (char *)ctx->work_buf;
			http_tr.max_rsp_len = ctx->work_buflen - 1;	/* Save place for a \0 at the end */
			http_tr.rsp_len = 0;

			rc = http_client_transaction(&ctx->http_to_dyndns[i], &http_tr);
			http_tr.p_rsp[http_tr.rsp_len] = 0;

			if (ctx->dbg.level > 2) {
				ctx->request_buf[http_tr.req_len] = 0;
				logit(LOG_DEBUG, "Sending alias table update to DDNS server:");
				logit(LOG_DEBUG, "%s", ctx->request_buf);
			}

			if (rc == 0) {
				rc = info->system->response_ok_func(ctx, &http_tr, i);
				if (rc == 0) {
					info->alias[j].update_required = 0;

					logit(LOG_INFO,
					      "Successful alias table update for %s => new IP# %s",
					      info->alias[j].names.name, info->my_ip_address.name);
					ctx->time_since_last_update = 0;
					ctx->force_addr_update = 0;
					anychange++;
				} else {
					logit(LOG_WARNING,
					      "%s error in DDNS server response:",
					      rc == RC_DYNDNS_RSP_RETRY_LATER ? "Temporary" : "Fatal");
					logit(LOG_WARNING, "[%d %s] %s",
					      http_tr.status,
					      http_tr.status_desc,
					      http_tr.p_rsp_body != http_tr.p_rsp ? http_tr.p_rsp_body : "");
				}

				if (ctx->dbg.level > 2) {
					logit(LOG_DEBUG, "DDNS server response:");
					logit(LOG_DEBUG, "%s", http_tr.p_rsp);
				}
			}

			rc2 = http_client_shutdown(&ctx->http_to_dyndns[i]);
			if (rc == 0) {
				/* Only overwrite rc with of http_client_shutdown() rc if previous call, in
				 * e.g., http_client_transaction() or the response_ok_func() callback was OK. */
				rc = rc2;
			}
			if (rc != 0) {
				break;
			}
			os_sleep_ms(1000);
		}
	}

	/* Successful change or when cache file does not yet exist! */
	if (anychange || access(ctx->cache_file, F_OK)) {
		FILE *fp;

		/* Update cache with new IP */
		fp = fopen(ctx->cache_file, "w");
		if (fp) {
			fprintf(fp, "%s", ctx->info[0].my_ip_address.name);
			fclose(fp);
		}

		/* Run external command hook on update. */
		if (anychange && ctx->external_command) {
			os_shell_execute(ctx->external_command,
					 ctx->info[0].my_ip_address.name,
					 ctx->info[0].alias[0].names.name, ctx->bind_interface);
		}
	}

	return rc;
}
예제 #15
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;
}
예제 #16
0
static enum data_ret write_data(struct rtmp_stream *stream, bool *can_write,
		uint64_t *last_send_time, size_t latency_packet_size,
		int delay_time)
{
	bool exit_loop = false;

	pthread_mutex_lock(&stream->write_buf_mutex);

	if (!stream->write_buf_len) {
		/* this is now an expected occasional condition due to use of
		 * auto-reset events, we could end up emptying the buffer as
		 * it's filled in a previous loop cycle, especially if using
		 * low latency mode. */
		pthread_mutex_unlock(&stream->write_buf_mutex);
		/* blog(LOG_DEBUG, "socket_thread_windows: Trying to send, "
				"but no data available"); */
		return RET_BREAK;
	}

	int ret;
	if (stream->low_latency_mode) {
		size_t send_len =
			min(latency_packet_size, stream->write_buf_len);

		ret = send(stream->rtmp.m_sb.sb_socket,
				(const char *)stream->write_buf,
				(int)send_len, 0);
	} else {
		ret = send(stream->rtmp.m_sb.sb_socket,
				(const char *)stream->write_buf,
				(int)stream->write_buf_len, 0);
	}

	if (ret > 0) {
		if (stream->write_buf_len - ret)
			memmove(stream->write_buf,
					stream->write_buf + ret,
					stream->write_buf_len - ret);
		stream->write_buf_len -= ret;

		*last_send_time = os_gettime_ns() / 1000000;

		os_event_signal(stream->buffer_space_available_event);
	} else {
		int err_code;
		bool fatal_err = false;

		if (ret == -1) {
			err_code = WSAGetLastError();

			if (err_code == WSAEWOULDBLOCK) {
				*can_write = false;
				pthread_mutex_unlock(&stream->write_buf_mutex);
				return RET_BREAK;
			}

			fatal_err = true;
		} else if (ret == 0) {
			err_code = 0;
			fatal_err = true;
		}

		if (fatal_err) {
			/* connection closed, or connection was aborted /
			 * socket closed / etc, that's a fatal error. */
			blog(LOG_ERROR, "socket_thread_windows: "
					"Socket error, send() returned %d, "
					"GetLastError() %d",
					ret, err_code);

			pthread_mutex_unlock(&stream->write_buf_mutex);
			fatal_sock_shutdown(stream);
			return RET_FATAL;
		}
	}

	/* finish writing for now */
	if (stream->write_buf_len <= 1000)
		exit_loop = true;

	pthread_mutex_unlock(&stream->write_buf_mutex);

	if (delay_time)
		os_sleep_ms(delay_time);

	return exit_loop ? RET_BREAK : RET_CONTINUE;
}