static PRInt32 _udt_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { ///fprintf(stdout, "%s:%d\n", __func__, __LINE__); UDTSOCKET s = get_socket_from_fd(fd); // peek is not supported in udt if (PR_MSG_PEEK & flags) { PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return -1; } int rc = udt_recv(s, (char*)buf, amount, 0); if(rc < 0) { int udterrcode = udt_getlasterror_code(); if (UDT_EASYNCRCV == udterrcode) { PR_SetError(PR_WOULD_BLOCK_ERROR, 0); } else { PR_SetError(PR_IO_ERROR, 0); } return -1; } return rc; }
/* Main receiver function. State diagram: slide 8, chapter 5 */ void receiver() { int ret; int expected = 1; Packet packet; /* Try to receive a packet, check for network errors */ while (1) { ret = udt_recv(&packet, sizeof(packet), -1); if (ret == NET_EOF) break; else if (ret == NET_SYSERR) { fprintf(stderr, "Receiver: NET_SYSERR\n"); exit(1); } /* At this point we have a valid packet. Check the sequence number. */ assert (ret == HEADERSIZE + packet.nbuffer); /* printf("Receiver: Received packet #%d. ", packet.seqn); */ if (packet.seqn == expected) { deliver_data(packet.buffer, packet.nbuffer); receiver_acknowledge(expected); expected++; } else { receiver_acknowledge(expected - 1); } } }
/* Attempts to get an ack. Timeout can be -1 (infinite) or any value >= 0. Returns -1 in case of timeout, otherwise the ACK sequence number. */ int get_ack(int timeout) { ACKPacket ack; int ret = udt_recv(&ack, sizeof(ACKPacket), timeout); if (ret == NET_EOF) { fprintf(stderr, "Sender: NET_EOF\n"); exit(1); } else if (ret == NET_SYSERR) { fprintf(stderr, "Sender: NET_SYSERR\n"); exit(1); } return ret == 0 ? -1 : ack.seqn; }
static PRInt32 _udt_read(PRFileDesc *fd, void *buf, PRInt32 amount) { ///fprintf(stdout, "%s:%d\n", __func__, __LINE__); UDTSOCKET s = get_socket_from_fd(fd); int rc = udt_recv(s, (char*)buf, amount, 0); if(rc < 0) { int udterrcode = udt_getlasterror_code(); if (UDT_EASYNCRCV == udterrcode) { PR_SetError(PR_WOULD_BLOCK_ERROR, 0); } else { PR_SetError(PR_IO_ERROR, 0); } return -1; } return rc; }
static PRInt32 _udt_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { uint32_t dummy_data; PRUdtSocketDesc* desc = (PRUdtSocketDesc*)(fd->secret); if (desc->sign_cnt != desc->rd_cnt) { PR_Recv(desc->sock_pair0, (char*)&dummy_data, sizeof(dummy_data), 0, 0); PR_AtomicIncrement(&desc->rd_cnt); } // peek is not supported in udt if(PR_MSG_PEEK & flags) return PR_WOULD_BLOCK_ERROR; int rc = udt_recv(desc->udtfd, (char*)buf, amount, 0); if(rc < 0) { int udterrcode = udt_getErrorCode(); if ((UDT_ERRECONNLOST == udterrcode) || (UDT_ERRENOCONN == udterrcode)) { PR_Close(desc->sock_pair1); //rc = 0; } } return rc; }
static PRInt32 _udt_read(PRFileDesc *fd, void *buf, PRInt32 amount) { UDTSOCKET s = get_socket_from_fd(fd); uint32_t dummy_data; int rc = 0; PRUdtSocketDesc* desc = (PRUdtSocketDesc*)(fd->secret); if (desc->sign_cnt != desc->rd_cnt) { PR_Recv(desc->sock_pair0, (char*)&dummy_data, sizeof(dummy_data), 0, 0); PR_AtomicIncrement(&desc->rd_cnt); } rc = udt_recv(s, (char*)buf, amount, 0); if(rc < 0) { int udterrcode = udt_getErrorCode(); if (UDT_ERRECONNLOST == udterrcode) { rc = 0; PR_Close(desc->sock_pair0); PR_Close(desc->sock_pair1); } else if (UDT_ERRENOCONN == udterrcode) { rc = 0; PR_Close(desc->sock_pair0); PR_Close(desc->sock_pair1); } } return rc; }
int main(int argc, char **argv ) { char ch; char buf[80]; char sendline[MAXLINE]; char recvline[MAXLINE]; int udt; while ((ch = getopt(argc,argv,"p:R:P:h")) != -1) { switch(ch) { case 'p': local_port = atol(optarg); break; case 'R': remote_addr = ntohl(inet_addr(optarg)); //!!! needs nhotl as udt requires host order! break; case 'P': remote_port = atol(optarg); break; case 'h': fprintf(stdout, PROGRAM_INFO); fprintf(stdout, "usage: udtdemo -p port -P port [-R address]\n\n"); fprintf(stdout, " p port : local UDP socket binds to `port'\n" ); fprintf(stdout, " P port : UDP datagrams will be sent to the remote `port'\n" ); fprintf(stdout, " R address : UDP datagrams will be sent to the remote host \n as specified by `address' (an implicit is 127.0.0.1)\n\n" ); exit(EXIT_SUCCESS); } } fprintf(stderr, PROGRAM_INFO); // Complain if something is missing or wrong. if (remote_addr == 0 || remote_port == 0 || local_port == 0) { fprintf(stderr, "Missing required arguments! Type '%s -h' for help.\n", PROGRAM); exit(EXIT_FAILURE); } fprintf(stderr, "Data channel from localhost:%d to %s:%d.\n", local_port, inet_ntop(AF_INET, &remote_addr, buf, 80), remote_port); fprintf(stderr, "Write data content, press ENTER to send the packet.\n"); // It is important to init UDT! udt = udt_init(local_port); fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make stdin reading non-clocking fd_set readfds; FD_ZERO(&readfds); FD_SET(udt, &readfds); FD_SET(STDIN_FILENO, &readfds); while (select(udt+1, &readfds, NULL, NULL, NULL)) { if (FD_ISSET(STDIN_FILENO, &readfds) && fgets(sendline, MAXLINE, stdin)>0) { // we have read a new line to send if (!udt_send(udt, remote_addr, remote_port, sendline, strlen(sendline))) { perror("udtdemo: "); // some error } } if (FD_ISSET(udt, &readfds)) { // We have a new message to print int n = udt_recv(udt, recvline, MAXLINE, NULL, NULL); recvline[n] = 0; fputs(recvline, stdout); } // and again! FD_ZERO(&readfds); FD_SET(udt, &readfds); FD_SET(STDIN_FILENO, &readfds); } return EXIT_SUCCESS; }
bool process(params_t* args) { ipk_sock_t udt = IPK_SOCK_INVALID; rdt_t* rdt = NULL; #ifndef _WIN32 if (!ipk_fd_block_mode(STDIN_FILENO, false)) { return false; } #endif udt = udt_init(args->src_port); if (!udt_connect(udt, args->dst_port)) { goto return_false; } rdt = rdt_new(); if (!rdt) { goto return_false; } if (!rdt_client_start(rdt)) { goto return_false; } bool eof = false; char buf[BUF_MAXLEN]; char rcvbuf[UDT_PACKET_MAXLEN]; char sndbuf[UDT_PACKET_MAXLEN]; size_t nbuf = 0; size_t nrcvbuf = 0; size_t nsndbuf = 0; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; #ifdef _WIN32 int nfds = 0; // ignored on win32 #else int nfds = max(STDIN_FILENO, udt) + 1; #endif fd_set rfds, wfds; while (!_terminate) { FD_ZERO(&rfds); FD_ZERO(&wfds); if (nsndbuf == 0) { nsndbuf = _countof(sndbuf); rdt_client_step(rdt, rcvbuf, nrcvbuf, sndbuf, &nsndbuf); } else { rdt_client_step(rdt, rcvbuf, nrcvbuf, NULL, NULL); } nrcvbuf = 0; FD_SET(udt, &rfds); if (nsndbuf > 0) { FD_SET(udt, &wfds); } #ifndef _WIN32 if (!eof && nbuf < _countof(buf)) { FD_SET(STDIN_FILENO, &rfds); } #endif if (nbuf > 0 && rdt_data_write(rdt, buf, nbuf)) { nbuf = 0; } else if (eof) { if (rdt_client_done(rdt)) break; } int numfd = select(nfds, &rfds, &wfds, NULL, &tv); if (numfd == -1) { ipk_sock_perror(ipk_sock_errno); } else if (numfd == 0) { continue; } else { #ifndef _WIN32 if (FD_ISSET(STDIN_FILENO, &rfds)) { #else if (!eof) { #endif size_t erecv = _countof(buf) - nbuf; size_t nrecv = fread(buf + nbuf, sizeof(char), erecv, stdin); _ipk_verbose_log("Readed %zu from stdin.", nrecv); nbuf += nrecv; if (nrecv != erecv) { if (feof(stdin)) { eof = true; } else if (ferror(stdin) && !ipk_sock_is_recoverable(errno)) { ipk_perror(errno); // send RST } } } if (FD_ISSET(udt, &wfds)) { int nsnd = udt_send(udt, sndbuf, nsndbuf); if (nsnd == -1) { ipk_sock_perror(ipk_sock_errno); goto return_false; } else if (nsnd > 0) { nsndbuf = 0; sndbuf[nsnd] = '\0'; _ipk_debug_log("#%x <<<\n%s", udt, sndbuf); _ipk_debug_log("#%x /<<<", udt); } else { // send again } } if (FD_ISSET(udt, &rfds)) { int nrcv = udt_recv(udt, rcvbuf, _countof(rcvbuf)); if (nrcv == -1) { ipk_sock_perror(ipk_sock_errno); goto return_false; } else if (nrcv > 0) { nrcvbuf = nrcv; rcvbuf[nrcv] = '\0'; _ipk_debug_log("#%x >>>\n%s", udt, rcvbuf); _ipk_debug_log("#%x />>>", udt); } else { // read again } } } } rdt_dispose(rdt); ipk_sock_close(udt); return true; return_false: rdt_dispose(rdt); ipk_sock_close(udt); return false; } int main(int argc, char* argv[]) { params_t params; memset(¶ms, '\0', sizeof(params_t)); setlocale(LC_ALL, ""); ipk_set_log_func(&mylog); ipk_set_log_level(1); if (!parseargs(argc, argv, ¶ms)) { _ipk_error_log("%s", "Chyba: nebyl zadan povinny parametr."); fprintf(stdout, "%s", "Synopsis: rdtclient -s source_port -d dest_port\n"); return EXIT_FAILURE; } ipk_set_log_level(params.verbose_lvl); if (params.action == ACT_HELP) { fprintf(stdout, "%s", "Spolehliva komunikace, projekt c. 3 pro predmet IPK.\n" "Autor: Radek Sevcik, [email protected]\n" "\n" "Synopsis: rdtclient -s source_port -d dest_port\n" "\n" "Parametry:\n" " -h\t\t\tVypise napovedu.\n" " -s source_port\tNasloucha na portu source_port.\n" " -d dest_port\t\tPripoji se na port dest_port.\n"); return EXIT_SUCCESS; } // sigint (ctrl+c), sigterm #ifdef _WIN32 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)&on_console_handler, true)) { ipk_perror_win(GetLastError()); return EXIT_FAILURE; } #else if (SIG_ERR == signal(SIGINT, &on_signal)) { ipk_perror(errno); return EXIT_FAILURE; } if (SIG_ERR == signal(SIGTERM, &on_signal)) { ipk_perror(errno); return EXIT_FAILURE; } #endif if (!ipk_sock_init()) { return EXIT_FAILURE; } if (0 != atexit(&cleanup)) { _ipk_error_log("%s", "Chyba: nedostatek pameti"); return EXIT_FAILURE; } return process(¶ms) ? EXIT_SUCCESS : EXIT_FAILURE; }