示例#1
0
//  Get fds and store them into user allocated memory. 
//  send_fd is for non-blocking send wire notifications.
//  receive_fd_ is for incoming back-channel protocol packets.
//  rdata_notify_fd_ is raised for waiting repair transmissions.
//  pending_notify_fd_ is for state driven events.
void zmq::pgm_socket_t::get_sender_fds (fd_t *send_fd_, fd_t *receive_fd_, 
    fd_t *rdata_notify_fd_, fd_t *pending_notify_fd_)
{
    socklen_t socklen;
    bool rc;

    zmq_assert (send_fd_);
    zmq_assert (receive_fd_);
    zmq_assert (rdata_notify_fd_);
    zmq_assert (pending_notify_fd_);

    socklen = sizeof (*send_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_SEND_SOCK, send_fd_, &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*receive_fd_));

    socklen = sizeof (*receive_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, receive_fd_,
        &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*receive_fd_));

    socklen = sizeof (*rdata_notify_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_REPAIR_SOCK, rdata_notify_fd_,
        &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*rdata_notify_fd_));

    socklen = sizeof (*pending_notify_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK,
        pending_notify_fd_, &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*pending_notify_fd_));
}
示例#2
0
文件: purinsend.c 项目: haoustc/dial
static
void*
nak_routine (
	void*		arg
	)
{
/* dispatch loop */
	pgm_sock_t* nak_sock = (pgm_sock_t*)arg;

	int efd = epoll_create (IP_MAX_MEMBERSHIPS);
	if (efd < 0) {
		fprintf (stderr, "epoll_create failed errno %i: \"%s\"", errno, strerror(errno));
	}

	int retval = pgm_epoll_ctl (nak_sock, efd, EPOLL_CTL_ADD, EPOLLIN);
	if (retval < 0) {
		fprintf (stderr, "pgm_epoll_ctl failed.");
	}

	struct epoll_event events[1];	/* wait for maximum 1 event */
	do {
		struct timeval tv;
		int timeout;
		char buf[4064];
		pgm_error_t* pgm_err = NULL;
		fprintf (stdout, "===========================L:%d\n", __LINE__);
		const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err);
		fprintf (stdout, "===========================L:%d\n", __LINE__);
		switch (status) {
		case PGM_IO_STATUS_TIMER_PENDING:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
			}
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
			}
		case PGM_IO_STATUS_WOULD_BLOCK:
block:
			timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */);
			break;

		default:
			if (pgm_err) {
				fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)");
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (1);

	return NULL;
}
示例#3
0
文件: pftp.c 项目: neeohw/pftp
static void *nak_routine(void *arg) {
    /* This thread makes sure we get the NAKs from the receivers */
    pgm_sock_t *pgm_sock = (pgm_sock_t*)arg;
    pgm_error_t* pgm_err = NULL;

    int fds = 0;
    fd_set readfds;
    char recv_buf[PGMBUF_SIZE];
    size_t bytes_read = 0;

    int run_receiver = m_run_receiver;
    while (run_receiver) {
        memset(&recv_buf, 0, PGMBUF_SIZE);
        bytes_read = 0;
        struct timeval tv;

        struct pgm_sockaddr_t from;
        socklen_t from_sz = sizeof(from);
        const int pgm_status = pgm_recvfrom(pgm_sock, recv_buf, PGMBUF_SIZE, MSG_DONTWAIT, &bytes_read, &from, &from_sz, &pgm_err);

        //PRINT_ERR("pgm_status: %d", pgm_status);
        switch (pgm_status) {
        case PGM_IO_STATUS_TIMER_PENDING:
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            goto block;
        }
        case PGM_IO_STATUS_RATE_LIMITED:
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            /* No accidental fallthrough! */
        }
block:
        case PGM_IO_STATUS_WOULD_BLOCK:
            FD_ZERO(&readfds);
            pgm_select_info(pgm_sock, &readfds, NULL, &fds);
            fds = select(fds, &readfds, NULL, NULL, pgm_status == PGM_IO_STATUS_WOULD_BLOCK ? NULL : &tv);
            break;
        default :
            if (pgm_err) {
                fprintf(stderr, "%s\n", pgm_err->message);
                pgm_error_free(pgm_err);
                pgm_err = NULL;
            }
            break;
        }
        pthread_mutex_lock(&m_pftp_mutex);
        run_receiver = m_run_receiver;
        pthread_mutex_unlock(&m_pftp_mutex);
    }
    pthread_exit(NULL);
}
示例#4
0
//  Return max TSDU size without fragmentation from current PGM transport.
size_t zmq::pgm_socket_t::get_max_tsdu_size ()
{
    int max_tsdu = 0;
    socklen_t optlen = sizeof (max_tsdu);

    bool rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_MSS, &max_tsdu, &optlen);
    zmq_assert (rc);
    zmq_assert (optlen == sizeof (max_tsdu));
    return (size_t) max_tsdu;
}
示例#5
0
//   Get receiver fds. receive_fd_ is signaled for incoming
//   packets, waiting_pipe_fd_ is signaled for state driven
//   events and data.
void zmq::pgm_socket_t::get_receiver_fds (int *receive_fd_, 
    int *waiting_pipe_fd_)
{
    socklen_t socklen;
    bool rc;

    zmq_assert (receive_fd_);
    zmq_assert (waiting_pipe_fd_);

    socklen = sizeof (*receive_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, receive_fd_, &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*receive_fd_));

    socklen = sizeof (*waiting_pipe_fd_);
    rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK, waiting_pipe_fd_, &socklen);
    zmq_assert (rc);
    zmq_assert (socklen == sizeof (*waiting_pipe_fd_));
}
示例#6
0
long zmq::pgm_socket_t::get_tx_timeout ()
{
    if (last_tx_status != PGM_IO_STATUS_RATE_LIMITED)
        return -1;

    struct timeval tv;
    socklen_t optlen = sizeof (tv);
    const bool rc = pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
    zmq_assert (rc);

    const long timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);

    return timeout;
}
示例#7
0
文件: daytime.c 项目: xjtuwjp/openpgm
unsigned
__stdcall
#endif
nak_routine (
	void*		arg
	)
{
/* dispatch loop */
	pgm_sock_t* nak_sock = (pgm_sock_t*)arg;
#ifndef _WIN32
	int fds;
	fd_set readfds;
#else
	SOCKET recv_sock, repair_sock, pending_sock;
	DWORD cEvents = PGM_SEND_SOCKET_READ_COUNT + 1;
	WSAEVENT waitEvents[ PGM_SEND_SOCKET_READ_COUNT + 1 ];
	DWORD dwTimeout, dwEvents;
	socklen_t socklen = sizeof (SOCKET);

	waitEvents[0] = terminateEvent;
	waitEvents[1] = WSACreateEvent();
	waitEvents[2] = WSACreateEvent();
	waitEvents[3] = WSACreateEvent();
	assert (3 == PGM_SEND_SOCKET_READ_COUNT);
	pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen);
	WSAEventSelect (recv_sock, waitEvents[1], FD_READ);
	pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_REPAIR_SOCK, &repair_sock, &socklen);
	WSAEventSelect (repair_sock, waitEvents[2], FD_READ);
	pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen);
	WSAEventSelect (pending_sock, waitEvents[3], FD_READ);
#endif /* !_WIN32 */
	do {
		struct timeval tv;
		char buf[4064];
		pgm_error_t* pgm_err = NULL;
		const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err);
		switch (status) {
		case PGM_IO_STATUS_TIMER_PENDING:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
			}
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
			}
		case PGM_IO_STATUS_WOULD_BLOCK:
block:
#ifndef _WIN32
			fds = terminate_pipe[0] + 1;
			FD_ZERO(&readfds);
			FD_SET(terminate_pipe[0], &readfds);
			pgm_select_info (nak_sock, &readfds, NULL, &fds);
			fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv);
#else
			dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE);
			switch (dwEvents) {
			case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break;
			case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break;
			case WSA_WAIT_EVENT_0+3: WSAResetEvent (waitEvents[3]); break;
			default: break;
			}
#endif /* !_WIN32 */
			break;

		default:
			if (pgm_err) {
				fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)");
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (!is_terminated);
#ifndef _WIN32
	return NULL;
#else
	WSACloseEvent (waitEvents[1]);
	WSACloseEvent (waitEvents[2]);
	WSACloseEvent (waitEvents[3]);
	_endthread();
	return 0;
#endif
}
示例#8
0
文件: pgmrecv.c 项目: xjtuwjp/openpgm
static
gpointer
receiver_thread (
	gpointer	data
	)
{
	pgm_sock_t* rx_sock = (pgm_sock_t*)data;
	const long iov_len = 20;
	const long ev_len  = 1;
	struct pgm_msgv_t msgv[iov_len];

#ifdef CONFIG_HAVE_EPOLL
	struct epoll_event events[ev_len];	/* wait for maximum 1 event */
	const int efd = epoll_create (IP_MAX_MEMBERSHIPS);
	if (efd < 0) {
		g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno));
		g_main_loop_quit (g_loop);
		return NULL;
	}

	if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0)
	{
		g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno));
		g_main_loop_quit (g_loop);
		return NULL;
	}
	struct epoll_event event;
	event.events = EPOLLIN;
	event.data.fd = g_quit_pipe[0];
	if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0)
	{
		g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno));
		g_main_loop_quit (g_loop);
		return NULL;
	}
#elif defined(CONFIG_HAVE_POLL)
	int n_fds = 2;
	struct pollfd fds[ 1 + n_fds ];
#elif defined(G_OS_UNIX) /* HAVE_SELECT */
	int n_fds;
	fd_set readfds;
#else /* G_OS_WIN32 */
	SOCKET recv_sock, pending_sock;
	DWORD cEvents = PGM_RECV_SOCKET_READ_COUNT + 1;
	WSAEVENT waitEvents[ PGM_RECV_SOCKET_READ_COUNT + 1 ];
	socklen_t socklen = sizeof (SOCKET);

	waitEvents[0] = g_quit_event;
	waitEvents[1] = WSACreateEvent ();
	pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen);
	WSAEventSelect (recv_sock, waitEvents[1], FD_READ);
	waitEvents[2] = WSACreateEvent ();
	pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen);
	WSAEventSelect (pending_sock, waitEvents[2], FD_READ);
#endif /* !CONFIG_HAVE_EPOLL */

	do {
		struct timeval tv;
#ifndef _WIN32
		int timeout;
#else
		DWORD dwTimeout, dwEvents;
#endif
		size_t len;
		pgm_error_t* pgm_err = NULL;
		const int status = pgm_recvmsgv (rx_sock,
					         msgv,
					         G_N_ELEMENTS(msgv),
					         0,
					         &len,
					         &pgm_err);
		switch (status) {
		case PGM_IO_STATUS_NORMAL:
			on_msgv (msgv, len);
			break;
		case PGM_IO_STATUS_TIMER_PENDING:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
			}
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
			}
/* fall through */
		case PGM_IO_STATUS_WOULD_BLOCK:
block:
#ifdef CONFIG_HAVE_EPOLL
			timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */);
#elif defined(CONFIG_HAVE_POLL)
			timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			memset (fds, 0, sizeof(fds));
			fds[0].fd = g_quit_pipe[0];
			fds[0].events = POLLIN;
			pgm_poll_info (rx_sock, &fds[1], &n_fds, POLLIN);
			poll (fds, 1 + n_fds, timeout /* ms */);
#elif defined(G_OS_UNIX) /* HAVE_SELECT */
			FD_ZERO(&readfds);
			FD_SET(g_quit_pipe[0], &readfds);
			n_fds = g_quit_pipe[0] + 1;
			pgm_select_info (rx_sock, &readfds, NULL, &n_fds);
			select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL);
#else /* G_OS_WIN32 */
			dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE);
			switch (dwEvents) {
			case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break;
			case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break;
			default: break;
			}
#endif /* !CONFIG_HAVE_EPOLL */
			break;

		default:
			if (pgm_err) {
				g_warning ("%s", pgm_err->message);
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (!g_quit);

#ifdef CONFIG_HAVE_EPOLL
	close (efd);
#elif defined(G_OS_WIN32)
	WSACloseEvent (waitEvents[1]);
	WSACloseEvent (waitEvents[2]);
#  if (__STDC_VERSION__ < 199901L)
	g_free (waitHandles);
#  endif
#endif
	return NULL;
}
int
main (
	int		argc,
	char*		argv[]
	)
{
	pgm_error_t* pgm_err = NULL;

	setlocale (LC_ALL, "");

	log_init ();
	g_message ("enonblocksyncrecvmsgv");

	if (!pgm_init (&pgm_err)) {
		g_error ("Unable to start PGM engine: %s", pgm_err->message);
		pgm_error_free (pgm_err);
		return EXIT_FAILURE;
	}

/* parse program arguments */
	const char* binary_name = strrchr (argv[0], '/');
	int c;
	while ((c = getopt (argc, argv, "s:n:p:lh")) != -1)
	{
		switch (c) {
		case 'n':	g_network = optarg; break;
		case 's':	g_port = atoi (optarg); break;
		case 'p':	g_udp_encap_port = atoi (optarg); break;
		case 'l':	g_multicast_loop = TRUE; break;

		case 'h':
		case '?': usage (binary_name);
		}
	}

/* setup signal handlers */
	signal (SIGSEGV, on_sigsegv);
	signal (SIGINT,  on_signal);
	signal (SIGTERM, on_signal);
#ifdef SIGHUP
	signal (SIGHUP,  SIG_IGN);
#endif

	if (!on_startup ()) {
		g_error ("startup failed");
		return EXIT_FAILURE;
	}

/* incoming message buffer, iov_len must be less than SC_IOV_MAX */
	const long iov_len = 8;
	const long ev_len  = 1;
	g_message ("Using iov_len %li ev_len %li", iov_len, ev_len);

	struct pgm_msgv_t msgv[iov_len];
	struct epoll_event events[ev_len];	/* wait for maximum 1 event */

/* epoll file descriptor */
	const int efd = epoll_create (IP_MAX_MEMBERSHIPS);
	if (efd < 0) {
		g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno));
		return EXIT_FAILURE;
	}

	const int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN);
	if (retval < 0) {
		g_error ("pgm_epoll_ctl failed.");
		return EXIT_FAILURE;
	}

/* dispatch loop */
	g_message ("entering PGM message loop ... ");
	do {
		struct timeval tv;
		int timeout;
		size_t len;
		const int status = pgm_recvmsgv (g_sock,
					         msgv,
					         iov_len,
						 0,
					         &len,
					         &pgm_err);
		switch (status) {
		case PGM_IO_STATUS_NORMAL:
			on_msgv (msgv, len);
			break;

		case PGM_IO_STATUS_TIMER_PENDING:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
			}
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
			}
/* fall through */
		case PGM_IO_STATUS_WOULD_BLOCK:
/* poll for next event */
block:
			timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 :  ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */);
			break;

		default:
			if (pgm_err) {
				g_warning ("%s", pgm_err->message);
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (!g_quit);

	g_message ("message loop terminated, cleaning up.");

/* cleanup */
	close (efd);
	if (g_sock) {
		g_message ("closing PGM socket.");
		pgm_close (g_sock, TRUE);
		g_sock = NULL;
	}

	g_message ("PGM engine shutdown.");
	pgm_shutdown ();
	g_message ("finished.");
	return EXIT_SUCCESS;
}
示例#10
0
int
main (
	int		argc,
	char*		argv[]
	)
{
	pgm_error_t* pgm_err = NULL;

	setlocale (LC_ALL, "");

#ifndef _WIN32
	puts ("プリン プリン");
#else
	_putws (L"プリン プリン");
#endif

	if (!pgm_init (&pgm_err)) {
		fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message);
		pgm_error_free (pgm_err);
		return EXIT_FAILURE;
	}

/* parse program arguments */
	const char* binary_name = strrchr (argv[0], '/');
	int c;
	while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1)
	{
		switch (c) {
		case 'n':	network = optarg; break;
		case 's':	port = atoi (optarg); break;
		case 'p':	udp_encap_port = atoi (optarg); break;
		case 'f':	use_fec = TRUE; break;
		case 'K':	rs_k = atoi (optarg); break;
		case 'N':	rs_n = atoi (optarg); break;
		case 'l':	use_multicast_loop = TRUE; break;

		case 'i':
			pgm_if_print_all();
			return EXIT_SUCCESS;

		case 'h':
		case '?': usage (binary_name);
		}
	}

	if (use_fec && ( !rs_n || !rs_k )) {
		fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k);
		usage (binary_name);
	}

/* setup signal handlers */
#ifdef SIGHUP
	signal (SIGHUP,  SIG_IGN);
#endif
#ifndef _WIN32
	int e = pipe (terminate_pipe);
	assert (0 == e);
	signal (SIGINT,  on_signal);
	signal (SIGTERM, on_signal);
#else
	terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent"));
	SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE);
#endif /* !_WIN32 */

	if (!on_startup()) {
		fprintf (stderr, "Startup failed\n");
		return EXIT_FAILURE;
	}

/* dispatch loop */
#ifndef _WIN32
	int fds;
	fd_set readfds;
#else
	int n_handles = 3, recv_sock, pending_sock;
	HANDLE waitHandles[ 3 ];
	DWORD dwTimeout, dwEvents;
	WSAEVENT recvEvent, pendingEvent;

	recvEvent = WSACreateEvent ();
	pgm_getsockopt (sock, PGM_RECV_SOCK, &recv_sock, sizeof(recv_sock));
	WSAEventSelect (recv_sock, recvEvent, FD_READ);
	pendingEvent = WSACreateEvent ();
	pgm_getsockopt (sock, PGM_PENDING_SOCK, &pending_sock, sizeof(pending_sock));
	WSAEventSelect (pending_sock, pendingEvent, FD_READ);

	waitHandles[0] = terminate_event;
	waitHandles[1] = recvEvent;
	waitHandles[2] = pendingEvent;
#endif /* !_WIN32 */
	puts ("Entering PGM message loop ... ");
	do {
		struct timeval tv;
		char buffer[4096];
		size_t len;
		pgm_tsi_t from;
		const int status = pgm_recvfrom (sock,
					         buffer,
					         sizeof(buffer),
					         0,
					         &len,
					         &from,
					         &pgm_err);
		switch (status) {
		case PGM_IO_STATUS_NORMAL:
			on_data (buffer, len, &from);
			break;
		case PGM_IO_STATUS_TIMER_PENDING:
			pgm_getsockopt (sock, PGM_TIME_REMAIN, &tv, sizeof(tv));
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			pgm_getsockopt (sock, PGM_RATE_REMAIN, &tv, sizeof(tv));
		case PGM_IO_STATUS_WOULD_BLOCK:
/* select for next event */
block:
#ifndef _WIN32
			fds = terminate_pipe[0] + 1;
			FD_ZERO(&readfds);
			FD_SET(terminate_pipe[0], &readfds);
			pgm_select_info (sock, &readfds, NULL, &fds);
			fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv);
#else
			dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout);
			switch (dwEvents) {
			case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break;
			case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break;
			default: break;
			}
#endif /* !_WIN32 */
			break;

		default:
			if (pgm_err) {
				fprintf (stderr, "%s\n", pgm_err->message);
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (!is_terminated);

	puts ("Message loop terminated, cleaning up.");

/* cleanup */
#ifndef _WIN32
	close (terminate_pipe[0]);
	close (terminate_pipe[1]);
#else
	WSACloseEvent (recvEvent);
	WSACloseEvent (pendingEvent);
	CloseHandle (terminate_event);
#endif /* !_WIN32 */

	if (sock) {
		puts ("Destroying PGM socket.");
		pgm_close (sock, TRUE);
		sock = NULL;
	}

	puts ("PGM engine shutdown.");
	pgm_shutdown ();
	puts ("finished.");
	return EXIT_SUCCESS;
}
示例#11
0
int
main (
	int		argc,
	char*		argv[]
	)
{
	pgm_error_t* pgm_err = NULL;

	setlocale (LC_ALL, "");

#if !defined(_WIN32)
	puts ("プリン プリン");
#else
/* Windows consoles have incredibly limited Unicode support */
	puts ("purin purin");
#endif
	if (!pgm_init (&pgm_err)) {
		fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message);
		pgm_error_free (pgm_err);
		return EXIT_FAILURE;
	}

/* parse program arguments */
#ifdef _WIN32
	const char* binary_name = strrchr (argv[0], '\\');
#else
	const char* binary_name = strrchr (argv[0], '/');
#endif
	if (NULL == binary_name)	binary_name = argv[0];
	else				binary_name++;

	int c;
	while ((c = getopt (argc, argv, "s:n:p:cf:K:N:lih")) != -1)
	{
		switch (c) {
		case 'n':	network = optarg; break;
		case 's':	port = atoi (optarg); break;
		case 'p':	udp_encap_port = atoi (optarg); break;
		case 'c':	use_pgmcc = TRUE; break;
		case 'f':	use_fec = TRUE; break;
		case 'K':	rs_k = atoi (optarg); break;
		case 'N':	rs_n = atoi (optarg); break;
		case 'l':	use_multicast_loop = TRUE; break;

		case 'i':
			pgm_if_print_all();
			return EXIT_SUCCESS;

		case 'h':
		case '?': usage (binary_name);
		}
	}

	if (use_fec && ( !rs_n || !rs_k )) {
		fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k);
		usage (binary_name);
	}

/* setup signal handlers */
#ifdef SIGHUP
	signal (SIGHUP,  SIG_IGN);
#endif
#ifndef _WIN32
	int e = pipe (terminate_pipe);
	assert (0 == e);
	signal (SIGINT,  on_signal);
	signal (SIGTERM, on_signal);
#else
	terminateEvent = WSACreateEvent();
	SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE);
	setvbuf (stdout, (char *) NULL, _IONBF, 0);
#endif /* !_WIN32 */

	if (!on_startup()) {
		fprintf (stderr, "Startup failed\n");
		return EXIT_FAILURE;
	}

/* dispatch loop */
#ifndef _WIN32
	int fds;
	fd_set readfds;
#else
	SOCKET recv_sock, pending_sock;
	DWORD cEvents = PGM_RECV_SOCKET_READ_COUNT + 1;
	WSAEVENT waitEvents[ PGM_RECV_SOCKET_READ_COUNT + 1 ];
	socklen_t socklen = sizeof (SOCKET);

	waitEvents[0] = terminateEvent;
	waitEvents[1] = WSACreateEvent();
	waitEvents[2] = WSACreateEvent();
	assert (2 == PGM_RECV_SOCKET_READ_COUNT);
	pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen);
	WSAEventSelect (recv_sock, waitEvents[1], FD_READ);
	pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen);
	WSAEventSelect (pending_sock, waitEvents[2], FD_READ);
#endif /* !_WIN32 */
	puts ("Entering PGM message loop ... ");
	do {
		struct timeval tv;
#ifdef _WIN32
		DWORD dwTimeout, dwEvents;
#endif
		char buffer[4096];
		size_t len;
		struct pgm_sockaddr_t from;
		socklen_t fromlen = sizeof (from);
		const int status = pgm_recvfrom (sock,
					         buffer,
					         sizeof(buffer),
					         0,
					         &len,
					         &from,
						 &fromlen,
					         &pgm_err);
		switch (status) {
		case PGM_IO_STATUS_NORMAL:
			on_data (buffer, len, &from);
			break;
		case PGM_IO_STATUS_TIMER_PENDING:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
			}
			goto block;
		case PGM_IO_STATUS_RATE_LIMITED:
			{
				socklen_t optlen = sizeof (tv);
				pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
			}
		case PGM_IO_STATUS_WOULD_BLOCK:
/* select for next event */
block:
#ifndef _WIN32
			fds = terminate_pipe[0] + 1;
			FD_ZERO(&readfds);
			FD_SET(terminate_pipe[0], &readfds);
			pgm_select_info (sock, &readfds, NULL, &fds);
			fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv);
#else
			dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
			dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE);
			switch (dwEvents) {
			case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break;
			case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break;
			default: break;
			}
#endif /* !_WIN32 */
			break;

		default:
			if (pgm_err) {
				fprintf (stderr, "%s\n", pgm_err->message);
				pgm_error_free (pgm_err);
				pgm_err = NULL;
			}
			if (PGM_IO_STATUS_ERROR == status)
				break;
		}
	} while (!is_terminated);

	puts ("Message loop terminated, cleaning up.");

/* cleanup */
#ifndef _WIN32
	close (terminate_pipe[0]);
	close (terminate_pipe[1]);
#else
	WSACloseEvent (waitEvents[0]);
	WSACloseEvent (waitEvents[1]);
	WSACloseEvent (waitEvents[2]);
#endif /* !_WIN32 */

	if (sock) {
		puts ("Destroying PGM socket.");
		pgm_close (sock, TRUE);
		sock = NULL;
	}

	puts ("PGM engine shutdown.");
	pgm_shutdown ();
	puts ("finished.");
	return EXIT_SUCCESS;
}
示例#12
0
文件: pftpd.c 项目: neeohw/pftp
int main( int argc, char *argv[]) {
    int c = 0;
    int port = 0;
    int run_state = STATE_WAIT_CMD;
    char network[128];
    char *iface = NULL;
    char *mcast_addr = NULL;

    network[0] = '\0';

    pgm_error_t* pgm_err = NULL;
    pgm_sock_t *pgm_sock = NULL;

    signal(SIGINT, handle_sigint);

    while((c = getopt(argc, argv, "hm:i:p:")) != -1) {
        switch (c) {
        case 'm':
            mcast_addr = optarg;
            break;
        case 'i':
            iface = optarg;
            break;
        case 'p':
            port = atoi(optarg);
            break;
        case 'h':
        case '?':
            print_usage();
            break;
        default:
            print_usage();
            break;
        }
    }

#ifdef UDPTEST
    int sockfd = 0;
    struct sockaddr_in servaddr;
    struct ip_mreqn mreq;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = port ? htons(port) : htons(PFTP_UDP_PORT);

    if (0 != bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) ) {
        PRINT_ERR("Couldn't bind socket!");
        return -1;
    }

    memset(&mreq, 0, sizeof(mreq));
    char *ifaddr = NULL;
    if (iface) {
        ifaddr = pftp_inet_iftoa(iface);
    } else {
        ifaddr = pftp_inet_iftoa("eth0");
    }

    mreq.imr_address.s_addr = inet_addr(ifaddr);
    mreq.imr_ifindex = 0;
    if (ifaddr) free(ifaddr);

    if (mcast_addr) {
        mreq.imr_multiaddr.s_addr = inet_addr(mcast_addr);
    } else {
        mreq.imr_multiaddr.s_addr = inet_addr(PFTP_DEFAULT_MCAST_ADDR);
    }

    if (0 != setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
        PRINT_ERR("Couldn't join multicast group!: %s" ,strerror(errno));
    }

#else
    if (iface) {
        char *ifaddr = pftp_inet_iftoa(iface);
        if (strlen(ifaddr) > 0) {
            strncat(network, ifaddr, 128);
            strncat(network, ";", 128);
        } else {
            free(ifaddr);
            return -1;
        }
        free(ifaddr);
    }

    if (mcast_addr) {
        strncat(network, mcast_addr, 128);
    } else {
        strncat(network, PFTP_DEFAULT_MCAST_ADDR, 128);
    }

    if (0 != pftp_create(0, network, port, &pgm_sock)) {
        return -1;
    }
#endif

    PRINT_DBG("Running receive loop");
    int fds = 0;
    fd_set readfds;
    int file_desc = -1;
    int total_bytes = 0;
    void *cmd_info = NULL;

    m_run_receive_loop = 1;

    while (m_run_receive_loop) {

        char recv_buf[PGMBUF_SIZE];
        memset(&recv_buf, 0, PGMBUF_SIZE);
        size_t bytes_read = 0;

#ifdef UDPTEST
        fds = sockfd + 1;

        bytes_read = recv(sockfd, recv_buf, PGMBUF_SIZE, MSG_DONTWAIT);

        switch (bytes_read) {
        case -1:
            if (errno == EWOULDBLOCK || errno == EAGAIN) {
                FD_ZERO(&readfds);
                FD_SET(sockfd, &readfds);
                select(fds, &readfds, NULL, NULL, NULL);
            }
            break;
        default:
        {
#else
        struct timeval tv;

        struct pgm_sockaddr_t from;
        socklen_t from_sz = sizeof(from);
        const int pgm_status = pgm_recvfrom(pgm_sock, recv_buf, PGMBUF_SIZE, MSG_DONTWAIT, &bytes_read, &from, &from_sz, &pgm_err);

        //PRINT_DBG("pgm_status: %d", pgm_status);
        switch (pgm_status) {

        case PGM_IO_STATUS_NORMAL :
        {
#endif
            int cmd_parsed = pftp_parse_cmd(recv_buf, &cmd_info);

            switch(cmd_parsed) {

            case PFTP_CMD_UNKNOWN :
                if (  run_state == STATE_FILE_TRANSFER
                   && file_desc > 0 ) {
                    write(file_desc, recv_buf, bytes_read);
                    total_bytes += bytes_read;
                    if (total_bytes >= ((struct pftp_send_file_cmd*)cmd_info)->fsize) {
                        PRINT_DBG("File %s received.", ((struct pftp_send_file_cmd*)cmd_info)->fname);
                        close(file_desc);
                        total_bytes = 0;
                        pftp_free_cmd(cmd_info);
                        run_state = STATE_WAIT_CMD;
                    }
                }
                break;

            case PFTP_CMD_SEND_FILE_PARSED :
            {
                struct pftp_send_file_cmd *sf_cmd = (struct pftp_send_file_cmd *)cmd_info;
                file_desc = open(sf_cmd->fname, O_CREAT | O_WRONLY, S_IRWXU);
                if (file_desc < 0) {
                    PRINT_ERR("Couldn't open file for writing! %s", strerror(errno));
                    pftp_free_cmd(cmd_info);
                    run_state = STATE_WAIT_CMD;
                } else {
                    run_state = STATE_FILE_TRANSFER;
                }

            } break;

            default :
                pftp_free_cmd(cmd_info);
                break;
            }

#ifdef UDPTEST
        } break;
        }
#else
        } break;
        case PGM_IO_STATUS_TIMER_PENDING:
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            goto block;
        }
        case PGM_IO_STATUS_RATE_LIMITED:
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            /* No accidental fallthrough! */
        }
        case PGM_IO_STATUS_WOULD_BLOCK:
block:
            FD_ZERO(&readfds);
            pgm_select_info(pgm_sock, &readfds, NULL, &fds);
            fds = select(fds, &readfds, NULL, NULL, pgm_status == PGM_IO_STATUS_WOULD_BLOCK ? NULL : &tv);
            break;
        case PGM_IO_STATUS_RESET:
            if (pgm_err) {
                fprintf(stderr, "%s\n", pgm_err->message);
                pgm_error_free(pgm_err);
                pgm_err = NULL;
            }
            close(file_desc);
            total_bytes = 0;
            run_state = STATE_WAIT_CMD;
            break;
        default :
            if (pgm_err) {
                fprintf(stderr, "%s\n", pgm_err->message);
                pgm_error_free(pgm_err);
                pgm_err = NULL;
            }
            if (pgm_status == PGM_IO_STATUS_ERROR) {
                m_run_receive_loop = 0;
            } else {
                PRINT_ERR("Unknown status!");
                m_run_receive_loop = 0;
            }
            break;
        }
#endif
    }

    if (file_desc > 0)
        close(file_desc);
    PRINT_DBG("Receive loop finished");

#ifdef UDPTEST
    if (sockfd > 0)
        close(sockfd);
#else
    if (pgm_sock) {
        pftp_stop(pgm_sock);
    }
#endif

    return 0;
}
示例#13
0
文件: pgm_rx.cpp 项目: romixlab/trunk
void PGMNetwork::doWork()
{
    /* dispatch loop */
#ifndef _WIN32
    int fds;
    fd_set readfds;


#else
    SOCKET recv_sock, pending_sock;
    DWORD cEvents = PGM_RECV_SOCKET_READ_COUNT + 1;
    WSAEVENT waitEvents[ PGM_RECV_SOCKET_READ_COUNT + 1 ];
    socklen_t socklen = sizeof (SOCKET);

    waitEvents[0] = terminateEvent;
    waitEvents[1] = WSACreateEvent();
    waitEvents[2] = WSACreateEvent();
    assert (2 == PGM_RECV_SOCKET_READ_COUNT);
    pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen);
    WSAEventSelect (recv_sock, waitEvents[1], FD_READ);
    pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen);
    WSAEventSelect (pending_sock, waitEvents[2], FD_READ);

    static WSAEVENT		terminateEvent;
#endif /* !_WIN32 */

    pgm_error_t* pgm_err = NULL;
    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    qDebug() << "Entering PGM message loop..." << QThread::currentThreadId();

    do {

#ifdef _WIN32
        DWORD dwTimeout, dwEvents;
#endif
        char buffer[4096];
        size_t len;
        struct pgm_sockaddr_t from;
        socklen_t fromlen = sizeof (from);
        const int status = pgm_recvfrom (m_socket,
                                         buffer,
                                         4096,
                                         0,
                                         &len,
                                         &from,
                                         &fromlen,
                                         &pgm_err);
        switch (status) {
        case PGM_IO_STATUS_NORMAL:
        {
            QByteArray ba(buffer, len);
            emit rx(ba);

            break;
        }
        case PGM_IO_STATUS_TIMER_PENDING:
        {
            socklen_t optlen = sizeof (tv);
            pgm_getsockopt (m_socket, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
        }
            goto block;
        case PGM_IO_STATUS_RATE_LIMITED:
        {
            socklen_t optlen = sizeof (tv);
            pgm_getsockopt (m_socket, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
        }
        case PGM_IO_STATUS_WOULD_BLOCK:
            /* select for next event */
block:
#ifndef _WIN32
            fds = m_terminate_pipe[0] + 1;
            FD_ZERO(&readfds);
            FD_SET(m_terminate_pipe[0], &readfds);
            pgm_select_info (m_socket, &readfds, NULL, &fds);
            fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv);
#else
            dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? WSA_INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
            dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, dwTimeout, FALSE);
            switch (dwEvents) {
            case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break;
            case WSA_WAIT_EVENT_0+2: WSAResetEvent (waitEvents[2]); break;
            default: break;
            }
#endif /* !_WIN32 */
            break;

        default:
            if (pgm_err) {
                qDebug() << "pgm error:" << pgm_err->message;
                pgm_error_free (pgm_err);
                pgm_err = NULL;
            }
            if (PGM_IO_STATUS_ERROR == status)
                break;
        }

        QCoreApplication::processEvents();
    } while (!m_is_terminated);

    qDebug() << "Message loop terminated, cleaning up.";

    /* cleanup */
#ifndef _WIN32
    close (m_terminate_pipe[0]);
    close (m_terminate_pipe[1]);
#else
    WSACloseEvent (waitEvents[0]);
    WSACloseEvent (waitEvents[1]);
    WSACloseEvent (waitEvents[2]);
#endif /* !_WIN32 */

    this->thread()->quit();
}
示例#14
0
文件: pftp.c 项目: neeohw/pftp
int main( int argc, char *argv[]) {
    int c = 0;
    int ret_val = 0;
    int port = 0;
    char network[128];
    char *file = NULL;
    char *iface = NULL;
    char *mcast_addr = NULL;
    int bfd = 0;
    network[0] = '\0';

#ifdef UDPTEST
    int sockfd = 0;
#else
    pgm_error_t* pgm_err = NULL;
    pgm_sock_t *pgm_sock;
    pthread_t nak_thread;
#endif

    while((c = getopt(argc, argv, ":hm:i:p:f:")) != -1) {
        switch (c) {
        case 'm':
            mcast_addr = optarg;
            break;
        case 'i':
            iface = optarg;
            break;
        case 'p':
            port = atoi(optarg);
            break;
        case 'h':
        case '?':
            print_usage();
            break;
        default:
            print_usage();
            break;
        }
    }

    if(optind != argc-1) {
        PRINT_ERR("Please provide the path to a file you want to send!");
        ret_val = -1;
        goto ret_error;
    } else {
        file = argv[optind];
    }

    if (iface) {
        char *ifaddr = pftp_inet_iftoa(iface);
        if (strlen(ifaddr) > 0) {
            strncat(network, ifaddr, 128);
            strncat(network, ";", 128);
        }
    }

    if (mcast_addr) {
        strncat(network, mcast_addr, 128);
    } else {
        strncat(network, PFTP_DEFAULT_MCAST_ADDR, 128);
    }

#ifdef UDPTEST
    struct sockaddr_in servaddr;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(PFTP_DEFAULT_MCAST_ADDR);
    servaddr.sin_port = port ? htons(port) : htons(PFTP_UDP_PORT);
#else

    if (0 != pftp_create(1, network, port, &pgm_sock)) {
        ret_val = -1;
        goto ret_error;
    }

    int pgm_status;

    /* Start NAK receiver thread */
    m_run_receiver = 1;
    pthread_create(&nak_thread, NULL, nak_routine, (void*)pgm_sock);
#endif

    char buf[PGMBUF_SIZE];
    buf[0] = '\0';

    struct stat fstat;
    if (-1 == stat(file, &fstat)) {
        PRINT_ERR("Couldn't stat file: %s", strerror(errno));
        ret_val = -1;
        goto ret_error;
    }

    char *fname = strrchr(file, '/');
    if (!fname) {
        fname = file;
    } else {
        fname = fname+1;
    }

    memset(buf, 0, PGMBUF_SIZE);
    snprintf(buf, PGMBUF_SIZE, CMD_SEND_FILE" %ld %s", fstat.st_size, fname);
    PRINT_DBG("Sending file with command: %s", buf);

    size_t bytes_written;
    int bytes_read;

#ifdef UDPTEST
    bytes_written = sendto(sockfd, buf, strlen(buf)+1, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
    if (bytes_written != strlen(buf)+1) {
        PRINT_ERR("Couldn't send file transfer command! %s", strerror(errno));
        ret_val = -1;
        goto ret_error;
    }
#else
    pgm_status = pgm_status = pgm_send(pgm_sock, buf, strlen(buf)+1, &bytes_written);
    if (pgm_status != PGM_IO_STATUS_NORMAL) {
        PRINT_ERR("Couldn't send file transfer command!");
        ret_val = -1;
        goto ret_error;
    }
#endif

    bfd = open(file, O_RDONLY);
    if (bfd < 0) {
        PRINT_ERR("Couldn't open file for reading! %s", strerror(errno));
        ret_val = -1;
        goto ret_error;
    }

    int fds = 0;
    fd_set writefds;
    fd_set readfds;

    bytes_read = read(bfd, buf, PGMBUF_SIZE);
    while (bytes_read > 0) {

#ifdef UDPTEST

        bytes_written = sendto(sockfd, buf, bytes_read, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));

#else
        struct timeval tv;
        pgm_status = pgm_send(pgm_sock, buf, bytes_read, &bytes_written);

        //PRINT_DBG("pgm_status: %d", pgm_status);

        switch (pgm_status) {

        case PGM_IO_STATUS_NORMAL :
        {
#endif
            if (bytes_written != bytes_read) {
                PRINT_ERR("Error sending file!");
                ret_val = -1;
                goto ret_error;
            }
            bytes_read = read(bfd, buf, PGMBUF_SIZE);

#ifdef UDPTEST
            struct timespec ts = {0, 35000};
            nanosleep(&ts, NULL);
#else
        } break;
        case PGM_IO_STATUS_TIMER_PENDING:
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            goto block;
        }
        case PGM_IO_STATUS_RATE_LIMITED :
        {
            socklen_t optlen = sizeof(tv);
            pgm_getsockopt (pgm_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
            if (0 == (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000))
                break;
            /* No accidental fallthrough! */
        }
        case PGM_IO_STATUS_CONGESTION :
        case PGM_IO_STATUS_WOULD_BLOCK :
block:
        {
            FD_ZERO(&writefds);
            pgm_select_info(pgm_sock, NULL, &writefds, &fds);
            fds = select(fds, NULL, &writefds, NULL, pgm_status == PGM_IO_STATUS_WOULD_BLOCK ? NULL : &tv);
        } break;
        default:
            PRINT_ERR("Send error!");
            ret_val = -1;
            goto ret_error;
            break;
        }
#endif
    }

#ifndef UDPTEST
    pthread_mutex_lock(&m_pftp_mutex);
    m_run_receiver = 0;
    pthread_mutex_unlock(&m_pftp_mutex);
    pthread_join(nak_thread, NULL);
    pthread_mutex_destroy(&m_pftp_mutex);
#endif

    goto ret_good;

ret_error:
    PRINT_DBG("Exit error");
    goto ret;
ret_good:
    PRINT_DBG("Exit good");
ret:
    if (bfd > 0)
        close(bfd);
#ifdef UDPTEST
    if (sockfd > 0)
        close(sockfd);
#else
    if (pgm_sock) {
        pftp_stop(pgm_sock);
    }
#endif
    return ret_val;
}