├── server.in ├── client.in ├── test.c ├── README ├── .gitignore ├── cli_send.c ├── serv_recv.c ├── serv_send.c ├── unprtt.h ├── Makefile ├── unpifiplus.h ├── prifinfo_plus.c ├── cli_recv.c ├── ReadMe ├── send_recv.c ├── rtt.c ├── get_ifi_info_plus.c ├── test.txt ├── server.c └── client.c /server.in: -------------------------------------------------------------------------------- 1 | 9877 2 | 50 -------------------------------------------------------------------------------- /client.in: -------------------------------------------------------------------------------- 1 | 127.0.0.1 2 | 9877 3 | aa.c 4 | 50 5 | 3 6 | 0.5 7 | 1000 8 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | 5 | struct smap_t { 6 | uint64_t base, length; 7 | uint32_t type; 8 | }__attribute__((packed)) *smap; 9 | 10 | 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Jun Zeng. 2 | Copyright (C) 2014 Yigong Wang 3 | All rights reserved. 4 | 5 | Based on Steven Codes' library. UNIX Network Programming, Volume 1, Third Edition. 6 | 7 | Unrestricted rights are granted to instructors and students of CSE530 class in Fall 2014 8 | at Stony Brook University. 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /cli_send.c: -------------------------------------------------------------------------------- 1 | #include "unprtt.h" 2 | #include 3 | 4 | #define RTT_DEBUG 5 | 6 | static struct msghdr msgsend; /* assumed init to 0 */ 7 | static struct hdr { 8 | uint32_t seq; /* sequence # */ 9 | uint32_t ts; /* timestamp when sent */ 10 | uint32_t fin; /* mark when file eof */ 11 | } sendhdr; 12 | 13 | ssize_t cli_send(int fd, uint32_t seq_num, uint32_t timestamp, void *outbuff, size_t outbytes) 14 | { 15 | ssize_t n; 16 | struct iovec iovsend[2]; 17 | 18 | sendhdr.seq = seq_num; 19 | sendhdr.ts = timestamp; 20 | sendhdr.fin = 0; 21 | 22 | msgsend.msg_iov = iovsend; 23 | msgsend.msg_iovlen = 2; 24 | 25 | iovsend[0].iov_base = &sendhdr; 26 | iovsend[0].iov_len = sizeof(struct hdr); 27 | iovsend[1].iov_base = outbuff; 28 | iovsend[1].iov_len = outbytes; 29 | 30 | if (sendmsg(fd, &msgsend, 0)<0){ 31 | err_sys("[ERROR:] Send packet error"); 32 | return(-1); 33 | } 34 | 35 | return(0); 36 | } -------------------------------------------------------------------------------- /serv_recv.c: -------------------------------------------------------------------------------- 1 | #include "unprtt.h" 2 | 3 | static struct msghdr msgrecv; /* assumed init to 0 */ 4 | 5 | static struct hdr { 6 | uint32_t seq; /* sequence # */ 7 | uint32_t ts; /* timestamp when sent */ 8 | uint32_t fin; /* mark when file eof */ 9 | }; 10 | 11 | ssize_t serv_recv(int fd, struct hdr *recvhdr, void *inbuff, size_t inbytes){ 12 | ssize_t n; 13 | struct iovec iovrecv[2]; //the argument set to 2 because 0 for header, 1 for data 14 | 15 | msgrecv.msg_name = NULL; 16 | msgrecv.msg_namelen = 0; 17 | msgrecv.msg_iov = iovrecv; 18 | msgrecv.msg_iovlen = 2; 19 | iovrecv[0].iov_base = recvhdr; 20 | iovrecv[0].iov_len = sizeof(struct hdr); 21 | iovrecv[1].iov_base = inbuff; 22 | iovrecv[1].iov_len = inbytes; 23 | 24 | printf("SEQ%d\n", recvhdr->seq); 25 | if((n = recvmsg(fd, &msgrecv, 0)) < 0){ 26 | return(-1); 27 | }else{ 28 | printf("[INFO]: datagram [%d] received...\n", (int)n); 29 | } 30 | 31 | return(n); /* return send datagram size */ 32 | } 33 | 34 | -------------------------------------------------------------------------------- /serv_send.c: -------------------------------------------------------------------------------- 1 | #include "unprtt.h" 2 | 3 | static struct rtt_info rttinfo; 4 | static struct msghdr msgsend; /* assumed init to 0 */ 5 | 6 | static struct hdr { 7 | uint32_t seq; /* sequence # */ 8 | uint32_t ts; /* timestamp when sent */ 9 | uint32_t fin; /* mark when file eof */ 10 | }; 11 | 12 | ssize_t serv_send(int fd, int seq_num, int fin, struct hdr *sendhdr, void *outbuff, size_t outbytes){ 13 | ssize_t n; 14 | struct iovec iovsend[2]; //the argument set to 2 because 0 for header, 1 for data 15 | 16 | sendhdr->seq = seq_num; 17 | sendhdr->ts = rtt_ts(&rttinfo); //store the time at begin sending data 18 | sendhdr->fin = fin; 19 | printf("FIN:%d\n", fin); 20 | msgsend.msg_name = NULL; 21 | msgsend.msg_namelen = 0; 22 | msgsend.msg_iov = iovsend; 23 | msgsend.msg_iovlen = 2; 24 | iovsend[0].iov_base = sendhdr; 25 | iovsend[0].iov_len = sizeof(struct hdr); 26 | iovsend[1].iov_base = outbuff; 27 | iovsend[1].iov_len = outbytes; 28 | 29 | if((n = sendmsg(fd, &msgsend, 0)) < 0){ 30 | return(-1); 31 | }else{ 32 | printf("[INFO]: datagram [%d] sent...\n", (int)n); 33 | } 34 | 35 | return(n); /* return send datagram size */ 36 | } -------------------------------------------------------------------------------- /unprtt.h: -------------------------------------------------------------------------------- 1 | #ifndef __unp_rtt_h 2 | #define __unp_rtt_h 3 | 4 | #include "unp.h" 5 | 6 | struct rtt_info { 7 | int rtt_rtt; /* most recent measured RTT, in milliseconds */ 8 | int rtt_srtt; /* smoothed RTT estimator, in milliseconds */ 9 | int rtt_rttvar; /* smoothed mean deviation, in milliseconds */ 10 | int rtt_rto; /* current RTO to use, in milliiseconds */ 11 | int rtt_nrexmt; /* # times retransmitted: 0, 1, 2, ... */ 12 | uint32_t rtt_base; /* # sec since 1/1/1970 at start */ 13 | }; 14 | 15 | #define RTT_RXTMIN 1000 /* min retransmit timeout value, in milliseconds */ 16 | #define RTT_RXTMAX 3000 /* max retransmit timeout value, in milliseconds */ 17 | #define RTT_MAXNREXMT 12 /* max # times to retransmit */ 18 | 19 | /* function prototypes */ 20 | void rtt_debug(struct rtt_info *); 21 | void rtt_init(struct rtt_info *); 22 | void rtt_newpack(struct rtt_info *); 23 | int rtt_start(struct rtt_info *); 24 | void rtt_stop(struct rtt_info *, uint32_t); 25 | int rtt_timeout(struct rtt_info *); 26 | uint32_t rtt_ts(struct rtt_info *); 27 | 28 | extern int rtt_d_flag; /* can be set to nonzero for addl info */ 29 | 30 | #endif /* __unp_rtt_h */ 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | 3 | LIBS := -lresolv -lnsl -lpthread -lm\ 4 | ../stevens_code/libunp.a\ 5 | 6 | FLAGS := -g -O2 7 | 8 | CFLAGS := ${FLAGS} -I../stevens_code/lib 9 | 10 | all: client server test get_ifi_info_plus.o rtt.o serv_send.o serv_recv.o cli_send.o cli_recv.o 11 | 12 | test: test.o 13 | ${CC} ${FLAGS} -o test test.o ${LIBS} 14 | server.o: server.c 15 | ${CC} ${CFLAGS} -c server.c 16 | 17 | server: server.o get_ifi_info_plus.o rtt.o serv_send.o serv_recv.o 18 | ${CC} ${FLAGS} -o server server.o get_ifi_info_plus.o rtt.o serv_send.o serv_recv.o ${LIBS} 19 | server.o: server.c 20 | ${CC} ${CFLAGS} -c server.c 21 | 22 | 23 | client: client.o get_ifi_info_plus.o rtt.o cli_send.o cli_recv.o 24 | ${CC} ${FLAGS} -o client client.o get_ifi_info_plus.o rtt.o cli_send.o cli_recv.o ${LIBS} 25 | client.o: client.c 26 | ${CC} ${CFLAGS} -c client.c 27 | 28 | 29 | get_ifi_info_plus.o: get_ifi_info_plus.c 30 | ${CC} ${CFLAGS} -c get_ifi_info_plus.c 31 | 32 | rtt.o: rtt.c 33 | ${CC} ${CFLAGS} -c rtt.c 34 | 35 | data_send.o: serv_send.c 36 | ${CC} ${CFLAGS} -c serv_send.c 37 | 38 | data_recv.o: serv_recv.c 39 | ${CC} ${CFLAGS} -c serv_recv.c 40 | 41 | cli_send.o: cli_send.c 42 | ${CC} ${CFLAGS} -c cli_send.c 43 | 44 | cli_recv.o: cli_recv.c 45 | ${CC} ${CFLAGS} -c cli_recv.c 46 | 47 | 48 | clean: 49 | rm test test.o client client.o server server.o get_ifi_info_plus.o rtt.o serv_send.o serv_recv.o cli_send.o cli_recv.o *~ 50 | 51 | -------------------------------------------------------------------------------- /unpifiplus.h: -------------------------------------------------------------------------------- 1 | /* Our own header for the programs that need interface configuration info. 2 | Include this file, instead of "unp.h". */ 3 | 4 | #ifndef __unp_ifi_plus_h 5 | #define __unp_ifi_plus_h 6 | 7 | #include "unp.h" 8 | #include 9 | 10 | #define IFI_NAME 16 /* same as IFNAMSIZ in */ 11 | #define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ 12 | 13 | struct ifi_info { 14 | char ifi_name[IFI_NAME]; /* interface name, null-terminated */ 15 | short ifi_index; /* interface index */ 16 | short ifi_mtu; /* interface MTU */ 17 | u_char ifi_haddr[IFI_HADDR]; /* hardware address */ 18 | u_short ifi_hlen; /* # bytes in hardware address: 0, 6, 8 */ 19 | short ifi_flags; /* IFF_xxx constants from */ 20 | short ifi_myflags; /* our own IFI_xxx flags */ 21 | struct sockaddr *ifi_addr; /* primary address */ 22 | struct sockaddr *ifi_brdaddr;/* broadcast address */ 23 | struct sockaddr *ifi_dstaddr;/* destination address */ 24 | 25 | /*================ cse 533 Assignment 2 modifications =================*/ 26 | 27 | struct sockaddr *ifi_ntmaddr; /* netmask address */ 28 | 29 | /*=====================================================================*/ 30 | 31 | struct ifi_info *ifi_next; /* next of these structures */ 32 | }; 33 | 34 | #define IFI_ALIAS 1 /* ifi_addr is an alias */ 35 | 36 | /* function prototypes */ 37 | struct ifi_info *get_ifi_info_plus(int, int); 38 | struct ifi_info *Get_ifi_info_plus(int, int); 39 | void free_ifi_info_plus(struct ifi_info *); 40 | 41 | #endif /* __unp_ifi_plus_h */ 42 | -------------------------------------------------------------------------------- /prifinfo_plus.c: -------------------------------------------------------------------------------- 1 | #include "unpifiplus.h" 2 | 3 | extern struct ifi_info *Get_ifi_info_plus(int family, int doaliases); 4 | extern void free_ifi_info_plus(struct ifi_info *ifihead); 5 | 6 | 7 | int 8 | main(int argc, char **argv) 9 | { 10 | struct ifi_info *ifi, *ifihead; 11 | struct sockaddr *sa; 12 | u_char *ptr; 13 | int i, family, doaliases; 14 | 15 | if (argc != 3) 16 | err_quit("usage: prifinfo_plus "); 17 | 18 | if (strcmp(argv[1], "inet4") == 0) 19 | family = AF_INET; 20 | #ifdef IPv6 21 | else if (strcmp(argv[1], "inet6") == 0) 22 | family = AF_INET6; 23 | #endif 24 | else 25 | err_quit("invalid "); 26 | doaliases = atoi(argv[2]); 27 | 28 | for (ifihead = ifi = Get_ifi_info_plus(family, doaliases); 29 | ifi != NULL; ifi = ifi->ifi_next) { 30 | printf("%s: ", ifi->ifi_name); 31 | if (ifi->ifi_index != 0) 32 | printf("(%d) ", ifi->ifi_index); 33 | printf("<"); 34 | /* *INDENT-OFF* */ 35 | if (ifi->ifi_flags & IFF_UP) printf("UP "); 36 | if (ifi->ifi_flags & IFF_BROADCAST) printf("BCAST "); 37 | if (ifi->ifi_flags & IFF_MULTICAST) printf("MCAST "); 38 | if (ifi->ifi_flags & IFF_LOOPBACK) printf("LOOP "); 39 | if (ifi->ifi_flags & IFF_POINTOPOINT) printf("P2P "); 40 | printf(">\n"); 41 | /* *INDENT-ON* */ 42 | 43 | if ( (i = ifi->ifi_hlen) > 0) { 44 | ptr = ifi->ifi_haddr; 45 | do { 46 | printf("%s%x", (i == ifi->ifi_hlen) ? " " : ":", *ptr++); 47 | } while (--i > 0); 48 | printf("\n"); 49 | } 50 | if (ifi->ifi_mtu != 0) 51 | printf(" MTU: %d\n", ifi->ifi_mtu); 52 | 53 | if ( (sa = ifi->ifi_addr) != NULL) 54 | printf(" IP addr: %s\n", 55 | Sock_ntop_host(sa, sizeof(*sa))); 56 | 57 | /*=================== cse 533 Assignment 2 modifications ======================*/ 58 | 59 | if ( (sa = ifi->ifi_ntmaddr) != NULL) 60 | printf(" network mask: %s\n", 61 | Sock_ntop_host(sa, sizeof(*sa))); 62 | 63 | /*=============================================================================*/ 64 | 65 | if ( (sa = ifi->ifi_brdaddr) != NULL) 66 | printf(" broadcast addr: %s\n", 67 | Sock_ntop_host(sa, sizeof(*sa))); 68 | if ( (sa = ifi->ifi_dstaddr) != NULL) 69 | printf(" destination addr: %s\n", 70 | Sock_ntop_host(sa, sizeof(*sa))); 71 | } 72 | free_ifi_info_plus(ifihead); 73 | exit(0); 74 | } 75 | -------------------------------------------------------------------------------- /cli_recv.c: -------------------------------------------------------------------------------- 1 | /* include dgsendrecv1 */ 2 | #include "unprtt.h" 3 | #include 4 | 5 | #define CLI_TIMEOUT 8000 6 | #define RTT_DEBUG 7 | 8 | static int rttinit = 0; 9 | static struct msghdr msgrecv; /* assumed init to 0 */ 10 | static struct hdr { 11 | uint32_t seq; /* sequence # */ 12 | uint32_t ts; /* timestamp when sent */ 13 | uint32_t fin; /* mark when file eof */ 14 | } recvhdr; 15 | 16 | static void sig_alrm(int signo); 17 | static sigjmp_buf jmpbuf; 18 | 19 | struct hdr cli_recv(int fd, void *inbuff, size_t inbytes) 20 | { 21 | ssize_t n; 22 | struct iovec iovrecv[2]; 23 | struct rtt_info rttinfo; 24 | 25 | 26 | msgrecv.msg_name = NULL; 27 | msgrecv.msg_namelen = 0; 28 | msgrecv.msg_iov = iovrecv; 29 | msgrecv.msg_iovlen = 2; 30 | iovrecv[0].iov_base = &recvhdr; 31 | iovrecv[0].iov_len = sizeof(struct hdr); 32 | iovrecv[1].iov_base = inbuff; 33 | iovrecv[1].iov_len = inbytes; 34 | 35 | rttinfo.rtt_rto = CLI_TIMEOUT; //8 sec time out 36 | 37 | if (rttinit == 0) { 38 | rtt_init(&rttinfo); /* first time we're called */ 39 | rttinit = 1; 40 | rtt_d_flag = 1; 41 | } 42 | 43 | Signal(SIGALRM, sig_alrm); 44 | rtt_newpack(&rttinfo); /* initialize for this packet */ 45 | 46 | alarm(rtt_start(&rttinfo)/1000); /* calc timeout value & start timer */ 47 | 48 | //#ifdef RTT_DEBUG 49 | rtt_debug(&rttinfo); 50 | //#endif 51 | 52 | if (sigsetjmp(jmpbuf, 1) != 0) { 53 | err_msg("cli_recv: no response from server, giving up"); 54 | rttinit = 0; /* reinit in case we're called again */ 55 | errno = ETIMEDOUT; 56 | err_sys("[ERROR]: Timeout"); 57 | return recvhdr; 58 | } 59 | 60 | n = Recvmsg(fd, &msgrecv, 0); 61 | if (n < sizeof(struct hdr)){ 62 | err_sys("[ERROR]: Received packet incomplete"); 63 | } 64 | 65 | printf("Length: %d\n", (int)n); 66 | //printf("BUFFER: %s\n", (char *)iovrecv[1].iov_base); 67 | printf("SEQ NUM: %u\n", recvhdr.seq); 68 | printf("IS FIN: %u\n", recvhdr.fin); 69 | alarm(0); /* stop SIGALRM timer */ 70 | return(recvhdr); /* return size of received datagram */ 71 | } 72 | 73 | static void sig_alrm(int signo) 74 | { 75 | siglongjmp(jmpbuf, 1); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /ReadMe: -------------------------------------------------------------------------------- 1 | YIGONG WANG SBU-ID:109973706 2 | JUN ZENG SBU-ID:109811026 3 | 4 | 5 | 1. The modifications to ensure that only unicast addresses are bound: 6 | Use a loop to build up the socket and bound to the IP address the function get_ifi_info_plus(professor given) return except the first loopback address. 7 | 8 | Our implementation of the array of structures described above: 9 | Store the socket file description, the IP address and network mask returned from the given function into the servIF and cliIF structure. Then the subnet address is got by the binary and operation of IP address and the relative network mask. 10 | 11 | 2. The details of our modifications to the code of Section 22.5: 12 | 1> The parameters in struct rtt_info have set to int except rtt_base; 13 | 2> All the multiply and divide operation have changed into binary operation; 14 | 3> The return value of rtt_start is divided by 1000; 15 | 4> RTT_RXTMIN is set to 1000 msec, RTT_RXTMAX is set to 3000 msec and RTT_MAXNREXMT is set to 12; 16 | 5> All the second parameters have been changed into millisecond; 17 | 6> rtt_timeout passes its value through the function rtt_minmax, after doubling the RTO. 18 | 19 | 20 | 3. The TCP mechanisms we implemented: 21 | When the transmittion starts, the conjection window size(cwin) is set to 1, and ssthresh is set to be equal to the cwin. Then every time a successful transmittion, cwin doubles. When the sender loses its datagram and receives the duplicate ack from the receiver, the cwin and ssthresh both divide half. If there is no ack received, the cwin is set to 1 and the ssthresh divides half. If then it is successful to transmit the datagrams, cwin is set to be equal to ssthresh. When the cwin bigger than ssthresh, it changes from double increasing into linear increasing. After the sender time out 12 times, it judges that the receiver is shut down. 22 | 23 | 24 | 4. Sender notifying receiver of the last datagram: 25 | Add one more parameter-fin into the hdr structure, and set it as 0 when the file stream has not reached the end. When the file stream is read to the end, fin is set to 1 and pass to the client with the hdr structure to notify receiver that this is the last datagram. 26 | 27 | Clean closing: 28 | After send to the server with the last ack, the client uses a recvmsg and the rtt mechanism to keep listen for the retransmitted datagram for a certain time. Here we set the time as 15 seconds. Then after 15 seconds, the recvmsg times out and the client closes. -------------------------------------------------------------------------------- /send_recv.c: -------------------------------------------------------------------------------- 1 | /* include dgsendrecv1 */ 2 | #include "unprtt.h" 3 | #include 4 | 5 | #define RTT_DEBUG 6 | 7 | /* 8 | //first read the socket buffer and impulse the handshake 9 | len = sizeof(cliaddr); 10 | if((n = recvfrom(sockfd[i], mesg, DGRAM_LEN, 0, (SA *) &cliaddr, &len)) < 0) 11 | err_sys("[ERROR]: child: recvfrom error..."); 12 | */ 13 | 14 | 15 | 16 | 17 | static struct rtt_info rttinfo; 18 | static int rttinit = 0; 19 | static struct msghdr msgsend, msgrecv; /* assumed init to 0 */ 20 | static struct hdr { 21 | uint32_t seq; /* sequence # */ 22 | uint32_t ts; /* timestamp when sent */ 23 | } sendhdr, recvhdr; 24 | 25 | static void sig_alrm(int signo); 26 | static sigjmp_buf jmpbuf; 27 | 28 | ssize_t send_recv(int fd, const void *outbuff, size_t outbytes, void *inbuff, size_t inbytes){ 29 | ssize_t n; 30 | struct iovec iovsend[2], iovrecv[2]; 31 | 32 | if (rttinit == 0) { 33 | rtt_init(&rttinfo); /* first time we're called */ 34 | rttinit = 1; 35 | rtt_d_flag = 1; 36 | } 37 | 38 | /* include dgsendrecv2 */ 39 | Signal(SIGALRM, sig_alrm); 40 | rtt_newpack(&rttinfo); /* initialize for this packet */ 41 | 42 | sendagain: 43 | #ifdef RTT_DEBUG 44 | fprintf(stderr, "send %4d: ", sendhdr.seq); 45 | #endif 46 | sendhdr.ts = rtt_ts(&rttinfo); 47 | Sendmsg(fd, &msgsend, 0); 48 | 49 | alarm(rtt_start(&rttinfo)); /* calc timeout value & start timer */ 50 | #ifdef RTT_DEBUG 51 | rtt_debug(&rttinfo); 52 | #endif 53 | 54 | if (sigsetjmp(jmpbuf, 1) != 0) { 55 | if (rtt_timeout(&rttinfo) < 0) { 56 | err_msg("dg_send_recv: no response from server, giving up"); 57 | rttinit = 0; /* reinit in case we're called again */ 58 | errno = ETIMEDOUT; 59 | return(-1); 60 | } 61 | #ifdef RTT_DEBUG 62 | err_msg("dg_send_recv: timeout, retransmitting"); 63 | #endif 64 | goto sendagain; 65 | } 66 | 67 | do { 68 | n = Recvmsg(fd, &msgrecv, 0); 69 | #ifdef RTT_DEBUG 70 | fprintf(stderr, "recv %4d\n", recvhdr.seq); 71 | #endif 72 | } while (n < sizeof(struct hdr) || recvhdr.seq != sendhdr.seq); 73 | 74 | alarm(0); /* stop SIGALRM timer */ 75 | /* 4calculate & store new RTT estimator values */ 76 | rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr.ts); 77 | 78 | return(n - sizeof(struct hdr)); /* return size of received datagram */ 79 | } 80 | 81 | static void 82 | sig_alrm(int signo) 83 | { 84 | siglongjmp(jmpbuf, 1); 85 | } 86 | /* end dgsendrecv2 */ 87 | 88 | ssize_t 89 | Dg_send_recv(int fd, const void *outbuff, size_t outbytes, 90 | void *inbuff, size_t inbytes, 91 | const SA *destaddr, socklen_t destlen) 92 | { 93 | ssize_t n; 94 | 95 | n = dg_send_recv(fd, outbuff, outbytes, inbuff, inbytes, 96 | destaddr, destlen); 97 | if (n < 0) 98 | err_quit("dg_send_recv error"); 99 | 100 | return(n); 101 | } 102 | -------------------------------------------------------------------------------- /rtt.c: -------------------------------------------------------------------------------- 1 | /* include rtt1 */ 2 | #include "unprtt.h" 3 | 4 | int rtt_d_flag = 0; /* debug flag; can be set by caller */ 5 | 6 | /* 7 | * Calculate the RTO value based on current estimators: 8 | * smoothed RTT plus four times the deviation 9 | */ 10 | #define RTT_RTOCALC(ptr) ((ptr)->rtt_srtt + (4.0 * (ptr)->rtt_rttvar)) 11 | 12 | static int rtt_minmax(int rto){ 13 | 14 | if (rto < RTT_RXTMIN) 15 | rto = RTT_RXTMIN; 16 | else if (rto > RTT_RXTMAX) 17 | rto = RTT_RXTMAX; 18 | return(rto); 19 | } 20 | 21 | void rtt_init(struct rtt_info *ptr){ 22 | struct timeval tv; 23 | 24 | Gettimeofday(&tv, NULL); 25 | ptr->rtt_base = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); /* # sec since 1/1/1970 at start */ 26 | 27 | ptr->rtt_rtt = 0; 28 | ptr->rtt_srtt = 0; 29 | ptr->rtt_rttvar = 750; 30 | ptr->rtt_rto = rtt_minmax(RTT_RTOCALC(ptr)); 31 | /* first RTO at (srtt + (4 * rttvar)) = 3 seconds */ 32 | } 33 | /* end rtt1 */ 34 | 35 | /* 36 | * Return the current timestamp. 37 | * Our timestamps are 32-bit integers that count milliseconds since 38 | * rtt_init() was called. 39 | */ 40 | 41 | /* include rtt_ts */ 42 | uint32_t rtt_ts(struct rtt_info *ptr){ 43 | uint32_t ts; 44 | struct timeval tv; 45 | 46 | Gettimeofday(&tv, NULL); 47 | ts = ((tv.tv_sec - ptr->rtt_base) * 1000) + (tv.tv_usec / 1000); 48 | return(ts); 49 | } 50 | 51 | void rtt_newpack(struct rtt_info *ptr){ 52 | ptr->rtt_nrexmt = 0; 53 | } 54 | 55 | int rtt_start(struct rtt_info *ptr){ 56 | return((int) (ptr->rtt_rto + 500)); /* round float to int */ 57 | /* 4return value can be used as: alarm(rtt_start(&foo)) */ 58 | } 59 | /* end rtt_ts */ 60 | 61 | /* 62 | * A response was received. 63 | * Stop the timer and update the appropriate values in the structure 64 | * based on this packet's RTT. We calculate the RTT, then update the 65 | * estimators of the RTT and its mean deviation. 66 | * This function should be called right after turning off the 67 | * timer with alarm(0), or right after a timeout occurs. 68 | */ 69 | 70 | /* include rtt_stop */ 71 | void rtt_stop(struct rtt_info *ptr, uint32_t ms) { 72 | int delta; 73 | 74 | ptr->rtt_rtt = ms; /* measured RTT in seconds */ 75 | 76 | /* 77 | * Update our estimators of RTT and mean deviation of RTT. 78 | * See Jacobson's SIGCOMM '88 paper, Appendix A, for the details. 79 | * We use floating point here for simplicity. 80 | */ 81 | 82 | delta = ptr->rtt_rtt - ptr->rtt_srtt; 83 | ptr->rtt_srtt += delta >> 3; /* g = 1/8 */ 84 | 85 | if (delta < 0) 86 | delta = -delta; /* |delta| */ 87 | 88 | ptr->rtt_rttvar += (delta - ptr->rtt_rttvar) >> 2; /* h = 1/4 */ 89 | 90 | ptr->rtt_rto = rtt_minmax(RTT_RTOCALC(ptr)); 91 | } 92 | /* end rtt_stop */ 93 | 94 | /* 95 | * A timeout has occurred. 96 | * Return -1 if it's time to give up, else return 0. 97 | */ 98 | 99 | /* include rtt_timeout */ 100 | int rtt_timeout(struct rtt_info *ptr) { 101 | ptr->rtt_rto << 1; /* next RTO */ 102 | ptr->rtt_rto = rtt_minmax(ptr->rtt_rto); 103 | 104 | if (++ptr->rtt_nrexmt > RTT_MAXNREXMT) 105 | return(-1); /* time to give up for this packet */ 106 | return(0); 107 | } 108 | /* end rtt_timeout */ 109 | 110 | /* 111 | * Print debugging information on stderr, if the "rtt_d_flag" is nonzero. 112 | */ 113 | 114 | void rtt_debug(struct rtt_info *ptr) { 115 | if (rtt_d_flag == 0) 116 | return; 117 | 118 | fprintf(stderr, "rtt = %d, srtt = %d, rttvar = %d, rto = %d\n", 119 | ptr->rtt_rtt, ptr->rtt_srtt, ptr->rtt_rttvar, ptr->rtt_rto); 120 | fflush(stderr); 121 | } 122 | -------------------------------------------------------------------------------- /get_ifi_info_plus.c: -------------------------------------------------------------------------------- 1 | 2 | #include "unpifiplus.h" 3 | 4 | struct ifi_info * 5 | get_ifi_info_plus(int family, int doaliases) 6 | { 7 | struct ifi_info *ifi, *ifihead, **ifipnext; 8 | int sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0; 9 | char *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname; 10 | struct ifconf ifc; 11 | struct ifreq *ifr, ifrcopy; 12 | struct sockaddr_in *sinptr; 13 | struct sockaddr_in6 *sin6ptr; 14 | 15 | sockfd = Socket(AF_INET, SOCK_DGRAM, 0); 16 | 17 | lastlen = 0; 18 | len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 19 | for ( ; ; ) { 20 | buf = Malloc(len); 21 | ifc.ifc_len = len; 22 | ifc.ifc_buf = buf; 23 | if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 24 | if (errno != EINVAL || lastlen != 0) 25 | err_sys("ioctl error"); 26 | } else { 27 | if (ifc.ifc_len == lastlen) 28 | break; /* success, len has not changed */ 29 | lastlen = ifc.ifc_len; 30 | } 31 | len += 10 * sizeof(struct ifreq); /* increment */ 32 | free(buf); 33 | } 34 | ifihead = NULL; 35 | ifipnext = &ifihead; 36 | lastname[0] = 0; 37 | sdlname = NULL; 38 | /* end get_ifi_info1 */ 39 | 40 | /* include get_ifi_info2 */ 41 | for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 42 | ifr = (struct ifreq *) ptr; 43 | 44 | #ifdef HAVE_SOCKADDR_SA_LEN 45 | len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); 46 | #else 47 | switch (ifr->ifr_addr.sa_family) { 48 | #ifdef IPV6 49 | case AF_INET6: 50 | len = sizeof(struct sockaddr_in6); 51 | break; 52 | #endif 53 | case AF_INET: 54 | default: 55 | len = sizeof(struct sockaddr); 56 | break; 57 | } 58 | #endif /* HAVE_SOCKADDR_SA_LEN */ 59 | ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ 60 | 61 | #ifdef HAVE_SOCKADDR_DL_STRUCT 62 | /* assumes that AF_LINK precedes AF_INET or AF_INET6 */ 63 | if (ifr->ifr_addr.sa_family == AF_LINK) { 64 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; 65 | sdlname = ifr->ifr_name; 66 | idx = sdl->sdl_index; 67 | haddr = sdl->sdl_data + sdl->sdl_nlen; 68 | hlen = sdl->sdl_alen; 69 | } 70 | #endif 71 | 72 | if (ifr->ifr_addr.sa_family != family) 73 | continue; /* ignore if not desired address family */ 74 | 75 | myflags = 0; 76 | /*================== cse 533 Assignment 2 modifications ==========================*/ 77 | /* Original code commented out by Manish Oct.2010 in order to obtain network 78 | masks and broadcast addresses associated with alias IP addresses under Solaris */ 79 | #if 0 80 | if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 81 | *cptr = 0; /* replace colon with null */ 82 | #endif 83 | /*=================================================================================*/ 84 | if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 85 | if (doaliases == 0) 86 | continue; /* already processed this interface */ 87 | myflags = IFI_ALIAS; 88 | } 89 | memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 90 | 91 | ifrcopy = *ifr; 92 | Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); 93 | flags = ifrcopy.ifr_flags; 94 | if ((flags & IFF_UP) == 0) 95 | continue; /* ignore if interface not up */ 96 | /* end get_ifi_info2 */ 97 | 98 | /* include get_ifi_info3 */ 99 | ifi = Calloc(1, sizeof(struct ifi_info)); 100 | *ifipnext = ifi; /* prev points to this new one */ 101 | ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 102 | 103 | ifi->ifi_flags = flags; /* IFF_xxx values */ 104 | ifi->ifi_myflags = myflags; /* IFI_xxx values */ 105 | #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU) 106 | Ioctl(sockfd, SIOCGIFMTU, &ifrcopy); 107 | ifi->ifi_mtu = ifrcopy.ifr_mtu; 108 | #else 109 | ifi->ifi_mtu = 0; 110 | #endif 111 | memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 112 | ifi->ifi_name[IFI_NAME-1] = '\0'; 113 | /* If the sockaddr_dl is from a different interface, ignore it */ 114 | if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0) 115 | idx = hlen = 0; 116 | ifi->ifi_index = idx; 117 | ifi->ifi_hlen = hlen; 118 | if (ifi->ifi_hlen > IFI_HADDR) 119 | ifi->ifi_hlen = IFI_HADDR; 120 | if (hlen) 121 | memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen); 122 | /* end get_ifi_info3 */ 123 | /* include get_ifi_info4 */ 124 | switch (ifr->ifr_addr.sa_family) { 125 | case AF_INET: 126 | sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 127 | ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in)); 128 | memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 129 | 130 | #ifdef SIOCGIFBRDADDR 131 | if (flags & IFF_BROADCAST) { 132 | Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); 133 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 134 | ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in)); 135 | memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); 136 | } 137 | #endif 138 | 139 | #ifdef SIOCGIFDSTADDR 140 | if (flags & IFF_POINTOPOINT) { 141 | Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); 142 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; 143 | ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in)); 144 | memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); 145 | } 146 | #endif 147 | 148 | /*================== cse 533 Assignment 2 modifications ====================*/ 149 | 150 | #ifdef SIOCGIFNETMASK 151 | Ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy); 152 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; 153 | ifi->ifi_ntmaddr = Calloc(1, sizeof(struct sockaddr_in)); 154 | memcpy(ifi->ifi_ntmaddr, sinptr, sizeof(struct sockaddr_in)); 155 | #endif 156 | 157 | /*===========================================================================*/ 158 | 159 | break; 160 | 161 | #ifdef IPV6 162 | case AF_INET6: 163 | sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr; 164 | ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6)); 165 | memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6)); 166 | #endif 167 | 168 | #ifdef SIOCGIFDSTADDR 169 | if (flags & IFF_POINTOPOINT) { 170 | Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); 171 | sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr; 172 | #ifdef IPV6 173 | ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6)); 174 | memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6)); 175 | #endif 176 | } 177 | #endif 178 | break; 179 | 180 | default: 181 | break; 182 | } 183 | } 184 | free(buf); 185 | return(ifihead); /* pointer to first structure in linked list */ 186 | } 187 | /* end get_ifi_info4 */ 188 | 189 | /* include free_ifi_info_plus */ 190 | void 191 | free_ifi_info_plus(struct ifi_info *ifihead) 192 | { 193 | struct ifi_info *ifi, *ifinext; 194 | 195 | for (ifi = ifihead; ifi != NULL; ifi = ifinext) { 196 | if (ifi->ifi_addr != NULL) 197 | free(ifi->ifi_addr); 198 | if (ifi->ifi_brdaddr != NULL) 199 | free(ifi->ifi_brdaddr); 200 | if (ifi->ifi_dstaddr != NULL) 201 | free(ifi->ifi_dstaddr); 202 | 203 | /*=========================== cse 533 Assignment 2 modifications ========================*/ 204 | 205 | if (ifi->ifi_ntmaddr != NULL) 206 | free(ifi->ifi_ntmaddr); 207 | 208 | /*=======================================================================================*/ 209 | 210 | ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ 211 | free(ifi); /* the ifi_info{} itself */ 212 | } 213 | } 214 | /* end free_ifi_info_plus */ 215 | 216 | struct ifi_info * 217 | Get_ifi_info_plus(int family, int doaliases) 218 | { 219 | struct ifi_info *ifi; 220 | 221 | if ( (ifi = get_ifi_info_plus(family, doaliases)) == NULL) 222 | err_quit("get_ifi_info_plus error"); 223 | return(ifi); 224 | } 225 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- 1 | **I Have A Dream** 2 | 3 | I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation. 4 | 5 | Five score years ago, a great American, in whose symbolic shadow we stand today, signed the Emancipation Proclamation. This momentous decree came as a great beacon light of hope to millions of Negro slaves who had been seared in the flames of withering injustice. It came as a joyous daybreak to end the long night of their captivity. 6 | 7 | But one hundred years later, the Negro still is not free. One hundred years later, the life of the Negro is still sadly crippled by the manacles of segregation and the chains of discrimination. One hundred years later, the Negro lives on a lonely island of poverty in the midst of a vast ocean of material prosperity. One hundred years later, the Negro is still languished in the corners of American society and finds himself an exile in his own land. And so we've come here today to dramatize a shameful condition. 8 | 9 | In a sense we've come to our nation's capital to cash a check. When the architects of our republic wrote the magnificent words of the Constitution and the Declaration of Independence, they were signing a promissory note to which every American was to fall heir. This note was a promise that all men, yes, black men as well as white men, would be guaranteed the "unalienable Rights" of "Life, Liberty and the pursuit of Happiness." It is obvious today that America has defaulted on this promissory note, insofar as her citizens of color are concerned. Instead of honoring this sacred obligation, America has given the Negro people a bad check, a check which has come back marked "insufficient funds." 10 | 11 | But we refuse to believe that the bank of justice is bankrupt. We refuse to believe that there are insufficient funds in the great vaults of opportunity of this nation. And so, we've come to cash this check, a check that will give us upon demand the riches of freedom and the security of justice. 12 | 13 | We have also come to this hallowed spot to remind America of the fierce urgency of Now. This is no time to engage in the luxury of cooling off or to take the tranquilizing drug of gradualism. Now is the time to make real the promises of democracy. Now is the time to rise from the dark and desolate valley of segregation to the sunlit path of racial justice. Now is the time to lift our nation from the quicksands of racial injustice to the solid rock of brotherhood. Now is the time to make justice a reality for all of God's children. 14 | 15 | It would be fatal for the nation to overlook the urgency of the moment. This sweltering summer of the Negro's legitimate discontent will not pass until there is an invigorating autumn of freedom and equality. Nineteen sixty-three is not an end, but a beginning. And those who hope that the Negro needed to blow off steam and will now be content will have a rude awakening if the nation returns to business as usual. And there will be neither rest nor tranquility in America until the Negro is granted his citizenship rights. The whirlwinds of revolt will continue to shake the foundations of our nation until the bright day of justice emerges. 16 | 17 | But there is something that I must say to my people, who stand on the warm threshold which leads into the palace of justice: In the process of gaining our rightful place, we must not be guilty of wrongful deeds. Let us not seek to satisfy our thirst for freedom by drinking from the cup of bitterness and hatred. We must forever conduct our struggle on the high plane of dignity and discipline. We must not allow our creative protest to degenerate into physical violence. Again and again, we must rise to the majestic heights of meeting physical force with soul force. 18 | 19 | The marvelous new militancy which has engulfed the Negro community must not lead us to a distrust of all white people, for many of our white brothers, as evidenced by their presence here today, have come to realize that their destiny is tied up with our destiny. And they have come to realize that their freedom is inextricably bound to our freedom. 20 | 21 | We cannot walk alone. 22 | 23 | And as we walk, we must make the pledge that we shall always march ahead. 24 | 25 | We cannot turn back. 26 | 27 | There are those who are asking the devotees of civil rights, "When will you be satisfied?" We can never be satisfied as long as the Negro is the victim of the unspeakable horrors of police brutality. We can never be satisfied as long as our bodies, heavy with the fatigue of travel, cannot gain lodging in the motels of the highways and the hotels of the cities. We cannot be satisfied as long as the negro's basic mobility is from a smaller ghetto to a larger one. We can never be satisfied as long as our children are stripped of their self-hood and robbed of their dignity by signs stating: "For Whites Only." We cannot be satisfied as long as a Negro in Mississippi cannot vote and a Negro in New York believes he has nothing for which to vote. No, no, we are not satisfied, and we will not be satisfied until "justice rolls down like waters, and righteousness like a mighty stream."¹ 28 | 29 | I am not unmindful that some of you have come here out of great trials and tribulations. Some of you have come fresh from narrow jail cells. And some of you have come from areas where your quest -- quest for freedom left you battered by the storms of persecution and staggered by the winds of police brutality. You have been the veterans of creative suffering. Continue to work with the faith that unearned suffering is redemptive. Go back to Mississippi, go back to Alabama, go back to South Carolina, go back to Georgia, go back to Louisiana, go back to the slums and ghettos of our northern cities, knowing that somehow this situation can and will be changed. 30 | 31 | Let us not wallow in the valley of despair, I say to you today, my friends. 32 | 33 | And so even though we face the difficulties of today and tomorrow, I still have a dream. It is a dream deeply rooted in the American dream. 34 | 35 | I have a dream that one day this nation will rise up and live out the true meaning of its creed: "We hold these truths to be self-evident, that all men are created equal." 36 | 37 | I have a dream that one day on the red hills of Georgia, the sons of former slaves and the sons of former slave owners will be able to sit down together at the table of brotherhood. 38 | 39 | I have a dream that one day even the state of Mississippi, a state sweltering with the heat of injustice, sweltering with the heat of oppression, will be transformed into an oasis of freedom and justice. 40 | 41 | I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character. 42 | 43 | I have a dream today! 44 | 45 | I have a dream that one day, down in Alabama, with its vicious racists, with its governor having his lips dripping with the words of "interposition" and "nullification" -- one day right there in Alabama little black boys and black girls will be able to join hands with little white boys and white girls as sisters and brothers. 46 | 47 | I have a dream today! 48 | 49 | I have a dream that one day every valley shall be exalted, and every hill and mountain shall be made low, the rough places will be made plain, and the crooked places will be made straight; "and the glory of the Lord shall be revealed and all flesh shall see it together." 50 | 51 | This is our hope, and this is the faith that I go back to the South with. 52 | 53 | With this faith, we will be able to hew out of the mountain of despair a stone of hope. With this faith, we will be able to transform the jangling discords of our nation into a beautiful symphony of brotherhood. With this faith, we will be able to work together, to pray together, to struggle together, to go to jail together, to stand up for freedom together, knowing that we will be free one day. 54 | 55 | And this will be the day -- this will be the day when all of God's children will be able to sing with new meaning: 56 | 57 | My country 'tis of thee, sweet land of liberty, of thee I sing. 58 | 59 | Land where my fathers died, land of the Pilgrim's pride, 60 | 61 | From every mountainside, let freedom ring! 62 | 63 | And if America is to be a great nation, this must become true. 64 | 65 | And so let freedom ring from the prodigious hilltops of New Hampshire. 66 | 67 | Let freedom ring from the mighty mountains of New York. 68 | 69 | Let freedom ring from the heightening Alleghenies of Pennsylvania. 70 | 71 | Let freedom ring from the snow-capped Rockies of Colorado. 72 | 73 | Let freedom ring from the curvaceous slopes of California. 74 | 75 | But not only that: 76 | 77 | Let freedom ring from Stone Mountain of Georgia. 78 | 79 | Let freedom ring from Lookout Mountain of Tennessee. 80 | 81 | Let freedom ring from every hill and molehill of Mississippi. 82 | 83 | From every mountainside, let freedom ring. 84 | 85 | And when this happens, and when we allow freedom ring, when we let it ring from every village and every hamlet, from every state and every city, we will be able to speed up that day when all of God's children, black men and white men, Jews and Gentiles, Protestants and Catholics, will be able to join hands and sing in the words of the old Negro spiritual: 86 | 87 | Free at last! Free at last! 88 | 89 | Thank God Almighty, we are free at last! -------------------------------------------------------------------------------- /server.c: -------------------------------------------------------------------------------- 1 | #include "unpifiplus.h" 2 | #include "unprtt.h" 3 | #include 4 | 5 | #define IF_NUM 10 // 6 | #define TIME_OUT 30 // 7 | #define CONN_TIME_OUT 200 // 8 | #define WAIT_TIME 2 9 | #define INPUT_FILE_NAME "server.in" // 10 | #define DGRAM_LEN 512 11 | #define MAX_CWIN 32 12 | 13 | // 14 | struct server_in{ 15 | int port_num; 16 | int window_size; 17 | }; 18 | 19 | struct servIF{ 20 | int sif_sockfd; // 21 | char sif_bound[INET_ADDRSTRLEN]; // 22 | char sif_ntm[INET_ADDRSTRLEN]; // 23 | char sif_snm[INET_ADDRSTRLEN]; // 24 | }; 25 | 26 | struct hdr { 27 | uint32_t seq; /* sequence # */ 28 | uint32_t ts; /* timestamp when sent */ 29 | uint32_t fin; /* mark when file eof */ 30 | }; 31 | 32 | sigjmp_buf jmpbuf; 33 | 34 | // 35 | void sig_chld(int); 36 | // 37 | void sig_alrm(int); 38 | // 39 | ssize_t serv_send(int, int, int, struct hdr*, void*, size_t); 40 | // 41 | ssize_t serv_recv(int, struct hdr*, void*, size_t); 42 | //print out the structure of data 43 | void prifsif(struct servIF *, int); 44 | //calculate the subnet mask 45 | char* subaddr(char *, char *); 46 | //realize the three handshake 47 | void hs_pnum_s(int, int, struct sockaddr_in, struct sockaddr_in); 48 | // 49 | struct server_in get_input_file(struct server_in); 50 | 51 | int main(int argc, char **agrv){ 52 | int i, n, sockfd[100], connfd, snum, maxfdp1, tmp, pos, last_pos, dg_num, fin, rs_sqn, is_timeout, is_noack, ssthresh, is_dup, is_eof; 53 | int issamehost, islocal, cwin, seq_num, rttinit; 54 | ssize_t nread; 55 | size_t leng; 56 | fd_set rset; 57 | FILE *fn; 58 | socklen_t len, peerlen; 59 | pid_t pid; 60 | char mesg[DGRAM_LEN], fpname[DGRAM_LEN], sendline[DGRAM_LEN], *req; 61 | const int on = 1; 62 | struct ifi_info *ifi; 63 | struct sockaddr_in *sa, servaddr, cliaddr, peeraddr; 64 | struct servIF sif[IF_NUM]; //assume 10 interface for unicast 65 | struct server_in input_file; 66 | struct hdr sendhdr[MAX_CWIN], recvhdr[MAX_CWIN]; 67 | char outbuf[MAX_CWIN][DGRAM_LEN], intbuf[MAX_CWIN][DGRAM_LEN]; 68 | struct rtt_info rttinfo; 69 | 70 | 71 | //Initiation 72 | snum = 0; 73 | issamehost = 0; 74 | islocal = 0; 75 | 76 | // Get parameters in input file; 77 | input_file = get_input_file(input_file); 78 | 79 | //get the interface of the host 80 | for(ifi = get_ifi_info_plus(AF_INET, 1); ifi != NULL; ifi = ifi -> ifi_next){ 81 | 82 | if((sockfd[snum] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 83 | err_sys("[ERROR]: build sock error..."); 84 | else 85 | sif[snum].sif_sockfd = sockfd[snum]; 86 | 87 | if(setsockopt(sockfd[snum], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 88 | err_sys("[ERROR]: set socket option(SO_REUSEADDR) error..."); 89 | 90 | sa = (struct sockaddr_in *) ifi -> ifi_addr; 91 | sa -> sin_family = AF_INET; 92 | sa -> sin_port = htons(input_file.port_num); 93 | //bind the sockfd and the server ip 94 | if(bind(sockfd[snum], (SA *) sa, sizeof(*sa)) < 0) 95 | err_sys("[ERROR]: bind error..."); 96 | 97 | if(inet_ntop(AF_INET, &sa -> sin_addr, sif[snum].sif_bound, sizeof(sif[snum].sif_bound)) == NULL) 98 | err_sys("[ERROR]: inet_ntop error"); 99 | 100 | if ((sa = (struct sockaddr_in *)ifi->ifi_ntmaddr) != NULL){ 101 | if(inet_ntop(AF_INET, &sa -> sin_addr, sif[snum].sif_ntm, sizeof(sif[snum].sif_ntm)) == NULL) 102 | err_sys("[ERROR]: inet_ntop error"); 103 | } 104 | 105 | strcpy(sif[snum].sif_snm, subaddr(sif[snum].sif_bound, sif[snum].sif_ntm)); 106 | 107 | snum++; 108 | } 109 | 110 | //print out the ip struct 111 | prifsif(sif, snum); 112 | 113 | //set up the block select function 114 | while(1){ 115 | FD_ZERO(&rset); 116 | for(i = 0; i < snum; i++){ 117 | tmp = 0; 118 | tmp = max(sockfd[i], tmp); 119 | } 120 | maxfdp1 = tmp + 1; 121 | for(i = 0; i < snum; i++) 122 | FD_SET(sockfd[i], &rset); 123 | if(select(maxfdp1, &rset, NULL, NULL, NULL) < 0){ 124 | if(errno == EINTR) 125 | continue; 126 | else 127 | err_sys("[ERROR]: select error..."); 128 | } 129 | 130 | signal(SIGCHLD, sig_chld); 131 | 132 | for(i = 0; i < snum; i++){ 133 | if(FD_ISSET(sockfd[i], &rset)){ 134 | if((pid = fork()) == 0){ 135 | 136 | //first read the socket buffer and impulse the handshake 137 | len = sizeof(cliaddr); 138 | if((n = recvfrom(sockfd[i], mesg, DGRAM_LEN, 0, (SA *) &cliaddr, &len)) < 0) 139 | err_sys("[ERROR]: child: recvfrom error..."); 140 | 141 | sleep(1); 142 | printf("[INFO]: Enter child process...\n"); 143 | 144 | //judge the connection type 145 | printf("\n\n"); 146 | mesg[n] = 0; 147 | req = mesg; 148 | if(!strcmp(req, "INIT_127")){ 149 | issamehost = 1; 150 | printf("[INFO]: Receive the REQ from client: [%s]\n", mesg); 151 | 152 | len = sizeof(cliaddr); 153 | snprintf(mesg, sizeof(mesg), "SAME_HOST"); 154 | if(sendto(sockfd[i], mesg, sizeof(mesg), 0, (SA *) &cliaddr, len) < 0) 155 | err_sys("[ERROR]: hs_pnum_s: sendto error..."); 156 | } 157 | 158 | else if(!memcmp(req, "INIT_CON", 8)){ 159 | printf("[INFO]: Receive the REQ from client: [%s]\n", mesg); 160 | if(!strcmp(req+8, sif[i].sif_snm)){ 161 | islocal = 1; 162 | len = sizeof(cliaddr); 163 | snprintf(mesg, sizeof(mesg), "LOCAL_HOST"); 164 | if(sendto(sockfd[i], mesg, sizeof(mesg), 0, (SA *) &cliaddr, len) < 0) 165 | err_sys("[ERROR]: hs_pnum_s: sendto error..."); 166 | } 167 | else{ 168 | len = sizeof(cliaddr); 169 | snprintf(mesg, sizeof(mesg), "COMM_HOST"); 170 | if(sendto(sockfd[i], mesg, sizeof(mesg), 0, (SA *) &cliaddr, len) < 0) 171 | err_sys("[ERROR]: hs_pnum_s: sendto error..."); 172 | } 173 | } 174 | 175 | else{ 176 | printf("[ERROR]: UNKNOWN REQ: %s\n", req); 177 | exit(0); 178 | } 179 | 180 | //build up the connection socket and bind it to the ephemeral port 181 | if((connfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 182 | err_sys("[ERROR]: child: build sock error..."); 183 | 184 | if(setsockopt(connfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 185 | err_sys("[Error]: Setting SO_REUSEADDR socket option error."); 186 | 187 | //set up the socket option SO_DONTROUTE 188 | if(islocal){ 189 | if(setsockopt(connfd, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)) < 0) 190 | err_sys("[Error]: Setting SO_DONTROUTE socket option error."); 191 | else 192 | printf("[INFO]: The socket option SO_DONTROUTE is set up...\n"); 193 | } 194 | 195 | bzero(&servaddr, sizeof(servaddr)); 196 | if(issamehost){ 197 | if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) 198 | err_sys("[ERROR]: main: inet_pton error for 127.0.0.1"); 199 | } 200 | else{ 201 | if(getsockname(sockfd[i], (SA *) &servaddr, &len) < 0) 202 | err_sys("[ERROR]: getsockname error..."); 203 | } 204 | servaddr.sin_family = AF_INET; 205 | servaddr.sin_port = htons(0); 206 | 207 | if(bind(connfd, (SA *) &servaddr, sizeof(servaddr)) < 0) 208 | err_sys("[ERROR]: child: bind error..."); 209 | 210 | len = sizeof(servaddr); 211 | if(getsockname(connfd, (SA *) &servaddr, &len) < 0) 212 | err_sys("[ERROR]: getsockname error..."); 213 | else 214 | printf("[INFO]: The connection socket is bound to %s\n", sock_ntop((SA *) &servaddr, len)); 215 | 216 | //get the IP client and its port number 217 | if(issamehost){ 218 | if (inet_pton(AF_INET, "127.0.0.1", &cliaddr.sin_addr) <= 0) 219 | err_sys("[ERROR]: main: inet_pton error for 127.0.0.1"); 220 | } 221 | 222 | len = sizeof(cliaddr); 223 | if(connect_timeo(connfd, (SA *) &cliaddr, sizeof(cliaddr), CONN_TIME_OUT) < 0) 224 | err_sys("[ERROR]: connect error..."); 225 | peerlen = sizeof(peeraddr); 226 | getpeername(connfd, (SA *) &peeraddr, &peerlen); 227 | printf("[INFO]: And it connects to %s: success\n", sock_ntop((SA *) &peeraddr, peerlen)); 228 | printf("---------------------------------\n"); 229 | 230 | sleep(1); 231 | 232 | //handshake: send the new port num to client 233 | hs_pnum_s(sockfd[i], connfd, cliaddr, servaddr); 234 | 235 | while(1){ 236 | //wait for file request 237 | if((n = recv(connfd, mesg, DGRAM_LEN, 0)) < 0) 238 | err_sys("[ERROR]: child: recv error..."); 239 | if(strcpy(fpname, mesg) == NULL) 240 | err_sys("[ERROR]: child: strcpy error..."); 241 | printf("[INFO]: Client requests the document: %s\n", fpname); 242 | 243 | fn = fopen(fpname, "rb+"); 244 | if(fn == NULL){ 245 | printf("[WARNING]: file not exist...\n\n"); 246 | snprintf(mesg, sizeof(mesg), "NO_FILE"); 247 | if(send(connfd, mesg, sizeof(mesg), 0) < 0){ 248 | err_sys("[ERROR]child: send error..."); 249 | } 250 | err_quit("[ERROR]: %s\n",mesg); 251 | } 252 | else{ 253 | printf("[INFO]: File exists...\n\n"); 254 | snprintf(mesg, sizeof(mesg), "YES_FILE"); 255 | if(send(connfd, mesg, sizeof(mesg), 0) < 0) 256 | err_sys("[ERROR]: child: send error..."); 257 | if(fseek(fn, 0, SEEK_SET) != 0) 258 | err_sys("[ERROR]: child: fseek error..."); 259 | 260 | //initiation 261 | cwin = 1; 262 | ssthresh = MAX_CWIN; 263 | seq_num = 0; 264 | fin = 0; 265 | rttinit = 0; 266 | rs_sqn = 0; 267 | is_timeout = 0; 268 | is_noack = 0; 269 | is_dup = 0; 270 | is_eof = 0; 271 | 272 | //first time we're called 273 | if (rttinit == 0){ 274 | rtt_init(&rttinfo); 275 | rttinit = 1; 276 | rtt_d_flag = 1; 277 | } 278 | 279 | signal(SIGALRM, sig_alrm); 280 | 281 | pos = 0;//pos point to the next datagram need to send 282 | last_pos = 0;//record the last RTT datagram positions 283 | 284 | //transmit file 285 | while(1){ 286 | 287 | if(cwin > ssthresh){ 288 | if(cwin < MAX_CWIN){ 289 | cwin++; 290 | printf("[INFO]: Conjection window reaches ssthresh, turn into linear increasing\n"); 291 | }else{ 292 | printf("[INFO]: Conjection window_size reaches max: %d\n", ssthresh); 293 | } 294 | } 295 | 296 | //initialize for this term of packet 297 | rtt_newpack(&rttinfo); 298 | last_pos = pos; 299 | //reading the file 300 | for(i = 0; i < cwin; i++){ 301 | if(!feof(fn)){ 302 | if((nread = fread(outbuf[i], DGRAM_LEN, 1, fn)) < 0) 303 | err_sys("[ERROR]: child: fread error..."); 304 | }else{ 305 | is_eof = 1; 306 | break; 307 | } 308 | } 309 | 310 | 311 | //judge the send buffer whether is full 312 | if(i == MAX_CWIN){ 313 | printf("[INFO]: Send buffer is full.\n"); 314 | } 315 | 316 | //record the datagram num 317 | dg_num = i; 318 | 319 | //sending the data 320 | for(i = 0; i < dg_num; i++){ 321 | if(is_eof){ 322 | if(i == dg_num-1){ 323 | fin = 1; 324 | } 325 | } 326 | leng = sizeof(outbuf[i]); 327 | if((n = serv_send(connfd, seq_num, fin, &sendhdr[i], outbuf[i], leng)) < 0){ 328 | err_sys("[ERROR]: child: serv_send error..."); 329 | }else{ 330 | seq_num++; 331 | printf("[INFO]: Send SQN[%d]\n", sendhdr[i].seq); 332 | } 333 | } 334 | 335 | if (sigsetjmp(jmpbuf, 1) != 0) { 336 | is_timeout = 1; 337 | 338 | if(i == 0){ 339 | is_noack = 1; 340 | } 341 | 342 | //get the ack of last receive datagram 343 | leng = sizeof(outbuf[pos-last_pos]); 344 | if((n = serv_send(connfd, pos, fin, &sendhdr[pos-last_pos], outbuf[pos-last_pos], leng)) < 0){ 345 | err_sys("[ERROR]: child: serv_send error..."); 346 | }else{ 347 | printf("[INFO]: Resend SQN[%d]\n", sendhdr[pos-last_pos].seq); 348 | } 349 | 350 | //judge the resend packet whether the same as the last one 351 | if(pos > rs_sqn){ 352 | rtt_newpack(&rttinfo); 353 | } 354 | rs_sqn = pos; 355 | 356 | if (rtt_timeout(&rttinfo) < 0) { 357 | rttinit = 0; /* reinit in case we're called again */ 358 | errno = ETIMEDOUT; 359 | err_quit("[ERROR]: No response from the client, giving up."); 360 | } 361 | } 362 | 363 | //calc timeout value & start timer 364 | alarm(rtt_start(&rttinfo)/1000); 365 | rtt_debug(&rttinfo); 366 | 367 | i = 0; 368 | //receiving the ack 369 | do{ 370 | if((n = serv_recv(connfd, &recvhdr[i], NULL, 0)) < 0){ 371 | err_sys("[ERROR]: child: serv_send error..."); 372 | }else{ 373 | printf("[INFO]: received ack[%d]\n", recvhdr[i].seq); 374 | } 375 | pos = recvhdr[i].seq; 376 | i++; 377 | //block in recv until the ack equals the send seq plus 1 378 | }while(n < sizeof(struct hdr) || recvhdr[i-1].seq != (sendhdr[dg_num-1].seq + 1)); 379 | 380 | alarm(0); 381 | rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr[i].ts); 382 | 383 | //change the cwin size 384 | if(is_timeout){ 385 | ssthresh = cwin >> 1; 386 | printf("[WARNING]: Time out! ssthresh set to the half of conjection window: %d\n", ssthresh); 387 | is_dup = 1; 388 | if(is_noack){ 389 | is_timeout = 0; 390 | is_noack = 0; 391 | cwin = 1; 392 | printf("[WARNING]: Receive none ack, conjection window set to 1.\n"); 393 | }else{ 394 | is_timeout = 0; 395 | if(cwin != 1){ 396 | cwin = cwin >> 1; 397 | } 398 | } 399 | }else if(cwin < MAX_CWIN){ 400 | cwin = cwin << 1; 401 | if(is_dup){ 402 | cwin = ssthresh; 403 | is_dup = 0; 404 | } 405 | } 406 | 407 | //exit the file transmit 408 | if(feof(fn)){ 409 | break; 410 | } 411 | } 412 | 413 | printf("\n[INFO]: Finish %s transmitting!\n\n", fpname); 414 | fclose(fn); 415 | exit(0); 416 | //inform client the file finish sending 417 | //snprintf(mesg, sizeof(mesg), "FIN"); 418 | //if(send(connfd, mesg, sizeof(mesg), 0) < 0) 419 | // err_sys("[ERROR]: child: send error..."); 420 | } 421 | } 422 | exit(0); //exit the child process 423 | } 424 | } 425 | } 426 | } 427 | exit(0); 428 | } 429 | 430 | 431 | void sig_chld(int signo){ 432 | pid_t pid; 433 | int stat; 434 | 435 | while((pid = waitpid(-1, &stat, WNOHANG)) > 0) 436 | printf("***child %d of server terminated!***\n\n\n", pid); 437 | return; 438 | } 439 | 440 | void sig_alrm(int signo){ 441 | siglongjmp(jmpbuf, 1); 442 | } 443 | 444 | void prifsif(struct servIF *sif, int snum){ 445 | int i; 446 | printf("\n----- Local interface Info. -----\n"); 447 | for(i = 0; i < snum; i++){ 448 | printf("* Interface %d:\n", i+1); 449 | printf("\tThe IP address:\t\t%s;\n", sif[i].sif_bound); 450 | printf("\tThe network mask:\t%s;\n", sif[i].sif_ntm); 451 | printf("\tThe subnet address:\t%s;\n", sif[i].sif_snm); 452 | } 453 | printf("---------------------------------\n\n"); 454 | return; 455 | } 456 | 457 | char* subaddr(char *ipaddr, char *ntmaddr){ 458 | char *snaddr; 459 | struct in_addr inaddr; 460 | 461 | inaddr.s_addr= inet_addr(ipaddr) & inet_addr(ntmaddr); 462 | snaddr = inet_ntoa(inaddr); 463 | return snaddr; 464 | } 465 | 466 | void hs_pnum_s(int sockfd, int connfd, struct sockaddr_in cliaddr, struct sockaddr_in servaddr){ 467 | int n, i; 468 | int pnum; 469 | char mesg[DGRAM_LEN], *ack; 470 | socklen_t len; 471 | fd_set rset; 472 | struct timeval tm; 473 | 474 | //send the port num 475 | len = sizeof(cliaddr); 476 | pnum = ntohs(servaddr.sin_port); 477 | snprintf(mesg, sizeof(mesg), "%d", pnum); 478 | 479 | i = 0; 480 | 481 | resend: if(sendto(sockfd, mesg, sizeof(mesg), 0, (SA *) &cliaddr, len) < 0){ 482 | err_sys("[ERROR]: hs_pnum_s: sendto error..."); 483 | }else{ 484 | printf("[INFO]: Port number %s is sent to client...\n", mesg); 485 | 486 | tm.tv_sec = WAIT_TIME; 487 | tm.tv_usec = 0; 488 | FD_ZERO(&rset); 489 | FD_SET(connfd, &rset); 490 | if((n = select(connfd+1, &rset, NULL, NULL, &tm)) < 0){ 491 | if(errno == EINTR){ 492 | printf("[WARNING]: Ignored EINTR signal"); 493 | } else { 494 | err_sys("[ERROR]: Select function error"); 495 | } 496 | } 497 | if(FD_ISSET(connfd, &rset)){ 498 | //receive the ack 499 | if((n = recvfrom(connfd, mesg, DGRAM_LEN, 0, (SA *) &cliaddr, &len)) < 0) 500 | err_sys("[ERROR]: hs_pnum_s: recvfrom error..."); 501 | mesg[n] = 0; //null terminate 502 | ack = mesg; 503 | if(!strcmp(ack, "ACK_PNUM")){ 504 | printf("[INFO]: Receive the ACK from client: [%s]\n", mesg); 505 | //close the inherited socket 506 | close(sockfd); 507 | } 508 | }else if (n == 0){ 509 | if(i > 12){ 510 | errno = ETIMEDOUT; 511 | err_quit("[ERROR]: No response from the client, giving up."); 512 | }else{ 513 | printf("[WARNING]: Time out!\nResend the port number...\n"); 514 | i++; 515 | goto resend; 516 | } 517 | } 518 | 519 | printf("---------------------------------\n"); 520 | } 521 | } 522 | 523 | struct server_in get_input_file(struct server_in input_file){ 524 | FILE * file = fopen(INPUT_FILE_NAME, "r"); 525 | char temp[DGRAM_LEN]; 526 | 527 | if (file == NULL){ 528 | err_sys("[ERROR]: Read input file error, program terminated."); 529 | } 530 | 531 | if (fgets( temp, sizeof temp, file ) != NULL){ 532 | input_file.port_num = atoi(temp); 533 | } else{ 534 | err_sys("[ERROR]: Read port number in file error, program terminated."); 535 | } 536 | 537 | if (fgets( temp, sizeof temp, file ) != NULL){ 538 | input_file.window_size = atoi(temp); 539 | } else{ 540 | err_sys("[ERROR]: Read sliding-window size in file error, program terminated."); 541 | } 542 | 543 | return input_file; 544 | } 545 | 546 | -------------------------------------------------------------------------------- /client.c: -------------------------------------------------------------------------------- 1 | #include "unpifiplus.h" 2 | #include "math.h" 3 | #include "unprtt.h" 4 | 5 | #define IF_NUM 10 // The maximum client interface number. 6 | #define CONN_TIME_OUT 200 // 7 | #define MAX_NAME_LEN 255 8 | #define WAIT_TIME 2 9 | #define INPUT_FILE_NAME "client.in" 10 | #define DGRAM_LEN 512 11 | #define RESIVE_BUFF_SIZE 512 12 | 13 | // 14 | struct client_in{ 15 | char server_address[INET_ADDRSTRLEN]; 16 | int port_num; 17 | char file_name[MAX_NAME_LEN]; 18 | int window_size; 19 | int seed_value; 20 | float p_loss; 21 | int receive_rate; 22 | } input_file; 23 | 24 | 25 | // Define the client interface struct. 26 | struct cliIF{ 27 | char cif_bound[INET_ADDRSTRLEN]; // IP address/Interface to be bound 28 | char cif_ntm[INET_ADDRSTRLEN]; // Client network mask 29 | }; 30 | 31 | // 32 | struct hdr { 33 | uint32_t seq; /* sequence # */ 34 | uint32_t ts; /* timestamp when sent */ 35 | uint32_t fin; /* mark when file eof */ 36 | }; 37 | 38 | FILE *fn; 39 | char recivebuff[RESIVE_BUFF_SIZE][DGRAM_LEN]; 40 | char buffflag[RESIVE_BUFF_SIZE]; 41 | uint32_t wroteposition; 42 | pthread_t tid, main_tid; 43 | pthread_mutex_t accessbuff_mutex = PTHREAD_MUTEX_INITIALIZER; 44 | pthread_cond_t accessbuff_cond = PTHREAD_COND_INITIALIZER; 45 | 46 | // Print out the interface infos of client 47 | void prifsif(struct cliIF *, int); 48 | //calculate the subnet mask 49 | char* subaddr(char *, char *); 50 | // 51 | void hs_pnum_c(int, struct sockaddr_in, struct sockaddr_in); 52 | // Request the data by file name 53 | void data_req(int); 54 | // 55 | struct client_in get_input_file(); 56 | // Get sleep time based on given seed 57 | struct timespec sleeptime(); 58 | // 59 | uint32_t get_last_ack_packet_bias(char *); 60 | // 61 | struct hdr cli_recv(int , void *, size_t); 62 | // 63 | ssize_t cli_send(int, uint32_t, uint32_t, void *, size_t); 64 | // 65 | void * consume_buff(void *); 66 | 67 | int main(int argc, char **argv){ 68 | 69 | int n, sockfd, snum, i, pnum, issamehost; 70 | char paddr[INET_ADDRSTRLEN], baddr[INET_ADDRSTRLEN], mesg[DGRAM_LEN], **pptr, str[INET_ADDRSTRLEN], *tempcharp, *ack; 71 | char buf[20] = "INIT_CON"; 72 | const int on = 1; 73 | socklen_t len, peerlen; 74 | struct sockaddr_in *sa, cliaddr, servaddr, peeraddr; 75 | struct in_addr inaddr; 76 | struct cliIF cif[IF_NUM]; 77 | struct ifi_info *ifi; 78 | struct hostent *hptr; 79 | struct timeval tm; 80 | fd_set rset; 81 | char * fpname; 82 | 83 | main_tid = pthread_self(); 84 | 85 | // Get parameters in input file; 86 | input_file = get_input_file(); 87 | srand(input_file.seed_value); 88 | 89 | fpname = input_file.file_name; 90 | //check if the file exits or not 91 | if((fn = fopen(fpname, "wb+")) == NULL){ 92 | err_sys("[Error]: File build or open fail"); 93 | } 94 | 95 | 96 | // Use inet_pton to judge whether this is a valid IPv4 address. 97 | if (inet_pton(AF_INET, input_file.server_address, &(inaddr.s_addr)) <= 0){ 98 | err_quit("[ERROR]: Please use a valid IPv4 address is file."); 99 | } else { 100 | // If the input is an ipv4 address 101 | in_addr_t addr = inet_addr(input_file.server_address); 102 | // If the IP address has no Domain record, give warning and process hostent struct. 103 | if((hptr = gethostbyaddr((const char *)&addr, 4, AF_INET)) == NULL){ 104 | err_msg("[WARNING]: Cannot find hostname for %s:%s", input_file.server_address, hstrerror(h_errno)); 105 | } 106 | } 107 | 108 | // Print Server's information (Hostname and IP addresses). 109 | printf("\n---------- Server Info. ---------\n"); 110 | printf("* Hostname:\n\t%s;\n", hptr->h_name); 111 | printf("* Address:\n" ); 112 | for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++){ 113 | printf("\t%s;\n", inet_ntop(AF_INET, *pptr, paddr, sizeof(paddr))); 114 | } 115 | printf("---------------------------------\n\n"); 116 | 117 | // Build up the socket 118 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ 119 | err_sys("[ERROR]: Build socket error, program terminated."); 120 | } 121 | 122 | // Set socket option SO_REUSEADDR. 123 | if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){ 124 | err_sys("[ERROR]: Setting SO_REUSEADDR socket option error."); 125 | } 126 | 127 | // Number of interface 128 | snum = 0; 129 | 130 | // Get all local interfaces infomation 131 | for(ifi = get_ifi_info_plus(AF_INET, 1); ifi != NULL; ifi = ifi -> ifi_next){ 132 | 133 | sa = (struct sockaddr_in *) ifi -> ifi_addr; 134 | sa -> sin_family = AF_INET; 135 | sa -> sin_port = htons(0); 136 | 137 | // Store Interface address and mask info. to cif array. 138 | if(inet_ntop(AF_INET, &sa -> sin_addr, cif[snum].cif_bound, sizeof(cif[snum].cif_bound)) == NULL){ 139 | err_sys("[ERROR]: Interface address not supported."); 140 | } 141 | if ((sa = (struct sockaddr_in *)ifi -> ifi_ntmaddr) != NULL){ 142 | if(inet_ntop(AF_INET, &sa -> sin_addr, cif[snum].cif_ntm, sizeof(cif[snum].cif_ntm)) == NULL){ 143 | err_sys("[ERROR]: Network mask not supported."); 144 | } 145 | } 146 | snum++; 147 | } 148 | 149 | // Print out the ip struct 150 | prifsif(cif, snum); 151 | 152 | //Bind the socket to the loopback address 153 | bzero(&cliaddr, sizeof(cliaddr)); 154 | cliaddr.sin_family = AF_INET; 155 | cliaddr.sin_port = htons(0); 156 | if(snum == 1){ 157 | if (inet_pton(AF_INET, "127.0.0.1", &cliaddr.sin_addr) <= 0){ 158 | err_quit("[ERROR]: inet_pton function error for 127.0.0.1"); 159 | } 160 | } else { 161 | if (inet_pton(AF_INET, cif[1].cif_bound, &cliaddr.sin_addr) <= 0){ 162 | err_quit("[ERROR]: inet_pton function error for %s", cif[1].cif_bound); 163 | } 164 | } 165 | 166 | if(bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)) < 0){ 167 | err_sys("[ERROR]: Socket bind error");//error occur 168 | } else { 169 | len = sizeof(cliaddr); 170 | if(getsockname(sockfd, (SA *) &cliaddr, &len) < 0){ 171 | err_sys("[ERROR]: getsockname function error"); 172 | } 173 | printf("[INFO]: Successfully bind to %s\n", sock_ntop((SA *) &cliaddr, len)); 174 | } 175 | //obtain the port number of client 176 | pnum = ntohs(cliaddr.sin_port); 177 | 178 | /* judge the typing IP whether the same as the client IP, if the same client sends to server SAME_HOST, then client socket 179 | bind to the new socket to 127.0.0.1, the same as server socket 180 | */ 181 | 182 | issamehost = 0; 183 | // Judege the typing IP 184 | for(i = 0; i < snum; i++){ 185 | if(!strcmp(input_file.server_address, cif[i].cif_bound)){ 186 | printf("[INFO]: The destination host is same host.\n"); 187 | issamehost = 1; 188 | break; 189 | } 190 | } 191 | 192 | if(issamehost){ 193 | // If 194 | bzero(&servaddr, sizeof(servaddr)); 195 | servaddr.sin_family = AF_INET; 196 | servaddr.sin_port = htons(input_file.port_num); 197 | 198 | if(inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0){ 199 | err_sys("[ERROR]: inet_pton function error for 127.0.0.1"); 200 | } 201 | 202 | i = 0; 203 | 204 | init1: snprintf(mesg, sizeof(mesg), "INIT_127"); 205 | if((n = sendto(sockfd, mesg, strlen(mesg), 0, (SA *) &servaddr, sizeof(servaddr))) < 0){ 206 | err_sys("[ERROR]: Cannot send INIT_127 to server"); 207 | } else { 208 | tm.tv_sec = WAIT_TIME; 209 | tm.tv_usec = 0; 210 | FD_ZERO(&rset); 211 | FD_SET(sockfd, &rset); 212 | if((n = select(sockfd+1, &rset, NULL, NULL, &tm)) < 0){ 213 | if(errno == EINTR){ 214 | printf("[WARNING]: Ignored EINTR signal"); 215 | } else { 216 | err_sys("[ERROR]: Select function error"); 217 | } 218 | } 219 | 220 | if(FD_ISSET(sockfd, &rset)){ 221 | len = sizeof(servaddr); 222 | if((n = recvfrom(sockfd, mesg, DGRAM_LEN, 0, (SA *) &servaddr, &len)) < 0){ 223 | err_sys("[ERROR]: recvfrom function error"); 224 | } 225 | mesg[n] = '\0'; 226 | ack = mesg; 227 | 228 | if(!strcmp(ack, "SAME_HOST")){ 229 | printf("[INFO]: Received the ACK from server: %s\n", mesg); 230 | close(sockfd); 231 | 232 | // rebuild up the socket 233 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ 234 | err_sys("[ERROR]: Build socket error, program terminated."); 235 | } else { 236 | printf("[INFO]: Socket successfully rebuilt\n"); 237 | } 238 | 239 | // reset socket option SO_REUSEADDR. 240 | if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){ 241 | err_sys("[Error]: Setting SO_REUSEADDR socket option error."); 242 | } 243 | 244 | //rebind the socket to the loopback address 245 | bzero(&cliaddr, sizeof(cliaddr)); 246 | cliaddr.sin_family = AF_INET; 247 | cliaddr.sin_port = htons(pnum); 248 | if (inet_pton(AF_INET, "127.0.0.1", &cliaddr.sin_addr) <= 0) 249 | err_quit("[ERROR]: main: inet_pton error for 127.0.0.1"); 250 | if(bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)) < 0) 251 | err_sys("[ERROR]: bind error..."); 252 | else{ 253 | len = sizeof(cliaddr); 254 | if(getsockname(sockfd, (SA *) &cliaddr, &len) < 0) 255 | err_sys("[ERROR]: getsockname error..."); 256 | printf("[INFO]: Rebind to %s: success\n", sock_ntop((SA *) &cliaddr, sizeof(cliaddr))); 257 | } 258 | 259 | //reconnect the socket to the loopback addressm 260 | if(connect_timeo(sockfd, (SA *) &servaddr, sizeof(servaddr), CONN_TIME_OUT) < 0) 261 | err_sys("[ERROR]: connect error..."); 262 | else{ 263 | peerlen = sizeof(peeraddr); 264 | getpeername(sockfd, (SA *) &peeraddr, &peerlen); 265 | printf("[INFO]: Connects to %s: success\n", sock_ntop((SA *) &peeraddr, peerlen)); 266 | printf("---------------------------------\n"); 267 | } 268 | } 269 | 270 | else{ 271 | printf("[ERROR]: UNKOWN ACK: %s\n", mesg); 272 | exit(0); 273 | } 274 | } 275 | else if(n == 0){ 276 | if(i > 12){ 277 | errno = ETIMEDOUT; 278 | err_quit("[ERROR]: No response from the server, giving up."); 279 | }else{ 280 | printf("[INIT_127] time out!\nRetry the requset...\n"); 281 | i++; 282 | goto init1; 283 | } 284 | } 285 | } 286 | }else{ 287 | /*send INIT_255 to subnet broadcast address, if server receive and reply LOCAL_HOST, 288 | then client socket set SO_DONTROUTE socket option,so does the server 289 | */ 290 | 291 | close(sockfd); 292 | 293 | // rebuild up the socket 294 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 295 | err_sys("[ERROR]: Build socket error, program terminated."); 296 | else 297 | printf("[INFO]: Rebuild the socket...\n"); 298 | 299 | // reset socket option SO_REUSEADDR. 300 | if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 301 | err_sys("[Error]: Setting SO_REUSEADDR socket option error."); 302 | 303 | //rebind the socket to the loopback address 304 | bzero(&cliaddr, sizeof(cliaddr)); 305 | cliaddr.sin_family = AF_INET; 306 | cliaddr.sin_port = htons(pnum); 307 | if (inet_pton(AF_INET, cif[1].cif_bound, &cliaddr.sin_addr) <= 0) 308 | err_quit("[ERROR]: main: inet_pton error"); 309 | if(bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)) < 0) 310 | err_sys("[ERROR]: bind error..."); 311 | 312 | bzero(&servaddr, sizeof(servaddr)); 313 | servaddr.sin_family = AF_INET; 314 | servaddr.sin_port = htons(input_file.port_num); 315 | if(inet_pton(AF_INET, input_file.server_address, &servaddr.sin_addr) <= 0) 316 | err_sys("[ERROR]: inet_pton error..."); 317 | 318 | strcpy(mesg, strcat(buf, subaddr(cif[1].cif_bound, cif[1].cif_ntm))); 319 | //snprintf(mesg, sizeof(mesg), strcat(buf, subaddr(cif[1].cif_bound, cif[1].cif_ntm))); 320 | 321 | i = 0; 322 | 323 | init2: if(sendto(sockfd, mesg, strlen(mesg), 0, (SA *) &servaddr, sizeof(servaddr)) < 0) 324 | err_sys("[INIT_CON]: sendto error..."); 325 | else{ 326 | printf("%s is send to server.\n", mesg); 327 | 328 | tm.tv_sec = WAIT_TIME; 329 | tm.tv_usec = 0; 330 | FD_ZERO(&rset); 331 | FD_SET(sockfd, &rset); 332 | if((n = select(sockfd+1, &rset, NULL, NULL, &tm)) < 0){ 333 | if(errno == EINTR) 334 | printf("[ERROR]: EINTR..."); 335 | else 336 | err_sys("[ERROR]: select error..."); 337 | } 338 | 339 | if(FD_ISSET(sockfd, &rset)){ 340 | len = sizeof(servaddr); 341 | if((n = recvfrom(sockfd, mesg, DGRAM_LEN, 0, (SA *) &servaddr, &len)) < 0) 342 | err_sys("[ERROR]:hs_pnum_s: recvfrom error..."); 343 | mesg[n] = 0; 344 | ack = mesg; 345 | if(!strcmp(ack, "LOCAL_HOST")){ 346 | printf("[INFO]: Receive the ACK from server: [%s]\n", mesg); 347 | 348 | close(sockfd); 349 | 350 | // rebuild up the socket 351 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 352 | err_sys("[ERROR]: Build socket error, program terminated."); 353 | else 354 | printf("[INFO]: Rebuild the socket...\n"); 355 | 356 | // reset socket option SO_REUSEADDR. 357 | if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 358 | err_sys("[Error]: Setting SO_REUSEADDR socket option error."); 359 | 360 | //set up the socket option SO_DONTROUTE 361 | if(setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)) < 0) 362 | err_sys("[Error]: Setting SO_DONTROUTE socket option error."); 363 | else 364 | printf("[INFO]: The socket option SO_DONTROUTE is set up...\n"); 365 | 366 | bzero(&cliaddr, sizeof(cliaddr)); 367 | cliaddr.sin_family = AF_INET; 368 | cliaddr.sin_port = htons(pnum); 369 | if (inet_pton(AF_INET, cif[1].cif_bound, &cliaddr.sin_addr) <= 0)//default the first interface address 370 | err_sys("[ERROR]: main: inet_pton error for %s", cif[1].cif_bound); 371 | 372 | //bind the socket to the designated client IP address 373 | if(bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)) < 0) 374 | err_sys("[ERROR]: bind error..."); 375 | 376 | len = sizeof(cliaddr); 377 | if(getsockname(sockfd, (SA *) &cliaddr, &len) < 0) 378 | err_sys("[ERROR]: getsockname error..."); 379 | printf("[INFO]: Rebind to %s: success\n", sock_ntop((SA *) &cliaddr, sizeof(cliaddr))); 380 | 381 | bzero(&servaddr, sizeof(servaddr)); 382 | servaddr.sin_family = AF_INET; 383 | servaddr.sin_port = htons(input_file.port_num); 384 | if(inet_pton(AF_INET, input_file.server_address, &servaddr.sin_addr) <= 0) 385 | err_sys("[ERROR]: inet_pton error..."); 386 | 387 | if(connect_timeo(sockfd, (SA *) &servaddr, sizeof(servaddr), CONN_TIME_OUT) < 0) 388 | err_sys("[ERROR]: connect error..."); 389 | 390 | peerlen = sizeof(peeraddr); 391 | getpeername(sockfd, (SA *) &peeraddr, &peerlen); 392 | printf("Connets to %s: success\n", sock_ntop((SA *) &peeraddr, peerlen)); 393 | printf("---------------------------------\n"); 394 | } 395 | 396 | else if(!strcmp(ack, "COMM_HOST")){ 397 | printf("Receive the ACK from server: [%s]\n", mesg); 398 | 399 | close(sockfd); 400 | 401 | // rebuild up the socket 402 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 403 | err_sys("[ERROR]: Build socket error, program terminated."); 404 | else 405 | printf("[INFO]: Rebuild the socket...\n"); 406 | 407 | // reset socket option SO_REUSEADDR. 408 | if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 409 | err_sys("[ERROR]: Setting SO_REUSEADDR socket option error."); 410 | 411 | //common connection application 412 | bzero(&cliaddr, sizeof(cliaddr)); 413 | cliaddr.sin_family = AF_INET; 414 | cliaddr.sin_port = htons(pnum); 415 | if (inet_pton(AF_INET, cif[1].cif_bound, &cliaddr.sin_addr) <= 0)//default the first interface address 416 | err_sys("[ERROR]: main: inet_pton error for %s", cif[1].cif_bound); 417 | 418 | //bind the socket to the designated client IP address 419 | if(bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)) < 0) 420 | err_sys("[ERROR]: bind error..."); 421 | 422 | len = sizeof(cliaddr); 423 | if(getsockname(sockfd, (SA *) &cliaddr, &len) < 0) 424 | err_sys("[ERROR]: getsockname error..."); 425 | printf("[INFO]: Rebind to %s: success\n", sock_ntop((SA *) &cliaddr, sizeof(cliaddr))); 426 | 427 | if(connect_timeo(sockfd, (SA *) &servaddr, sizeof(servaddr), CONN_TIME_OUT) < 0) 428 | err_sys("[ERROR]: connect error..."); 429 | 430 | peerlen = sizeof(peeraddr); 431 | getpeername(sockfd, (SA *) &peeraddr, &peerlen); 432 | printf("[INFO]: Connets to %s: success\n", sock_ntop((SA *) &peeraddr, peerlen)); 433 | printf("---------------------------------\n"); 434 | } 435 | 436 | else{ 437 | printf("[ERROR]: UNKOWN ACK: %s\n", mesg); 438 | exit(0); 439 | } 440 | } 441 | else if(n == 0){ 442 | if(i > 12){ 443 | errno = ETIMEDOUT; 444 | err_quit("[ERROR]: No response from the server, giving up."); 445 | }else{ 446 | printf("[INIT_CON] time out!\nRetry the requset...\n"); 447 | i++; 448 | goto init2; 449 | } 450 | } 451 | } 452 | } 453 | 454 | //handshake: receive the new port number and reconnect to the child server 455 | hs_pnum_c(sockfd, cliaddr, servaddr); 456 | 457 | //ftp process 458 | data_req(sockfd); 459 | close(sockfd); 460 | pthread_join(tid, NULL); 461 | fclose(fn); 462 | exit(0); 463 | } 464 | 465 | 466 | void prifsif(struct cliIF *cif, int snum){ 467 | int i; 468 | printf("\n----- Local interface Info. -----\n"); 469 | for(i = 0; i < snum; i++){ 470 | printf("* Interface %d:\n", i+1); 471 | printf("\tThe IP address:\t\t%s;\n", cif[i].cif_bound); 472 | printf("\tThe network mask:\t%s;\n", cif[i].cif_ntm); 473 | } 474 | printf("---------------------------------\n\n"); 475 | return; 476 | } 477 | 478 | char* subaddr(char *ipaddr, char *ntmaddr){ 479 | char *snaddr; 480 | struct in_addr inaddr; 481 | 482 | inaddr.s_addr= inet_addr(ipaddr) & inet_addr(ntmaddr); 483 | snaddr = inet_ntoa(inaddr); 484 | return snaddr; 485 | } 486 | 487 | void hs_pnum_c(int sockfd, struct sockaddr_in cliaddr, struct sockaddr_in servaddr){ 488 | int n, pnum; 489 | char mesg[DGRAM_LEN]; 490 | socklen_t len; 491 | 492 | //receive the port number 493 | len = sizeof(cliaddr); 494 | printf("[INFO]: waiting port number...\n"); 495 | if((n = recv(sockfd, mesg, DGRAM_LEN, 0)) < 0) 496 | perror("hs_pnum_c: recv error..."); 497 | else{ 498 | mesg[n] = 0; //null terminate 499 | printf("[INFO]: Receive the new port number %s from server\n", mesg); 500 | } 501 | 502 | //reconnect 503 | pnum = atoi(mesg); 504 | servaddr.sin_port = htons(pnum); 505 | if(connect_timeo(sockfd, (SA *) &servaddr, sizeof(servaddr), CONN_TIME_OUT) < 0) 506 | err_sys("[ERROR]: connect error..."); 507 | else 508 | printf("[INFO]: Reconnect to the new port: success\n"); 509 | 510 | //reply the ack 511 | snprintf(mesg, sizeof(mesg), "ACK_PNUM"); 512 | if(send(sockfd, mesg, sizeof(mesg), 0) < 0) 513 | err_sys("[ERROR]: hs_pnum_c: send error..."); 514 | else 515 | printf("[INFO]: Reply the ACK to the server...\n"); 516 | 517 | printf("---------------------------------\n"); 518 | } 519 | 520 | 521 | void data_req(int sockfd){ 522 | int i, eofflag, n = 0; 523 | char *choice, sendline[DGRAM_LEN], recvline[DGRAM_LEN], *ack; 524 | uint32_t lastackpacket; 525 | size_t dg_size = DGRAM_LEN; 526 | struct hdr recvhdr; 527 | fd_set rset; 528 | struct timeval tm; 529 | char * fpname = input_file.file_name; 530 | 531 | printf("[INFO]: The file request: %s\n", fpname); 532 | 533 | printf("---------------------------------\n"); 534 | 535 | i = 0; 536 | 537 | filereq: if((n = send(sockfd, fpname, strlen(fpname)+1, 0)) < 0){ 538 | err_sys("[ERROR]: data_req: send error..."); 539 | } else { 540 | tm.tv_sec = WAIT_TIME; 541 | tm.tv_usec = 0; 542 | FD_ZERO(&rset); 543 | FD_SET(sockfd, &rset); 544 | if((n = select(sockfd+1, &rset, NULL, NULL, &tm)) < 0){ 545 | if(errno == EINTR){ 546 | printf("[WARNING]: Ignored EINTR signal"); 547 | } else { 548 | err_sys("[ERROR]: Select function error"); 549 | } 550 | } 551 | if(FD_ISSET(sockfd, &rset)){ 552 | if((n = recv(sockfd, recvline, DGRAM_LEN, 0)) < 0){ 553 | err_sys("[ERROR]: data_req: recv error..."); 554 | } else { 555 | ack = recvline; 556 | if(!strcmp(ack, "NO_FILE")){ 557 | printf("[Error]: cannot find the designated file...\n"); 558 | exit(0); 559 | } else if (!strcmp(ack, "YES_FILE")) { 560 | printf("*The file exists in the server*\n"); 561 | } else { 562 | err_quit("UNKOWN ACK"); 563 | } 564 | } 565 | }else if (n == 0){ 566 | if(i > 12){ 567 | errno = ETIMEDOUT; 568 | err_quit("[ERROR]: No response from the server, giving up."); 569 | }else{ 570 | printf("File requset time out!\nResend the requset...\n"); 571 | i++; 572 | goto filereq; 573 | } 574 | } 575 | 576 | //receive the data 577 | printf("**Enter transmission mode**:\n"); 578 | bzero(buffflag, RESIVE_BUFF_SIZE); 579 | lastackpacket = 0; 580 | wroteposition = 0; 581 | eofflag = 0; 582 | pthread_create(&tid, NULL, consume_buff, NULL); 583 | 584 | for (;;){ 585 | recvhdr = cli_recv( sockfd, recivebuff[lastackpacket-wroteposition], dg_size); 586 | buffflag[(recvhdr.seq)-wroteposition] = 1; 587 | printf("[INFO]: Received data sequence:%d\n", recvhdr.seq); 588 | 589 | lastackpacket = get_last_ack_packet_bias(buffflag)+wroteposition; 590 | 591 | if (cli_send(sockfd, lastackpacket, recvhdr.ts, NULL, 0)<0){ 592 | err_sys("[ERROR:] Send packet error"); 593 | } 594 | 595 | if (recvhdr.fin==1){ 596 | buffflag[(recvhdr.seq)-wroteposition] = 2; 597 | eofflag = 1; 598 | break; 599 | } 600 | pthread_cond_signal(&accessbuff_cond); 601 | } 602 | printf("**End transmission mode**:\n"); 603 | } 604 | } 605 | 606 | struct client_in get_input_file(){ 607 | FILE * file = fopen(INPUT_FILE_NAME, "r"); 608 | char temp[DGRAM_LEN]; 609 | 610 | if (file == NULL){ 611 | err_sys("[ERROR]: Read input file error, program terminated."); 612 | } 613 | 614 | if (fgets ( temp, sizeof temp, file ) != NULL){ 615 | temp[strlen(temp)-1] = '\0'; 616 | strcpy(input_file.server_address, temp); 617 | } else{ 618 | err_sys("[ERROR]: Read server address in file error, program terminated."); 619 | } 620 | 621 | if (fgets( temp, sizeof temp, file ) != NULL){ 622 | input_file.port_num = atoi(temp); 623 | } else{ 624 | err_sys("[ERROR]: Read port number in file error, program terminated."); 625 | } 626 | 627 | if (fgets( temp, sizeof temp, file ) != NULL){ 628 | temp[strlen(temp)-1] = '\0'; 629 | strcpy(input_file.file_name, temp); 630 | } else{ 631 | err_sys("[ERROR]: Read file name in file error, program terminated."); 632 | } 633 | 634 | if (fgets( temp, sizeof temp, file ) != NULL){ 635 | input_file.window_size = atoi(temp); 636 | } else{ 637 | err_sys("[ERROR]: Read sliding-window size in file error, program terminated."); 638 | } 639 | 640 | if (fgets( temp, sizeof temp, file ) != NULL){ 641 | input_file.seed_value = atoi(temp); 642 | } else{ 643 | err_sys("[ERROR]: Read seed value in file error, program terminated."); 644 | } 645 | 646 | if (fgets( temp, sizeof temp, file ) != NULL){ 647 | input_file.p_loss = atof(temp); 648 | } else{ 649 | err_sys("[ERROR]: Read datagram loss probability in file error, program terminated."); 650 | } 651 | 652 | if (fgets( temp, sizeof temp, file ) != NULL){ 653 | input_file.receive_rate = atoi(temp); 654 | } else{ 655 | err_sys("[ERROR]: Read receive rate parameter in file error, program terminated."); 656 | } 657 | 658 | return input_file; 659 | } 660 | 661 | struct timespec sleeptime(){ 662 | int mu = input_file.receive_rate; 663 | double random_value = (double)rand()/(double)RAND_MAX; 664 | struct timespec time_to_sleep; 665 | int stime; 666 | 667 | stime = (int) -1*mu*log(random_value); 668 | time_to_sleep.tv_sec = stime/1000; 669 | time_to_sleep.tv_nsec = stime%1000 * 1000000; 670 | 671 | return time_to_sleep; 672 | } 673 | 674 | uint32_t get_last_ack_packet_bias(char *flag){ 675 | uint32_t lastackpacket; 676 | for (lastackpacket=0; lastackpacket