Example #1
0
/*  ----------------------------
 *          MONITOR CODE
 *  ---------------------------- */
void run_dtnperf_monitor(monitor_parameters_t * parameters)
{
	/* ------------------------
	 * variables
	 * ------------------------ */
	dtnperf_options_t * perf_opt = parameters->perf_g_opt->perf_opt;

	bp_error_t error;
	bp_endpoint_id_t local_eid;
	bp_reg_info_t reginfo;
	bp_reg_id_t regid;
	bp_bundle_object_t bundle_object;
	bp_bundle_status_report_t * status_report;
	bp_endpoint_id_t bundle_source_addr;
	bp_timestamp_t bundle_creation_timestamp;
	bp_timeval_t bundle_expiration;
	bp_endpoint_id_t relative_source_addr;
	bp_timestamp_t relative_creation_timestamp;
	HEADER_TYPE bundle_header;

	session_t * session;
	bundle_type_t bundle_type;
	struct timeval current, start;
	char * command;
	char temp[256];
	char * filename;
	int filename_len;
	char * full_filename;
	FILE * file;


	/* ------------------------
	 * initialize variables
	 * ------------------------ */
	boolean_t debug = perf_opt->debug;
	int debug_level = perf_opt->debug_level;

	dedicated_monitor = parameters->dedicated_monitor;
	bp_handle_open = FALSE;

	perf_opt->logs_dir = correct_dirname(perf_opt->logs_dir);

	status_report = NULL;
	session_list = session_list_create();

	// set out buffer size if daemon
	if (perf_opt->daemon)
	{
		setlinebuf(stdout);
		setlinebuf(stderr);
	}

	// create dir where dtnperf monitor will save logs
	// command should be: mkdir -p "logs_dir"
	if(debug && debug_level > 0)
		printf("[debug] initializing shell command...");
	command = malloc(sizeof(char) * (10 + strlen(perf_opt->logs_dir)));
	sprintf(command, "mkdir -p %s", perf_opt->logs_dir);
	if(debug && debug_level > 0)
		printf("done. Shell command = %s\n", command);

	// execute shell command
	if(debug && debug_level > 0)
		printf("[debug] executing shell command...");
	if (system(command) < 0)
	{
		perror("Error opening monitor logs dir");
		monitor_clean_exit(-1);
	}
	free(command);
	if(debug && debug_level > 0)
		printf("done\n");

	// signal handlers
	signal(SIGINT, monitor_handler);
	signal(SIGUSR1, monitor_handler);
	signal(SIGUSR2, monitor_handler);

	//open the connection to the bundle protocol router
	if(debug && debug_level > 0)
		printf("[debug] opening connection to bundle protocol router...");
	if (perf_opt->use_ip)
		error = bp_open_with_ip(perf_opt->ip_addr, perf_opt->ip_port, &handle);
	else
		error = bp_open(&handle);
	if (error != BP_SUCCESS)
	{
		fflush(stdout);
		fprintf(stderr, "fatal error opening bp handle: %s\n", bp_strerror(error));
		monitor_clean_exit(1);
	}
	else
	{
		bp_handle_open = TRUE;
	}
	if(debug && debug_level > 0)
		printf("done\n");

	//build a local eid
	if(debug && debug_level > 0)
		printf("[debug] building a local eid...");
	if (parameters->dedicated_monitor)
		sprintf(temp, "%s_%d", MON_EP_STRING, parameters->client_id);
	else
		sprintf(temp, "%s", MON_EP_STRING);
	bp_build_local_eid(handle, &local_eid, temp);
	if(debug && debug_level > 0)
		printf("done\n");
	if (debug)
		printf("local_eid = %s\n", local_eid.uri);

	// checking if there is already a registration
	if(debug && debug_level > 0)
		printf("[debug] checking for existing registration...");
	error = bp_find_registration(handle, &local_eid, &regid);
	if (error == BP_SUCCESS)
	{
		fflush(stdout);
		fprintf(stderr, "error: there is a registration with the same eid.\n");
		fprintf(stderr, "regid 0x%x\n", (unsigned int) regid);
		monitor_clean_exit(1);
	}
	if ((debug) && (debug_level > 0))
		printf(" done\n");

	//create a new registration to the local router based on this eid
	if(debug && debug_level > 0)
		printf("[debug] registering to local daemon...");
	memset(&reginfo, 0, sizeof(reginfo));
	bp_copy_eid(&reginfo.endpoint, &local_eid);
	reginfo.flags = BP_REG_DEFER;
	reginfo.regid = BP_REGID_NONE;
	reginfo.expiration = 0;
	if ((error = bp_register(handle, &reginfo, &regid)) != 0)
	{
		fflush(stdout);
		fprintf(stderr, "error creating registration: %d (%s)\n",
				error, bp_strerror(bp_errno(handle)));
		monitor_clean_exit(1);
	}
	if ((debug) && (debug_level > 0))
		printf(" done\n");
	if (debug)
		printf("regid 0x%x\n", (unsigned int) regid);

	// start expiration timer thread
	pthread_mutex_init (&mutexdata, NULL);
	pthread_create(&session_exp_timer, NULL, session_expiration_timer, (void *) parameters);

	if (!dedicated_monitor)
		printf("DTNperf Monitor started\n Waiting for bundles...\n");


	// start infinite loop
	while(1)
	{
		// reset variables
		bundle_type = NONE;

		// create a bundle object
		if ((debug) && (debug_level > 0))
			printf("[debug] initiating memory for bundles...\n");
		error = bp_bundle_create(&bundle_object);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "fatal error initiating memory for bundles: %s\n", bp_strerror(error));
			monitor_clean_exit(1);
		}
		if(debug && debug_level > 0)
			printf("done\n");


		// wait until receive a bundle
		if ((debug) && (debug_level > 0))
			printf("[debug] waiting for bundles...\n");
		error = bp_bundle_receive(handle, bundle_object, BP_PAYLOAD_MEM, -1);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "error getting recv reply: %d (%s)\n",
					error, bp_strerror(bp_errno(handle)));
			monitor_clean_exit(1);
		}
		if ((debug) && (debug_level > 0))
			printf(" bundle received\n");

		// mark current time
		if ((debug) && (debug_level > 0))
			printf("[debug] marking time...");
		gettimeofday(&current, NULL);
		if ((debug) && (debug_level > 0))
			printf(" done\n");

		// get SOURCE eid
		if ((debug) && (debug_level > 0))
			printf("[debug]\tgetting source eid...");
		error = bp_bundle_get_source(bundle_object, &bundle_source_addr);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "error getting bundle source eid: %s\n",
					bp_strerror(error));
			monitor_clean_exit(1);
		}
		if ((debug) && (debug_level > 0))
		{
			printf(" done:\n");
			printf("\tbundle_source_addr = %s\n", bundle_source_addr.uri);
			printf("\n");
		}

		// get bundle CREATION TIMESTAMP
		if ((debug) && (debug_level > 0))
			printf("[debug]\tgetting bundle creation timestamp...");
		error = bp_bundle_get_creation_timestamp(bundle_object, &bundle_creation_timestamp);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "error getting bundle creation timestamp: %s\n",
					bp_strerror(error));
			monitor_clean_exit(1);
		}
		if ((debug) && (debug_level > 0))
		{
			printf(" done:\n");
			printf("\tbundle creation timestamp:\n"
					"\tsecs = %d\n\tseqno= %d\n",
					(int)bundle_creation_timestamp.secs, (int)bundle_creation_timestamp.seqno);
			printf("\n");
		}

		// get bundle EXPIRATION TIME
		if ((debug) && (debug_level > 0))
			printf("[debug]\tgetting bundle expiration time...");
		error = bp_bundle_get_expiration(bundle_object, &bundle_expiration);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "error getting bundle expiration time: %s\n",
					bp_strerror(error));
			monitor_clean_exit(1);
		}
		if ((debug) && (debug_level > 0))
		{
			printf(" done:\n");
			printf("\tbundle expiration: %lu\n", bundle_expiration);
			printf("\n");
		}

		// check if bundle is a status report
		if ((debug) && (debug_level > 0))
			printf("[debug] check if bundle is a status report...\n");
		error = bp_bundle_get_status_report(bundle_object, &status_report);
		if (error != BP_SUCCESS)
		{
			fflush(stdout);
			fprintf(stderr, "error checking if bundle is a status report: %d (%s)\n",
					error, bp_strerror(bp_errno(handle)));
			continue;
		}
		if ((debug) && (debug_level > 0))
			printf(" %s\n", status_report == NULL ? "no" : "yes");

		// check for other bundle types
		if (status_report != NULL)
			bundle_type = STATUS_REPORT;
		else
		{
			get_bundle_header_and_options(&bundle_object, & bundle_header, NULL);

			if (bundle_header == FORCE_STOP_HEADER)
				bundle_type = CLIENT_FORCE_STOP;
			else if (bundle_header == STOP_HEADER)
				bundle_type = CLIENT_STOP;
			else if (bundle_header == DSA_HEADER)
				bundle_type = SERVER_ACK;
			else // unknown bundle type
			{
				fprintf(stderr, "error: unknown bundle type\n");
				continue;
			}
		}

		// retrieve or open log file
		pthread_mutex_lock(&mutexdata);

		session = NULL;

		switch (bundle_type)
		{
		case STATUS_REPORT:
			bp_copy_eid(&relative_source_addr, &(status_report->bundle_id.source));
			relative_creation_timestamp = status_report->bundle_id.creation_ts;
			break;

		case SERVER_ACK:
			get_info_from_ack(&bundle_object, &relative_source_addr, &relative_creation_timestamp);
			break;

		case CLIENT_STOP:
		case CLIENT_FORCE_STOP:
			bp_copy_eid(&relative_source_addr, &bundle_source_addr);
			relative_creation_timestamp = bundle_creation_timestamp;
			break;

		default:
			break;
		}

		session = session_get(session_list, relative_source_addr);

		if (session == NULL) // start a new session
		{
			// mark start time
			start = current;
			char * ptr;
			filename_len = strlen(relative_source_addr.uri) - strlen("dtn://") + 15;
			filename = (char *) malloc(filename_len);
			memset(filename, 0, filename_len);
			strncpy(temp, relative_source_addr.uri, strlen(relative_source_addr.uri) + 1);
			strtok(temp, "/");
			sprintf(filename, "%lu_", relative_creation_timestamp.secs);
			strcat(filename, strtok(NULL, "/"));

			// remove .dtn suffix from the filename
			ptr = strstr(filename, ".dtn");
			if (ptr != NULL)
				ptr[0] = '\0';

			// add .csv extension
			strcat(filename, ".csv");
			full_filename = (char *) malloc(strlen(perf_opt->logs_dir) + strlen(filename) + 2);
			sprintf(full_filename, "%s/%s", perf_opt->logs_dir, filename);
			file = fopen(full_filename, "w");
			session = session_create(relative_source_addr, full_filename, file, start,
					relative_creation_timestamp.secs, bundle_expiration);
			session_put(session_list, session);
			// write header in csv log file
			fprintf(file,"Mon_RX_TIME;BSR_OR_ACK_SOURCE;BSR_OR_ACK_TIMESTAMP;BSR_OR_ACK_SEQNO;"
					"TYPE;BUNDLE_X_SOURCE;BUNDLE_X_TIMESTAMP;BUNDLE_X_SEQNO;"
					"FRAG_OFFSET;FRAG_LENGTH;");
			csv_print_status_report_timestamps_header(file);
			csv_end_line(file);
		}

		// update session infos
		session->last_bundle_time = bundle_creation_timestamp.secs;
		session->expiration = bundle_expiration;
		file = session->file;
		memcpy(&start, session->start, sizeof(struct timeval));

		if (bundle_type == STATUS_REPORT && (status_report->flags & BP_STATUS_DELIVERED))
		{
			session->delivered_count++;
		}

		pthread_mutex_unlock(&mutexdata);

		// print rx time in csv log
		csv_print_rx_time(file, current, start);

		// print bundle source in csv log
		csv_print_eid(file, bundle_source_addr);

		//print bundle creation timestamp in csv log
		csv_print_timestamp(file, bundle_creation_timestamp);

		// print bundle type in csv log
		switch (bundle_type)
		{
		case CLIENT_STOP:
			csv_print(file, "CLIENT_STOP");
			break;
		case CLIENT_FORCE_STOP:
			csv_print(file, "CLIENT_FORCE_STOP");
			break;
		case SERVER_ACK:
			csv_print(file, "SERVER_ACK");
			break;
		case STATUS_REPORT:
			csv_print(file, "STATUS_REPORT");
			break;
		default:
			csv_print(file, "UNKNOWN");
			break;
		}

		// print relative source and timestamp
		if (bundle_type == SERVER_ACK || bundle_type == STATUS_REPORT)
		{
			csv_print_eid(file, relative_source_addr);
			csv_print_timestamp(file, relative_creation_timestamp);
		}

		// print status report infos in csv log
		if (bundle_type == STATUS_REPORT)
		{
			csv_print_ulong(file, status_report->bundle_id.frag_offset);
			csv_print_ulong(file, status_report->bundle_id.orig_length);
			csv_print_status_report_timestamps(file, * status_report);
		}

		// end line in csv log
		csv_end_line(file);

		// close file
		if (bundle_type == CLIENT_STOP)
		{
			int total_to_receive;
			get_info_from_stop(&bundle_object, &total_to_receive);
			pthread_mutex_lock(&mutexdata);
			session->total_to_receive = total_to_receive;
			session->wait_after_stop = bundle_expiration;
			gettimeofday(session->stop_arrival_time, NULL);
			pthread_mutex_unlock(&mutexdata);
		}
		else if (bundle_type == CLIENT_FORCE_STOP)
		{
			printf("DTNperf monitor: received forced end session bundle\n");
			session_close(session_list, session);
		}


	} // end loop

	session_list_destroy(session_list);
	bp_close(handle);
	bp_handle_open = FALSE;
}
Example #2
0
void * congestion_control(void * opt)
{
	dtnperf_options_t *perf_opt = ((dtnperf_global_options_t *)(opt))->perf_opt;
	boolean_t debug = perf_opt->debug;
	int debug_level = perf_opt->debug_level;
	boolean_t create_log = perf_opt->create_log;

	bp_timestamp_t reported_timestamp;
	bp_endpoint_id_t ack_sender;
	HEADER_TYPE ack_header;
	bp_copy_eid(&ack_sender, &dest_eid);
	struct timeval temp;

	int position = -1;

	if (debug && debug_level > 0)
		printf("[debug cong crtl] congestion control = %c\n", perf_opt->congestion_ctrl);

	if (perf_opt->congestion_ctrl == 'w') // window based congestion control
	{
		bp_bundle_create(&ack);

		while ((close_ack_receiver == 0) || (gettimeofday(&temp, NULL) == 0 && ack_recvd.tv_sec - temp.tv_sec <= perf_opt->wait_before_exit))
		{
			// if there are no bundles without ack, wait
			pthread_mutex_lock(&mutexdata);
			if (close_ack_receiver == 0 && count_info(send_info, perf_opt->window) == 0)
			{
				pthread_cond_wait(&cond_ackreceiver, &mutexdata);
				pthread_mutex_unlock(&mutexdata);
				// pthread_yield();
				sched_yield();
				continue;
			}

			// Wait for the reply
			if ((debug) && (debug_level > 0))
				printf("\t[debug cong crtl] waiting for the reply...\n");

			if ((error = bp_bundle_receive(handle, ack, BP_PAYLOAD_MEM, count_info(send_info, perf_opt->window) == 0 ? perf_opt->wait_before_exit : -1)) != BP_SUCCESS)
			{
				if(count_info(send_info, perf_opt->window) == 0 && close_ack_receiver == 1)
					// send_bundles is terminated
					break;
				fprintf(stderr, "error getting server ack: %d (%s)\n", error, bp_strerror(bp_errno(handle)));
				if (create_log)
					fprintf(log_file, "error getting server ack: %d (%s)\n", error, bp_strerror(bp_errno(handle)));
				client_clean_exit(1);
			}

			// Check if is actually a server ack bundle
			get_bundle_header_and_options(&ack, &ack_header, NULL);
			if (ack_header != DSA_HEADER)
			{
				fprintf(stderr, "error getting server ack: wrong bundle header\n");
				if (create_log)
					fprintf(log_file, "error getting server ack: wrong bundle header\n");

				pthread_mutex_unlock(&mutexdata);
				//pthread_yield();
				sched_yield();
				continue;
			}

			gettimeofday(&ack_recvd, NULL);
			if ((debug) && (debug_level > 0))
				printf("\t[debug cong crtl] ack received\n");

			// Get ack infos
			error = get_info_from_ack(&ack, NULL, &reported_timestamp);
			if (error != BP_SUCCESS)
			{
				fprintf(stderr, "error getting info from ack: %s\n", bp_strerror(error));
				if (create_log)
					fprintf(log_file, "error getting info from ack: %s\n", bp_strerror(error));
				client_clean_exit(1);
			}
			if ((debug) && (debug_level > 1))
				printf("\t[debug cong crtl] ack received timestamp: %lu %lu\n", reported_timestamp.secs, reported_timestamp.seqno);
			position = is_in_info(send_info, reported_timestamp, perf_opt->window);
			if (position < 0)
			{
				fprintf(stderr, "error removing bundle info\n");
				if (create_log)
					fprintf(log_file, "error removing bundle info\n");
				client_clean_exit(1);
			}
			remove_from_info(send_info, position);
			if ((debug) && (debug_level > 0))
				printf("\t[debug cong crtl] ack validated\n");
			sem_post(&window);
			if ((debug) && (debug_level > 1))
			{
				int cur;
				sem_getvalue(&window, &cur);
				printf("\t[debug cong crtl] window is %d\n", cur);
			}

			pthread_mutex_unlock(&mutexdata);
			//pthread_yield();
			sched_yield();
		} // end while(n_bundles)

		bp_bundle_free(&ack);
	}
	else if (perf_opt->congestion_ctrl == 'r') // Rate based congestion control
	{
		double interval_secs;

		if (perf_opt->rate_unit == 'b') // rate is bundles per second
		{
			interval_secs = 1.0 / perf_opt->rate;
		}
		else 							// rate is bit or kbit per second
		{
			if (perf_opt->rate_unit == 'k') // Rate is kbit per second
			{
				perf_opt->rate = kilo2byte(perf_opt->rate);
			}
			else // rate is Mbit per second
			{
				perf_opt->rate = mega2byte(perf_opt->rate);
			}
			interval_secs = (double)perf_opt->bundle_payload * 8 / perf_opt->rate;
		}

		if (debug)
			printf("[debug cong crtl] wait time for each bundle: %.4f sec\n", interval_secs);

		pthread_mutex_lock(&mutexdata);
		while(close_ack_receiver == 0)
		{
			pthread_mutex_unlock(&mutexdata);
			sem_post(&window);
			//pthread_yield();
			sched_yield();
			if (debug && debug_level > 0)
				printf("[debug cong crtl] increased window size\n");
			pthread_sleep(interval_secs);
			pthread_mutex_lock(&mutexdata);
		}
	}
	else // wrong char for congestion control
	{
		client_clean_exit(1);
	}

	pthread_exit(NULL);
	return NULL;
}