al_bp_error_t prepare_force_stop_bundle(al_bp_bundle_object_t * start, al_bp_endpoint_id_t monitor,
		al_bp_timeval_t expiration, al_bp_bundle_priority_t priority)
{
	FILE * start_stream;
	HEADER_TYPE start_header = FORCE_STOP_HEADER;
	al_bp_endpoint_id_t none;
	al_bp_bundle_delivery_opts_t opts = BP_DOPTS_NONE;
	al_bp_bundle_set_payload_location(start, BP_PAYLOAD_MEM);
	open_payload_stream_write(*start, &start_stream);
	fwrite(&start_header, HEADER_SIZE, 1, start_stream);
	close_payload_stream_write(start, start_stream);
	al_bp_bundle_set_dest(start, monitor);
	al_bp_get_none_endpoint(&none);
	al_bp_bundle_set_replyto(start, none);
	al_bp_bundle_set_delivery_opts(start, opts);
	al_bp_bundle_set_expiration(start, expiration);
	al_bp_bundle_set_priority(start, priority);
	return BP_SUCCESS;
}
al_bp_error_t prepare_stop_bundle(al_bp_bundle_object_t * stop, al_bp_endpoint_id_t monitor,
		al_bp_timeval_t expiration, al_bp_bundle_priority_t priority, int sent_bundles)
{
	FILE * stop_stream;
	HEADER_TYPE stop_header = STOP_HEADER;
	al_bp_endpoint_id_t none;
	uint32_t buf;
	al_bp_bundle_delivery_opts_t opts = BP_DOPTS_NONE;
	al_bp_bundle_set_payload_location(stop, BP_PAYLOAD_MEM);
	open_payload_stream_write(*stop, &stop_stream);
	fwrite(&stop_header, HEADER_SIZE, 1, stop_stream);
	buf = htonl(sent_bundles);
	fwrite(&buf, sizeof(buf), 1, stop_stream);
	close_payload_stream_write(stop, stop_stream);
	al_bp_bundle_set_dest(stop, monitor);
	al_bp_get_none_endpoint(&none);
	al_bp_bundle_set_replyto(stop, none);
	al_bp_bundle_set_delivery_opts(stop, opts);
	al_bp_bundle_set_expiration(stop, expiration);
	al_bp_bundle_set_priority(stop, priority);
	return BP_SUCCESS;
}
Пример #3
0
/*  ----------------------------
 *          CLIENT CODE
 *  ---------------------------- */
void run_dtnperf_client(dtnperf_global_options_t * perf_g_opt)
{
	/* ------------------------
	 * variables
	 * ------------------------ */
	char * client_demux_string;
	int pthread_status;

	char temp1[256]; // buffer for different purpose
	char temp2[256];
	FILE * stream; // stream for preparing payolad
	bp_bundle_object_t bundle_stop;
	monitor_parameters_t mon_params;


	/* ------------------------
	 * initialize variables
	 * ------------------------ */
	perf_opt = perf_g_opt->perf_opt;
	conn_opt = perf_g_opt->conn_opt;
	boolean_t debug = perf_opt->debug;
	int debug_level =  perf_opt->debug_level;
	boolean_t verbose = perf_opt->verbose;
	boolean_t create_log = perf_opt->create_log;
	log_open = FALSE;
	bp_handle_open = FALSE;
	source_file_created = FALSE;
	stream = NULL;
	tot_bundles = 0;
	process_interrupted = FALSE;
	perf_opt->log_filename = correct_dirname(perf_opt->log_filename);
	source_file = (char*) malloc(strlen(SOURCE_FILE) + 7);
	sprintf(source_file, "%s_%d", SOURCE_FILE, getpid());

	// Create a new log file
	if (create_log)
	{
		if ((log_file = fopen(perf_opt->log_filename, "w")) == NULL)
		{
			fprintf(stderr, "fatal error opening log file\n");
			client_clean_exit(1);
		}
		log_open = TRUE;
	}

	// Connect to BP Daemon
	if ((debug) && (debug_level > 0))
		printf("[debug] opening connection to local BP daemon...");

	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)
	{
		fprintf(stderr, "fatal error opening bp handle: %s\n", bp_strerror(error));
		if (create_log)
			fprintf(log_file, "fatal error opening bp handle: %s\n", bp_strerror(error));
		client_clean_exit(1);
	}
	else
	{
		bp_handle_open = TRUE;
	}

	if ((debug) && (debug_level > 0))
		printf("done\n");

	// Ctrl+C handler
	signal(SIGINT, &client_handler);

	/* -----------------------------------------------------
	 *   initialize and parse bundle src/dest/replyto EIDs
	 * ----------------------------------------------------- */

	// append process id to the client demux string
	client_demux_string = malloc (strlen(CLI_EP_STRING) + 10);
	sprintf(client_demux_string, "%s_%d", CLI_EP_STRING, getpid());

	//build a local eid
	if(debug && debug_level > 0)
		printf("[debug] building a local eid...");
	bp_build_local_eid(handle, &local_eid, client_demux_string);
	if(debug && debug_level > 0)
		printf("done\n");
	if (debug)
		printf("Source     : %s\n", local_eid.uri);
	if (create_log)
		fprintf(log_file, "\nSource     : %s\n", local_eid.uri);

	// parse SERVER EID
	// append server demux string to destination eid
	strcat(perf_opt->dest_eid, SERV_EP_STRING);

	if (verbose)
		fprintf(stdout, "%s (local)\n", perf_opt->dest_eid);
	// parse
	error = bp_parse_eid_string(&dest_eid, perf_opt->dest_eid);

	if (error != BP_SUCCESS)
	{
		fprintf(stderr, "fatal error parsing bp EID: invalid eid string '%s'\n", perf_opt->dest_eid);
		if (create_log)
			fprintf(log_file, "\nfatal error parsing bp EID: invalid eid string '%s'", perf_opt->dest_eid);
		client_clean_exit(1);
	}

	if (debug)
		printf("Destination: %s\n", dest_eid.uri);

	if (create_log)
		fprintf(log_file, "Destination: %s\n", dest_eid.uri);


	// parse REPLY-TO (if none specified, same as the source)
	if (strlen(perf_opt->mon_eid) == 0)
	{
		char * ptr;
		ptr = strstr(local_eid.uri, CLI_EP_STRING);
		// copy from local eid only the uri (not the demux string)
		strncpy(perf_opt->mon_eid, local_eid.uri, ptr - local_eid.uri);

	}
	// append monitor demux string to replyto eid
	strcat(perf_opt->mon_eid, MON_EP_STRING);
	// parse
	error = bp_parse_eid_string(&mon_eid, perf_opt->mon_eid);
	if (error != BP_SUCCESS)
	{
		fprintf(stderr, "fatal error parsing bp EID: invalid eid string '%s'\n", perf_opt->dest_eid);
		if (create_log)
			fprintf(log_file, "\nfatal error parsing bp EID: invalid eid string '%s'", perf_opt->dest_eid);
		client_clean_exit(1);
	}
	if (debug)
		printf("Reply-to   : %s\n\n", mon_eid.uri);

	if (create_log)
		fprintf(log_file, "Reply-to   : %s\n\n", mon_eid.uri);

	if(create_log)
		fflush(log_file);

	// checking if there is a running monitor on this endpoint
	if(perf_g_opt->mode == DTNPERF_CLIENT_MONITOR)
	{
		if(debug && debug_level > 0)
			printf("[debug] checking for existing monitor on this endpoint...\n");
		error = bp_find_registration(handle, &mon_eid, &regid);
		if (error == BP_SUCCESS)
		{
			dedicated_monitor = FALSE;
			printf("there is already a monitor on this endpoint.\n");
			printf("regid 0x%x\n", (unsigned int) regid);
		}
		else
		{
			dedicated_monitor = TRUE;
			mon_params.client_id = getpid();
			mon_params.perf_g_opt = perf_g_opt;
			printf("there is not a monitor on this endpoint.\n");
			sprintf(temp1, "%s_%d", mon_eid.uri, mon_params.client_id);
			bp_parse_eid_string(&mon_eid, temp1);

			// start dedicated monitor
			if ((monitor_pid = fork()) == 0)
			{
				start_dedicated_monitor((void *) &mon_params);
				exit(0);
			}
			printf("started a new dedicated monitor\n");

		}
		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)));
		if (create_log)
			fprintf(log_file, "error creating registration: %d (%s)\n",
					error, bp_strerror(bp_errno(handle)));
		client_clean_exit(1);
	}
	if ((debug) && (debug_level > 0))
		printf(" done\n");
	if (debug)
		printf("regid 0x%x\n", (unsigned int) regid);
	if (create_log)
		fprintf(log_file, "regid 0x%x\n", (unsigned int) regid);

	// if bundle payload > MAX_MEM_PAYLOAD, then transfer a file
	if (!perf_opt->use_file && perf_opt->bundle_payload > MAX_MEM_PAYLOAD)
	{
		perf_opt->use_file = 1;
		perf_opt->bundle_payload = BP_PAYLOAD_FILE;
		if (verbose)
			printf("Payload %ld > %d: Using file instead of memory\n", perf_opt->bundle_payload, MAX_MEM_PAYLOAD);
		if (create_log)
			fprintf(log_file, "Payload %ld > %d: Using file instead of memory\n", perf_opt->bundle_payload, MAX_MEM_PAYLOAD);
	}

	/* ------------------------------------------------------------------------------
	 * select the operative-mode (between Time_Mode, Data_Mode and File_Mode)
	 * ------------------------------------------------------------------------------ */

	if (perf_opt->op_mode == 'T')	// Time mode
	{

		if (verbose)
			printf("Working in Time_Mode\n");

		if (create_log)
			fprintf(log_file, "Working in Time_Mode\n");

		if (verbose)
			printf("requested %d second(s) of transmission\n", perf_opt->transmission_time);

		if (create_log)
			fprintf(log_file, "requested %d second(s) of transmission\n", perf_opt->transmission_time);
	}
	else if (perf_opt->op_mode == 'D') // Data mode
	{
		if (verbose)
			printf("Working in Data_Mode\n");
		if (create_log)
			fprintf(log_file, "Working in Data_Mode\n");
		if (verbose)
			printf("requested transmission of %ld bytes of data\n", perf_opt->data_qty);
		if (create_log)
			fprintf(log_file, "requested transmission of %ld bytes of data\n", perf_opt->data_qty);
	}
	else if (perf_opt->op_mode == 'F') // File mode
	{
		if (verbose)
			printf("Working in File_Mode\n");
		if (create_log)
			fprintf(log_file, "Working in File_Mode\n");
		if (verbose)
			printf("requested transmission of file %s\n", perf_opt->F_arg);
		if (create_log)
			fprintf(log_file, "requested transmission of file %s\n", perf_opt->F_arg);

	}

	if (verbose)
		printf(" transmitting data %s\n", perf_opt->use_file ? "using a file" : "using memory");
	if (create_log)
		fprintf(log_file, " transmitting data %s\n", perf_opt->use_file ? "using a file" : "using memory");

	if (verbose)
		printf("%s based congestion control:\n", perf_opt->congestion_ctrl == 'w' ? "sliding window" : "rate");
	if (create_log)
		fprintf(log_file, "%s based congestion control:\n", perf_opt->congestion_ctrl == 'w' ? "sliding window" : "rate");
	if(perf_opt->congestion_ctrl == 'w')
	{
		if (verbose)
			printf("\twindow is %d bundles\n", perf_opt->window);
		if (create_log)
			fprintf(log_file, "\twindow is %d bundles\n", perf_opt->window);
	}
	else
	{
		if (verbose)
			printf("\trate is %ld %c\n", perf_opt->rate, perf_opt->rate_unit);
		if (create_log)
			fprintf(log_file, "\trate is %ld %c\n", perf_opt->rate, perf_opt->rate_unit);
	}
	if (verbose)
		printf("payload is %ld bytes\n", perf_opt->bundle_payload);
	if (create_log)
		fprintf(log_file, "payload is %ld bytes\n", perf_opt->bundle_payload);


	sent_bundles = 0;

	if (perf_opt->op_mode == 'D' || perf_opt->op_mode == 'F') // Data or File mode
	{
		if ((debug) && (debug_level > 0))
			printf("[debug] calculating how many bundles are needed...");

		if (perf_opt->op_mode == 'F') // File mode
		{
			struct stat file;
			if (stat(perf_opt->F_arg, &file) < 0)
			{
				fprintf(stderr, "couldn't stat file %s : %s", perf_opt->F_arg, strerror(errno));
				if (create_log)
					fprintf(log_file, "couldn't stat file %s : %s", perf_opt->F_arg, strerror(errno));
				client_clean_exit(1);
			}

			// get transfer file basename
			strcpy(temp1, perf_opt->F_arg);
			strcpy(temp2, basename(temp1));
			transfer_filename = malloc(strlen(temp2) + 1);
			strcpy(transfer_filename, temp2);

			transfer_filedim = file.st_size;
			tot_bundles += bundles_needed(transfer_filedim, get_file_fragment_size(perf_opt->bundle_payload, strlen(transfer_filename)));
		}
		else // Data mode
			tot_bundles += bundles_needed(perf_opt->data_qty, perf_opt->bundle_payload);

		if ((debug) && (debug_level > 0))
			printf(" n_bundles = %ld\n", tot_bundles);

	}


	// Create the file
	if (perf_opt->use_file)
	{
		// create the file
		if ((debug) && (debug_level > 0))
			printf("[debug] creating file %s...", source_file);

		stream = fopen(source_file,	"wb");

		if (stream == NULL)
		{
			fprintf(stderr, "ERROR: couldn't create file %s.\n \b Maybe you don't have permissions\n", source_file);

			if (create_log)
				fprintf(log_file, "ERROR: couldn't create file %s.\n \b Maybe you don't have permissions\n", source_file);

			client_clean_exit(2);
		}

		source_file_created = TRUE;

		fclose(stream);

		if ((debug) && (debug_level > 0))
			printf(" done\n");

		// set the absolute path of the source file
		char buf[256];
		getcwd(buf, 256);
		strcat(buf, "/");
		strcat(buf, source_file);
		source_file_abs = malloc(strlen(buf) + 1);
		strncpy(source_file_abs, buf, strlen(buf) + 1);
	}

	// Create the bundle object
	if ((debug) && (debug_level > 0))
		printf("[debug] creating the bundle object...");
	error = bp_bundle_create(& bundle);
	if (error != BP_SUCCESS)
	{
		fprintf(stderr, "ERROR: couldn't create bundle object\n");

		if (create_log)
			fprintf(log_file, "ERROR: couldn't create bundle object\n");
		client_clean_exit(1);
	}
	if ((debug) && (debug_level > 0))
		printf(" done\n");

	// Fill the payload
	if ((debug) && (debug_level > 0))
		printf("[debug] filling payload...");

	if (perf_opt->use_file)
		error = bp_bundle_set_payload_file(&bundle, source_file_abs, strlen(source_file_abs));
	else
		error = bp_bundle_set_payload_mem(&bundle, buffer, bufferLen);
	if (error != BP_SUCCESS)
	{
		fprintf(stderr, "ERROR: couldn't set bundle payload\n");

		if (create_log)
			fprintf(log_file, "ERROR: couldn't set bundle payload\n");
		client_clean_exit(1);
	}
	if ((debug) && (debug_level > 0))
		printf(" done\n");


	// open payload stream in write mode
	if (open_payload_stream_write(bundle, &stream) < 0)
	{
		fprintf(stderr, "ERROR: couldn't open payload stream in write mode");

		if (create_log)
			fprintf(log_file, "ERROR: couldn't open payload stream in write mode");

		client_clean_exit(2);
	}

	// prepare the payload
	if(perf_opt->op_mode == 'F') // File mode
	{
		// payload will be prepared into send_bundles() cycle

		// open file to transfer in read mode
		if ((transfer_fd = open(perf_opt->F_arg, O_RDONLY)) < 0)
		{
			fprintf(stderr, "couldn't stat file %s : %s", perf_opt->F_arg, strerror(errno));
			if (create_log)
				fprintf(log_file, "couldn't stat file %s : %s", perf_opt->F_arg, strerror(errno));
			client_clean_exit(2);
		}
	}
	else // Time and Data mode
	{
		error = prepare_generic_payload(perf_opt, stream, perf_opt->bundle_payload);
		if (error != BP_SUCCESS)
		{
			fprintf(stderr, "error preparing payload: %s\n", bp_strerror(error));
			if (create_log)
				fprintf(log_file, "error preparing payload: %s\n", bp_strerror(error));
			client_clean_exit(1);
		}
	}

	// close the stream
	close_payload_stream_write(&bundle, stream);

	if(debug)
		printf("[debug] payload prepared");

	// Create the array for the bundle send info (only for sliding window congestion control)
	if (perf_opt->congestion_ctrl == 'w') {
		if ((debug) && (debug_level > 0))
			printf("[debug] creating structure for sending information...");

		send_info = (send_information_t*) malloc(perf_opt->window * sizeof(send_information_t));
		init_info(send_info, perf_opt->window);

		if ((debug) && (debug_level > 0))
			printf(" done\n");
	}


	// Setting the bundle options
	bp_bundle_set_source(&bundle, local_eid);
	bp_bundle_set_dest(&bundle, dest_eid);
	bp_bundle_set_replyto(&bundle, mon_eid);
	set_bp_options(&bundle, conn_opt);

	// intialize stop bundle;
	bp_bundle_create(&bundle_stop);

	if ((debug) && (debug_level > 0))
		printf("[debug] entering in loop\n");

	// Run threads
	if (perf_opt->congestion_ctrl == 'w') // sliding window congestion control
		sem_init(&window, 0, perf_opt->window);
	else								// rate based congestion control
		sem_init(&window, 0, 0);


	sigset_t sigset;

	// blocking signals for the threads
	sigemptyset(&sigset);
	sigaddset(&sigset, SIGINT);
	sigaddset(&sigset, SIGUSR1);
	sigaddset(&sigset, SIGUSR2);
	pthread_sigmask(SIG_BLOCK, &sigset, NULL);


	pthread_cond_init(&cond_ackreceiver, NULL);
	pthread_mutex_init (&mutexdata, NULL);


	pthread_create(&sender, NULL, send_bundles, (void*)perf_g_opt);
	pthread_create(&cong_ctrl, NULL, congestion_control, (void*)perf_g_opt);
	pthread_create(&wait_for_signal, NULL, wait_for_sigint, (void*) client_demux_string);

	pthread_join(cong_ctrl, (void**)&pthread_status);
	pthread_join(sender, (void**)&pthread_status);

	pthread_mutex_destroy(&mutexdata);
	sem_destroy(&window);
	pthread_cond_destroy(&cond_ackreceiver);

	// if user sent Ctrl+C to the client,
	// let the wait_for_signal thread to terminate the execution
	if (process_interrupted)
		pause();

	if ((debug) && (debug_level > 0))
		printf("[debug] out from loop\n");

	// Get the TOTAL end time
	if ((debug) && (debug_level > 0))
		printf("[debug] getting total end-time...");

	gettimeofday(&end, NULL);

	if ((debug) && (debug_level > 0))
		printf(" end.tv_sec = %u sec\n", (u_int)end.tv_sec);

	// Print final report
	print_final_report(NULL);
	if(perf_opt->create_log)
		print_final_report(log_file);

	// fill the stop bundle
	prepare_stop_bundle(&bundle_stop, mon_eid, conn_opt->expiration, conn_opt->priority, sent_bundles);
	bp_bundle_set_source(&bundle_stop, local_eid);

	// send stop bundle to monitor
	if (debug)
		printf("sending the stop bundle to the monitor...");
	if ((error = bp_bundle_send(handle, regid, &bundle_stop)) != 0)
	{
		fprintf(stderr, "error sending the stop bundle: %d (%s)\n", error, bp_strerror(error));
		if (create_log)
			fprintf(log_file, "error sending the stop bundle: %d (%s)\n", error, bp_strerror(error));
		client_clean_exit(1);
	}
	if (debug)
		printf("done.\n");

	// waiting monitor stops
	if (dedicated_monitor)
	{
		printf("\nWaiting for dedicated monitor to stop...\n");
		wait(&monitor_status);
	}


	// Close the BP handle --
	if ((debug) && (debug_level > 0))
		printf("[debug] closing DTN handle...");

	if (bp_close(handle) != BP_SUCCESS)
	{
		fprintf(stderr, "fatal error closing bp handle: %s\n", strerror(errno));
		if (create_log)
			fprintf(log_file, "fatal error closing bp handle: %s\n", strerror(errno));
		client_clean_exit(1);
	}
	else
	{
		bp_handle_open = FALSE;
	}

	if ((debug) && (debug_level > 0))
		printf(" done\n");

	if (create_log)
	{
		fclose(log_file);
		log_open = FALSE;
	}

	// deallocate memory
	if (perf_opt->op_mode == 'F')
	{
		close(transfer_fd);
	}
	if (perf_opt->use_file)
	{
		remove(source_file);
		source_file_created = FALSE;

		if (debug && debug > 1)
		{
			printf("[debug] removed file %s\n", source_file);
		}
	}
	free((void*)buffer);
	free(client_demux_string);
	free(source_file_abs);
	free(source_file);
	free(transfer_filename);
	free(send_info);
	bp_bundle_free(&bundle);
	bp_bundle_free(&bundle_stop);


	if (perf_opt->create_log)
		printf("\nClient log saved: %s\n", perf_opt->log_filename);

	printf("\n");

	exit(0);
}
Пример #4
0
/**
 * Client Threads code
 */
void * send_bundles(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;
	boolean_t condition;
	boolean_t eof_reached;
	u32_t actual_payload;
	FILE * stream;

	// Initialize timer
	if ((debug) && (debug_level > 0))
		printf("[debug send thread] initializing timer...");
	if (create_log)
		fprintf(log_file, " initializing timer...");

	gettimeofday(&start, NULL);

	if ((debug) && (debug_level > 0))
		printf(" start.tv_sec = %d sec\n", (u_int)start.tv_sec);
	if (create_log)
		fprintf(log_file, " start.tv_sec = %d sec\n", (u_int)start.tv_sec);

	if (perf_opt->op_mode == 'T')		// TIME MODE
	{									// Calculate end-time
		if ((debug) && (debug_level > 0))
			printf("[debug send thread] calculating end-time...");

		if (create_log)
			fprintf(log_file, " calculating end-time...");

		end = set (0);
		end.tv_sec = start.tv_sec + perf_opt->transmission_time;

		if ((debug) && (debug_level > 0))
			printf(" end.tv_sec = %d sec\n", (u_int)end.tv_sec);

		if (create_log)
			fprintf(log_file, " end.tv_sec = %d sec\n", (u_int)end.tv_sec);
	}

	if ((debug) && (debug_level > 0))
		printf("[debug send thread] entering loop...\n");
	if (create_log)
		fprintf(log_file, " entering loop...\n");

	if (perf_opt->op_mode == 'T') 	// TIME MODE
	{								// init variables for loop and setting condition
		now.tv_sec = start.tv_sec;
		condition = now.tv_sec <= end.tv_sec;
	}
	else							// DATA and FILE MODE
	{								// setting condition for loop
		condition = sent_bundles < tot_bundles;
	}

	// send bundles loop
	while (condition)				//LOOP
	{
		// prepare payload if FILE MODE
		if (perf_opt->op_mode == 'F')
		{
			open_payload_stream_write(bundle, &stream);
			error = prepare_file_transfer_payload(perf_opt, stream, transfer_fd,
					transfer_filename, transfer_filedim, &eof_reached);
			close_payload_stream_write(&bundle, stream);
		}

		// prepare payload if last bundle of DATA MODE
		if (perf_opt->op_mode == 'D')
		{
			if (sent_bundles == tot_bundles - 1 && perf_opt->data_qty % perf_opt->bundle_payload != 0)
			{
				open_payload_stream_write(bundle, &stream);
				prepare_generic_payload(perf_opt, stream, perf_opt->data_qty % perf_opt->bundle_payload);
				close_payload_stream_write(&bundle, stream);
			}
		}

		// window debug
		if ((debug) && (debug_level > 1))
		{
			int cur;
			sem_getvalue(&window, &cur);
			printf("\t[debug send thread] window is %d\n", cur);
		}
		// wait for the semaphore
		sem_wait(&window);

		if (perf_opt->op_mode == 'T') 	// TIME MODE
		{								// force re-check of condition after the semaphore
			gettimeofday(&now, NULL);
			if (now.tv_sec > end.tv_sec)
				break;
		}

		// Send the bundle
		if (debug)
			printf("sending the bundle...");

		if (perf_opt->congestion_ctrl == 'w')
			pthread_mutex_lock(&mutexdata);

		if ((error = bp_bundle_send(handle, regid, &bundle)) != 0)
		{
			fprintf(stderr, "error sending bundle: %d (%s)\n", error, bp_strerror(error));
			if (create_log)
				fprintf(log_file, "error sending bundle: %d (%s)\n", error, bp_strerror(error));
			client_clean_exit(1);
		}
		if ((error = bp_bundle_get_id(bundle, &bundle_id)) != 0)
		{
			fprintf(stderr, "error getting bundle id: %s\n", bp_strerror(error));
			if (create_log)
				fprintf(log_file, "error getting bundle id: %s\n", bp_strerror(error));
			client_clean_exit(1);
		}
		if (debug)
			printf(" bundle sent\n");
		if ((debug) && (debug_level > 0))
			printf("\t[debug send thread] ");
		printf("bundle sent timestamp: %llu.%llu\n", (unsigned long long) bundle_id->creation_ts.secs, (unsigned long long) bundle_id->creation_ts.seqno);
		if (create_log)
			fprintf(log_file, "\t bundle sent timestamp: %llu.%llu\n", (unsigned long long) bundle_id->creation_ts.secs, (unsigned long long) bundle_id->creation_ts.seqno);

		// put bundle id in send_info (only windowed congestion control)
		if (perf_opt->congestion_ctrl == 'w') {
			gettimeofday(&bundle_sent, NULL);
			add_info(send_info, *bundle_id, bundle_sent, perf_opt->window);
			if ((debug) && (debug_level > 1))
				printf("\t[debug send thread] added info for sent bundle\n");
			pthread_cond_signal(&cond_ackreceiver);
			pthread_mutex_unlock(&mutexdata);
		}

		// Increment sent_bundles
		++sent_bundles;

		if ((debug) && (debug_level > 0))
			printf("\t[debug send thread] now bundles_sent is %d\n", sent_bundles);
		if (create_log)
			fprintf(log_file, "\t now bundles_sent is %d\n", sent_bundles);
		// Increment data_qty
		bp_bundle_get_payload_size(bundle, &actual_payload);
		sent_data += actual_payload;

		if (perf_opt->op_mode == 'T')	// TIME MODE
		{								// update time and condition
			gettimeofday(&now, NULL);
			condition = now.tv_sec <= end.tv_sec;
		}
		else							// DATA MODE
		{								// update condition
			condition = sent_bundles < tot_bundles;
		}
	} // while

	if ((debug) && (debug_level > 0))
		printf("[debug send thread] ...out from loop\n");
	if (create_log)
		fprintf(log_file, " ...out from loop\n");

	pthread_mutex_lock(&mutexdata);
	close_ack_receiver = 1;
	if (perf_opt->congestion_ctrl == 'r')
	{
		// terminate congestion control thread
		pthread_cancel(cong_ctrl);
	}
	else
	{
		pthread_cond_signal(&cond_ackreceiver);
	}
	pthread_mutex_unlock(&mutexdata);
	// close thread
	pthread_exit(NULL);

}