src/mrt.c
// mrt_connect: connect to a given server (return a connection)
// always return a connection, check if it's an active connection before use
// empty connection on fail
// ip_addr, reserved
connect to a given server (return a connection)
always return a connection, check if it's an active connection before use
empty connection on fail
ip_addr, reserved
connect to a given server ( return a connection ) always return a connection check if it ' s an active connection before use empty connection on fail ip_addr reserved
mrt_connection * mrt_connect(int ip_addr, int PORT_NUM) {
  int isn, pid, sockfd; 
  int timeout;
  time_t t;
  struct timespec start, curr;
  struct sockaddr_in cliaddr, sendaddr, recvaddr;
  socklen_t len = sizeof(struct sockaddr_in);
  mrt_packet * pkt; 
  setbuf(stdout, (char *)0);
  srand((unsigned) time(&t));
  isn = rand() % 1024;
  mrt_connection * rc = mmap(NULL, sizeof(mrt_connection), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  memset(rc, 0, sizeof(mrt_connection));
  rc->addr.sin_addr.s_addr = INADDR_ANY;
  rc->addr.sin_port = htons(PORT_NUM);
  rc->addr.sin_family = AF_INET;
  fill_addr(&sendaddr, "", 0);
  fill_addr(&recvaddr, "", 0);
  if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
      perror("socket creation failed"); 
      exit(EXIT_FAILURE); 
  }
  if (bind(sockfd, (const struct sockaddr *)&recvaddr, sizeof(struct sockaddr_in)) == -1) {
    perror("bind sockfd");
  }
  rc->fd = sockfd;
  if ((pid = fork())) {
    rc->pid = pid;
    timeout = 0;
    clock_gettime(CLOCK_REALTIME, &start);
    while(!timeout) {
      send_ctrl_pkt(sockfd, &rc->addr, FLAG_SYN, isn, 0);
      if (rc->active) break;
      nanosleep((const struct timespec[]){0, 1e8L}, NULL);
      clock_gettime(CLOCK_REALTIME, &curr);
      if ((long)curr.tv_sec - (long)start.tv_sec >= SYN_TIMEOUT) timeout++;
    }
    if (timeout) {
      if (!rc->pid) printf("Server is down.\n");
      else {
        kill(pid, SIGKILL);
        printf("Server unreachable.\n");
        close(sockfd);
        memset(rc, 0, sizeof(mrt_connection));
        return NULL;
      }
    }
  } else {
    pkt = (mrt_packet *)malloc(sizeof(mrt_packet));
    memset(pkt, 0, sizeof(mrt_packet));
    while ((recvfrom(sockfd, (char *)pkt, sizeof(mrt_packet),  
              MSG_WAITALL, ( struct sockaddr *) &cliaddr, 
              &len)) != -1) {
      if (MRT_TEST) print_pkt(pkt);
      if (cliaddr.sin_port == htons(PORT_NUM)) {
        switch (pkt->header.flags) {
          case FLAG_SYN | FLAG_ACK:
            memcpy(&rc->addr, &cliaddr, sizeof(struct sockaddr_in));
            rc->active = 1;
            rc->base = -1;
            rc->rcvwnd = pkt->header.rcvwnd;
            rc->offset = isn;
            break;
          case FLAG_FIN:
            close(sockfd);
            memset(rc, 0, sizeof(mrt_connection));
            printf("The connection is terminated by the server.\n");
            exit(0);
            break;
          case FLAG_FIN | FLAG_ACK:
            rc->initialized = 1;
            break;
          case FLAG_ACK:
            if ((pkt->header.seq - rc->offset - 1) > rc->base) rc->base = pkt->header.seq - rc->offset - 1;  
            rc->rcvwnd = pkt->header.rcvwnd;
            break;
        }
      }
    }
  }
  return rc;
}
mrt_connection * mrt_connect ( int ip_addr , int PORT_NUM ) { int isn , pid , sockfd ; int timeout ; time_t t ; struct timespec start , curr ; struct sockaddr_in cliaddr , sendaddr , recvaddr ; socklen_t len = sizeof ( struct sockaddr_in ) ; mrt_packet * pkt ; setbuf ( stdout , ( char * ) 0 ) ; srand ( ( unsigned ) time ( & t ) ) ; isn = rand ( ) % 1024 ; mrt_connection * rc = mmap ( NULL , sizeof ( mrt_connection ) , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS , -1 , 0 ) ; memset ( rc , 0 , sizeof ( mrt_connection ) ) ; rc -> addr . sin_addr . s_addr = INADDR_ANY ; rc -> addr . sin_port = htons ( PORT_NUM ) ; rc -> addr . sin_family = AF_INET ; fill_addr ( & sendaddr , " " , 0 ) ; fill_addr ( & recvaddr , " " , 0 ) ; if ( ( sockfd = socket ( AF_INET , SOCK_DGRAM , 0 ) ) < 0 ) { perror ( " " ) ; exit ( EXIT_FAILURE ) ; } if ( bind ( sockfd , ( const struct sockaddr * ) & recvaddr , sizeof ( struct sockaddr_in ) ) == -1 ) { perror ( " " ) ; } rc -> fd = sockfd ; if ( ( pid = fork ( ) ) ) { rc -> pid = pid ; timeout = 0 ; clock_gettime ( CLOCK_REALTIME , & start ) ; while ( ! timeout ) { send_ctrl_pkt ( sockfd , & rc -> addr , FLAG_SYN , isn , 0 ) ; if ( rc -> active ) break ; nanosleep ( ( const struct timespec [ ] ) { 0 , 1e8L } , NULL ) ; clock_gettime ( CLOCK_REALTIME , & curr ) ; if ( ( long ) curr . tv_sec - ( long ) start . tv_sec >= SYN_TIMEOUT ) timeout ++ ; } if ( timeout ) { if ( ! rc -> pid ) printf ( " \n " ) ; else { kill ( pid , SIGKILL ) ; printf ( " \n " ) ; close ( sockfd ) ; memset ( rc , 0 , sizeof ( mrt_connection ) ) ; return NULL ; } } } else { pkt = ( mrt_packet * ) malloc ( sizeof ( mrt_packet ) ) ; memset ( pkt , 0 , sizeof ( mrt_packet ) ) ; while ( ( recvfrom ( sockfd , ( char * ) pkt , sizeof ( mrt_packet ) , MSG_WAITALL , ( struct sockaddr * ) & cliaddr , & len ) ) != -1 ) { if ( MRT_TEST ) print_pkt ( pkt ) ; if ( cliaddr . sin_port == htons ( PORT_NUM ) ) { switch ( pkt -> header . flags ) { case FLAG_SYN | FLAG_ACK : memcpy ( & rc -> addr , & cliaddr , sizeof ( struct sockaddr_in ) ) ; rc -> active = 1 ; rc -> base = -1 ; rc -> rcvwnd = pkt -> header . rcvwnd ; rc -> offset = isn ; break ; case FLAG_FIN : close ( sockfd ) ; memset ( rc , 0 , sizeof ( mrt_connection ) ) ; printf ( " \n " ) ; exit ( 0 ) ; break ; case FLAG_FIN | FLAG_ACK : rc -> initialized = 1 ; break ; case FLAG_ACK : if ( ( pkt -> header . seq - rc -> offset - 1 ) > rc -> base ) rc -> base = pkt -> header . seq - rc -> offset - 1 ; rc -> rcvwnd = pkt -> header . rcvwnd ; break ; } } } } return rc ; }
mrt_connect: connect to a given server (return a connection)
always return a connection, check if it's an active connection before use
empty connection on fail
ip_addr, reserved
mrt_connect : connect to a given server ( return a connection ) always return a connection check if it ' s an active connection before use empty connection on fail ip_addr reserved
// to store incoming packets // the addr should be checked here too // save the packet // close the connection, and stop transmitting data // server acked the disconnection // data control, adjust base, send ack, seq, rcvwnd