int main(int argc, char *argv[]) { int sockfd; int portno, n_char; int slen; struct sockaddr_in serv_addr; struct hostent *server; char *hostname, *filepath; double p_loss, p_corrupt; p_loss = 0.0; p_corrupt = 0.0; int expect_seq_num; struct packet snd_pkt, rcv_pkt; FILE* file; if (argc < 4) { fprintf(stderr, "Usage: %s hostname port filepath [loss ratio] [corrupt ratio]\n", argv[0]); exit(0); } switch (argc) { case 6: p_corrupt = atof(argv[5]); case 5: p_loss = atof(argv[4]); default: filepath = argv[3]; portno = atoi(argv[2]); hostname = argv[1]; break; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); // Using UDP! if (sockfd < 0) { error("Error opening socket"); } server = gethostbyname(hostname); if (server == NULL) { fprintf(stderr, "Error: no such host\n"); exit(0); } bzero((char *)&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); // Create the initial packet expect_seq_num = 1; snd_pkt = make_packet(); set_syn(&snd_pkt); snd_pkt.seq_num = 0; set_data(&snd_pkt, filepath, strlen(filepath)); slen = sizeof(serv_addr); char str[100] = "copy_"; char *dirc, *basec, *dname, *bname; dirc = strdup(filepath); basec = strdup(filepath); dname = dirname(dirc); bname = basename(basec); file = fopen(strcat(str, bname), "wb"); // Send the initial packet msg("Sending file request to sender...\n"); n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, slen); if (n_char < 0) { error("Error sending packet"); } // Go-Back-N FSM while (1) { // Wait to receive a message // if (rcv_pkt) // { // free(rcv_pkt); // } rcv_pkt = make_packet(); n_char = recvfrom(sockfd, &rcv_pkt, sizeof(rcv_pkt), 0, (struct sockaddr*)&serv_addr, (socklen_t*)&slen); if (check_none(&rcv_pkt)) { msg("No such file exists on the sender side\n"); fclose(file); remove(str); teardown(NULL, sockfd); } if (check_fin(&rcv_pkt)) // server closing connection { msg("-> FIN\n"); msg("<- FIN-ACK ...\n"); //free(&snd_pkt); snd_pkt = make_packet(); set_fin(&snd_pkt); n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (n_char < 0) { error("Error sending FIN-ACK"); } //free(&rcv_pkt); //free(&snd_pkt); teardown(file, sockfd); break; } if (n_char < 0) { msg("Packet from sender LOST\n"); } else if (chance() < p_loss) { msg("Packet from sender LOST\n"); } else if (chance() < p_corrupt) { msg("Packet from sender CORRUPT\n"); msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num); int n_char; n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (n_char < 0) { error("Error acking packet\n"); } } else if (rcv_pkt.seq_num == expect_seq_num) { msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num); fwrite(rcv_pkt.data, 1, rcv_pkt.d_length, file); expect_seq_num++; //free(&snd_pkt); snd_pkt = make_packet(); set_ack(&snd_pkt); snd_pkt.seq_num = rcv_pkt.seq_num; send_ack(sockfd, snd_pkt, serv_addr); } else if (rcv_pkt.seq_num < expect_seq_num) { msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num); //free(&snd_pkt); snd_pkt = make_packet(); set_ack(&snd_pkt); snd_pkt.seq_num = rcv_pkt.seq_num; msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num); int n_char; n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (n_char < 0) { error("Error acking packet\n"); } } else { msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num); msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num); int n_char; n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (n_char < 0) { error("Error acking packet\n"); } } } }
// return 1 on success, -1 if queue is_full, 0 for other failure int ErrorControl::send(char ecPlayerId, void *dataPtr, long unsigned int dataLen) { if( connecting_player_count == 0) return 1; if( send_queue_space() < MAX_QUEUE/2) { #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 1) DEBUG_LOG("ec_remote.send() fail, buffer half full"); #endif return -1; } int frameId = en_send_queue(); if( frameId < 0) { #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 1) DEBUG_LOG("ec_remote.send() fail, buffer full"); #endif return frameId; } else { // -------- add buffer to queue --------- // err_when( frameId >= MAX_QUEUE ); VLenQueue &sq = send_queue[frameId]; sq.clear(); char *ecMsg = sq.reserve( sizeof(EcMsgHeader) + dataLen + CRC_LEN ); ((EcMsgHeader *)ecMsg)->init( FIRST_SEND, self_ec_player_id, frameId ); memcpy( ecMsg + sizeof(EcMsgHeader), dataPtr, dataLen ); *((CRC_TYPE *) (ecMsg + sizeof(EcMsgHeader) + dataLen) ) = crc8((unsigned char *)ecMsg, sizeof(EcMsgHeader) + dataLen); // ------- clear all ack flags of that frame --------// PID_TYPE toDPid = BROADCAST_PID; clear_ack( frameId ); if( ecPlayerId != 0) { toDPid = dp_id[ecPlayerId]; err_when(toDPid == BROADCAST_PID); for(char p = 1; p <= MAX_PLAYER; ++p) if( p != ecPlayerId ) set_ack(p, frameId); } // ------- try to send the data for the first time ------- // if( mp_ptr->send(toDPid, sq.queue_buf, sq.length()) ) { // mark send time mark_send_time(frameId, TIME_OUT ); #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 3) debugStr = "ec_remote.send() successful, frame "; debugStr += frameId; DEBUG_LOG(debugStr); #endif // mark the func_id of the message RE_SEND ((EcMsgHeader *)ecMsg)->func_id = RE_SEND; // recalculate CRC *((CRC_TYPE *) (ecMsg + sizeof(EcMsgHeader) + dataLen) ) = crc8((unsigned char *)ecMsg, sizeof(EcMsgHeader) + dataLen); } else { // mark send time, mark a shorter time mark_send_time(frameId, SHORT_TIME_OUT); #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2) debugStr = "ec_remote.send() fail, frame "; debugStr += frameId; DEBUG_LOG(debugStr); #endif // still return true to sender, as it will be re-send later } } return 1; }
int main(int argc, char **argv) { int sock; struct sockaddr_in addr; char buffer[MAX_PACKET_SIZE]; int recsize; int retval; socklen_t addr_len; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1){ fprintf(stderr, "Socket failed.\n"); return -1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(UDP_PORT); retval = bind(sock,(struct sockaddr *)&addr, sizeof(addr)); if(retval != 0){ fprintf(stderr, "Socket bind failed.\n"); close(sock); return -1; } struct common_header header; struct ack_packet ack; int packet_count = 0; /* Main loop to receive packets and send back Act.*/ for(;;){ recsize = recvfrom (sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &addr_len); printf("recsize: %d\n", recsize); struct stream strm; strm.strm = buffer; strm.p = buffer; /* Read and analyze packet common header.*/ read_header(&header, &strm); sleep(1); /*Send an Act Packet every 16 successive received packets. */ if (++packet_count == 16){ set_ack(&ack); /* Set the ack contetns.*/ addr.sin_addr.s_addr = htonl(0x7F000001); /* send to address 127.0.0.1 */ addr.sin_port = htons(UDP_PORT); int byte_sent = sendto(sock, &ack, sizeof(ack), 0, (struct sockaddr *)&addr, addr_len); if (byte_sent < 0) fprintf(stderr, "Error sending Act Packet. \n"); addr.sin_addr.s_addr = INADDR_ANY; /* Set address back to recvfrom */ addr.sin_port = htons(UDP_PORT); packet_count = 0; } } }
void ErrorControl::yield() { // -------- receive any frame from dplay -----------// char *recvPtr; uint32_t recvLen; PID_TYPE from; static int simError = 1; // check any player lost // ##### begin Gilbert 2/5 ########// int sysMsgCount; int p; // detect any player lost, detected previous mp_ptr->send for( p = 1; p <= MAX_PLAYER; ++p) { if( dp_id[p-1] && !mp_ptr->is_player_connecting(dp_id[p-1]) ) { set_player_lost(p); } } while( (recvPtr = mp_ptr->receive(&from, &recvLen, &sysMsgCount)) != NULL || sysMsgCount != 0) { // -------- detect any player lost ---------// if( sysMsgCount ) { for( p = 1; p <= MAX_PLAYER; ++p) { if( dp_id[p-1] && !mp_ptr->is_player_connecting(dp_id[p-1]) ) { set_player_lost(p); } } } if( !recvPtr ) break; // only received system message from direct play // ##### end Gilbert 2/5 ########// // -------- receive the message ----------// #ifdef DEBUG // simulate crc error // if( ++simError >= 10) // simError = 0; #endif if( simError && !crc8((unsigned char *)recvPtr, recvLen)) { // crc correct EcMsgHeader ecMsg = *(EcMsgHeader *)recvPtr; switch( ecMsg.func_id ) { case FIRST_SEND: // accept except frameId is wait_to_receive -1 or recv_flag is set if( is_waiting_receive( ecMsg.sender_id, ecMsg.frame_id ) ) { err_when( ecMsg.sender_id <= 0 || ecMsg.sender_id > MAX_PLAYER); #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 3 ) debugStr = "ec_remote : FIRST_SEND received, from:"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " accepted"; DEBUG_LOG(debugStr); #endif if( !is_recv_full() ) { if( dp_id[ecMsg.sender_id-1] ) { // mark recv_flag set_recv_flag(ecMsg.sender_id, ecMsg.frame_id); // send ACK char replyMsg[sizeof(EcMsgHeader) + CRC_LEN]; ((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id); *((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader)); mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) ); if( ecMsg.frame_id == wait_to_receive[ecMsg.sender_id-1] ) { // clear recv_flag, until it is zero char &scanFrame = wait_to_receive[ecMsg.sender_id-1]; for( ; recv_flag[ecMsg.sender_id-1][scanFrame]; inc_frame_id(scanFrame) ) clear_recv_flag( ecMsg.sender_id, prev_frame_id(scanFrame) ); } } // append the queue to receive queue en_recv_queue(recvPtr, recvLen); } else { // drop the message if the receive queue is full #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) DEBUG_LOG("ec_remote : but receive_queue is full, discard message"); #endif } } else { #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : FIRST_SEND received, from:"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " discarded"; DEBUG_LOG(debugStr); #endif // some frame before are missing, wait resend // discard the frame, but reply, for the sender not to // send the frame again if( dp_id[ecMsg.sender_id-1] ) { // send ACK char replyMsg[sizeof(EcMsgHeader) + CRC_LEN]; ((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id); *((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader)); mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) ); } } break; case RE_SEND: // accept except frameId is wait_to_receive -1 or recv_flag is set if( is_waiting_receive( ecMsg.sender_id, ecMsg.frame_id ) ) { #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : RE_SEND received, from:"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " accepted"; DEBUG_LOG(debugStr); #endif err_when( ecMsg.sender_id <= 0 || ecMsg.sender_id > MAX_PLAYER); if( !is_recv_full() ) { if( dp_id[ecMsg.sender_id-1] ) { // mark recv_flag set_recv_flag(ecMsg.sender_id, ecMsg.frame_id); // send ACK char replyMsg[sizeof(EcMsgHeader) + CRC_LEN]; ((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id); *((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader)); mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) ); if( ecMsg.frame_id == wait_to_receive[ecMsg.sender_id-1] ) { // clear recv_flag, until it is zero char &scanFrame = wait_to_receive[ecMsg.sender_id-1]; for( ; recv_flag[ecMsg.sender_id-1][scanFrame]; inc_frame_id(scanFrame) ) clear_recv_flag( ecMsg.sender_id, prev_frame_id(scanFrame) ); } } // append the queue to receive queue en_recv_queue(recvPtr, recvLen); } else { // drop the message if the receive queue is full #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) DEBUG_LOG("ec_remote : but receive_queue is full, discard message"); #endif } } else { #if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : RE_SEND received, from:"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " discarded"; DEBUG_LOG(debugStr); #endif // re-dundant frame, discard, but still reply ACK, // for the sender not to send the frame again if( dp_id[ecMsg.sender_id-1] ) { // send ACK char replyMsg[sizeof(EcMsgHeader) + CRC_LEN]; ((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id); *((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader)); mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) ); } } break; case ACKNOW: // mark the frame ack if( is_waiting_ack(ecMsg.sender_id, ecMsg.frame_id) ) { #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 3 ) debugStr = "ec_remote : ACKNOW received"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " accepted"; DEBUG_LOG(debugStr); #endif set_ack(ecMsg.sender_id, ecMsg.frame_id); clear_acked_frame(); } else { // discard the frame #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : ACKNOW received"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " discarded"; DEBUG_LOG(debugStr); #endif } break; case NEGACK: // re-send only the frameId if( is_waiting_ack(ecMsg.sender_id, ecMsg.frame_id) ) { #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : NEGACK received"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " accepted"; DEBUG_LOG(debugStr); #endif char *replyMsg = send_queue[ecMsg.frame_id].queue_buf; DWORD replyLen = send_queue[ecMsg.frame_id].length(); mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, replyLen ); err_when( replyLen <= sizeof(EcMsgHeader) ); // don't mark re-send time // mark the func_id of the message RE_SEND ((EcMsgHeader *)replyMsg)->func_id = RE_SEND; // recalculate CRC *((CRC_TYPE *) (replyMsg + replyLen - CRC_LEN) ) = crc8((unsigned char *)replyMsg, replyLen - CRC_LEN); DEBUG_LOG("ec_remote : frame retransmitted"); } else { #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 ) debugStr = "ec_remote : NEGACK received"; debugStr += ecMsg.sender_id; debugStr += " frame:"; debugStr += ecMsg.frame_id; debugStr += " discarded"; DEBUG_LOG(debugStr); #endif } break; default: err_here(); } } else { // crc incorrect if( recvLen > sizeof(EcMsgHeader) + CRC_LEN ) { char senderId = get_ec_player_id(from); if( senderId) { // send NEGACK frame char replyMsg[sizeof(EcMsgHeader) + CRC_LEN]; ((EcMsgHeader *)replyMsg)->init(NEGACK, self_ec_player_id, wait_to_receive[senderId-1]); *((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader)); mp_ptr->send( dp_id[senderId-1], replyMsg, sizeof(replyMsg) ); } #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2) DEBUG_LOG("ec_remote : long packet corrupted" ); #endif } else { // it is probably, ACKNOW/ NEGACK frame, discard it #if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2) DEBUG_LOG("ec_remote : short packet corrupted" ); #endif } } } // ------ retransmit any un-acked and time-out-ed frame -------// clear_acked_frame(); re_transmit(); }
void *ack_receiver_thread(void *params) { struct ack_receiver_thread_parameter *p = (struct ack_receiver_thread_parameter *) params; int *sockfd = p->sockfd; unsigned long long *chunks_ack_count = p->chunks_ack_count; unsigned long long *total_chunks = p->total_chunks; unsigned long long *chunk_id_first_unacked = p->chunk_id_first_unacked; unsigned char *required_acks = p->required_acks; unsigned char **chunks_ack = p->chunks_ack; unsigned char **chunk_cache = p->chunk_cache; pthread_mutex_t **chunk_cache_mutex = p->chunk_cache_mutex; size_t header_length = sizeof(struct layer2) + sizeof(struct layer3) + sizeof(struct layer4_udp); unsigned int i; unsigned char buffer[header_length + (*required_acks * FSCP_UDP_ID_BYTES)]; unsigned long long chunk_id = 0L; size_t recvlen; unsigned long long progress = 101; struct layer4_udp *buffer_l4 = (struct layer4_udp *) (buffer + sizeof(struct layer2) + sizeof(struct layer3)); uchar_t *buffer_payload = buffer + header_length; // Receive ACK while (*chunks_ack_count < *total_chunks) { recvlen = recv(*sockfd, buffer, header_length + (*required_acks * FSCP_UDP_ID_BYTES), 0); if ((recvlen != -1UL) && (recvlen >= header_length + FSCP_UDP_ID_BYTES)) { // The packet may contain acknowledgement of more than one chunk for(i=0; ((i<ntohs(buffer_l4->len)/FSCP_UDP_ID_BYTES) && (i<*required_acks)); i++) { // Get chunk id memcpy(&chunk_id, buffer_payload + i*FSCP_UDP_ID_BYTES, FSCP_UDP_ID_BYTES); if (likely(chunk_id>0)) { if (unlikely(chunk_id == (1ULL<<(FSCP_UDP_ID_BYTES*8))-1)) { // Receive FIN *chunks_ack_count = *total_chunks; fprintf(stdout, "\b\b\b\b100%%"); break; } if (!is_ack(chunks_ack, chunk_id)) { set_ack(chunks_ack, chunk_id, true); *chunks_ack_count = *chunks_ack_count + 1; // Advance to the next unacked id if (chunk_id == *chunk_id_first_unacked) { do { *chunk_id_first_unacked = *chunk_id_first_unacked + 1; } while (is_ack(chunks_ack, *chunk_id_first_unacked)); } // Remove cache of the chunk pthread_mutex_lock(*chunk_cache_mutex+(chunk_id-1)); free(chunk_cache[chunk_id-1]); pthread_mutex_destroy(*chunk_cache_mutex+(chunk_id-1)); #ifdef _DEBUG fprintf(stdout, "[DEBUG] Recv %3llu%%: ACK 0x%.6llx\n", 100*(*chunks_ack_count)/(*total_chunks), chunk_id); #else #ifdef _PROGRESS_ENABLED if (progress != 100*(*chunks_ack_count)/(*total_chunks)) { progress = 100*(*chunks_ack_count)/(*total_chunks); fprintf(stdout, "\b\b\b\b%3llu%%", progress); fflush(stdout); } #endif #endif } } } } } return 0; }