/* *************************************************** * Function: control_loop * *************************************************** * control_loop() is the main STCP loop; it repeatedly waits for one of the * following to happen: * - incoming data from the peer * - new data from the application (via mywrite()) * - the socket to be closed (via myclose()) * - a timeout */ static void control_loop(mysocket_t sd, context_t *ctx) { assert(ctx); unsigned int event = 0; bool fin_retry = false; /* TRUE = APP_CLOSE_REQUESTED but window was full */ while (!ctx->done) { size_t bytes_in_transit = ctx->nxt_seq_num - ctx->seq_base; size_t win_space = ctx->recv_win - bytes_in_transit; event = control_wait(sd, ctx, fin_retry); if (event & NETWORK_DATA) { handle_network_data(sd, ctx); } if ((event & APP_DATA) && !fin_retry) { handle_app_data(sd, ctx); } if (event == TIMEOUT){ handle_timeout(sd, ctx); } if ((event & APP_CLOSE_REQUESTED) || fin_retry) { if (win_space>0){ send_fin(sd, ctx); fin_retry = false; } else { our_dprintf("App requested FIN but window is full\n"); fin_retry = true; } } } }
//正常关闭RUDP SOCKET void RUDPSocket::close() { switch(state_) { case RUDP_CONNECTING: case RUDP_CONNECTED: if(event_handler_ != NULL) { event_handler_->rudp_close_event(rudp_id_); } //发送SYN RUDP_INFO("close rudp socket, state = RUDP_FIN_STATE, rudp id = " << rudp_id_); set_state(RUDP_FIN_STATE); RUDP_DEBUG("send fin, rudp socket id = " << rudp_id_); send_fin(); set_timer(ccc_.get_rtt() + TIMER_MIN_DELAY); send_count_ ++; break; case RUDP_FIN2_STATE: set_state(RUDP_CLOSE); break; } }
int32_t RUDPSocket::handle_timeout(const void *act, uint32_t timer_id) { if(timer_id_ != timer_id) return 0; timer_id_= 0; //解决状态定时的问题,尤其是报文发送 switch(state_) { case RUDP_CONNECTING: if(send_count_ < SYN_MAX_COUNT) { send_syn(); set_timer(CONNECT_DELAY); RUDP_DEBUG("resend syn, rudp socket id = " << rudp_id_); send_count_ ++; } else //连接超时 { RUDP_INFO("connecting timeout! state = RUDP_FIN2_STATE, rudp id = " << rudp_id_); set_state(RUDP_FIN2_STATE); if(event_handler_ != NULL) event_handler_->rudp_exception_event(rudp_id_); else { RUDP_INFO("state = RUDP_CLOSE, rudp id = " << rudp_id_); set_state(RUDP_CLOSE); } } break; case RUDP_FIN_STATE: if(send_count_ < FIN_MAX_COUNT) { RUDP_DEBUG("resend fin, rudp socket id = " << rudp_id_); send_fin(); set_timer(ccc_.get_rtt() + TIMER_MIN_DELAY); send_count_ ++; } else { RUDP_INFO("fin timeout, state = RUDP_CLOSE, rudp id = " << rudp_id_); set_state(RUDP_CLOSE); } break; } return 0; }
//强制关闭RUDP SOCKET void RUDPSocket::force_close() { switch(state_) { case RUDP_CONNECTING: case RUDP_CONNECTED: RUDP_DEBUG("send fin, rudp socket id = " << rudp_id_); for(uint8_t i = 0; i < 6; i ++) //直接发送3个fin send_fin(); case RUDP_FIN2_STATE: RUDP_INFO("state = RUDP_CLOSE"); set_state(RUDP_CLOSE); break; } }
int libsoccr_restore(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size) { int mstate = 1 << data->state; if (libsoccr_set_sk_data_noq(sk, data, data_size)) return -1; if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_RECV_QUEUE, sk->recv_queue)) return -1; if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_SEND_QUEUE, sk->send_queue)) return -1; if (data->flags & SOCCR_FLAGS_WINDOW) { struct tcp_repair_window wopt = { .snd_wl1 = data->snd_wl1, .snd_wnd = data->snd_wnd, .max_window = data->max_window, .rcv_wnd = data->rcv_wnd, .rcv_wup = data->rcv_wup, }; if (mstate & (RCVQ_FIRST_FIN | RCVQ_SECOND_FIN)) { wopt.rcv_wup--; wopt.rcv_wnd++; } if (setsockopt(sk->fd, SOL_TCP, TCP_REPAIR_WINDOW, &wopt, sizeof(wopt))) { logerr("Unable to set window parameters"); return -1; } } /* * To restore a half closed sockets, fin packets has to be restored in * recv and send queues. Here shutdown() is used to restore a fin * packet in the send queue and a fake fin packet is send to restore it * in the recv queue. */ if (mstate & SNDQ_FIRST_FIN) restore_fin_in_snd_queue(sk->fd, mstate & SNDQ_FIN_ACKED); /* Send a fin packet to the socket to restore it in a receive queue. */ if (mstate & (RCVQ_FIRST_FIN | RCVQ_SECOND_FIN)) if (send_fin(sk, data, data_size, TH_ACK | TH_FIN) < 0) return -1; if (mstate & SNDQ_SECOND_FIN) restore_fin_in_snd_queue(sk->fd, mstate & SNDQ_FIN_ACKED); if (mstate & RCVQ_FIN_ACKED) data->inq_seq++; if (mstate & SNDQ_FIN_ACKED) { data->outq_seq++; if (send_fin(sk, data, data_size, TH_ACK) < 0) return -1; } return 0; } static int __send_queue(struct libsoccr_sk *sk, int queue, char *buf, __u32 len) { int ret, err = -1, max_chunk; int off; max_chunk = len; off = 0; do { int chunk = len; if (chunk > max_chunk) chunk = max_chunk; ret = send(sk->fd, buf + off, chunk, 0); if (ret <= 0) { if (max_chunk > 1024) { /* * Kernel not only refuses the whole chunk, * but refuses to split it into pieces too. * * When restoring recv queue in repair mode * kernel doesn't try hard and just allocates * a linear skb with the size we pass to the * system call. Thus, if the size is too big * for slab allocator, the send just fails * with ENOMEM. * * In any case -- try smaller chunk, hopefully * there's still enough memory in the system. */ max_chunk >>= 1; continue; } logerr("Can't restore %d queue data (%d), want (%d:%d:%d)", queue, ret, chunk, len, max_chunk); goto err; } off += ret; len -= ret; } while (len);
int send_data(int socket_desc, int sock_id, int pnum, struct sockaddr_in* to) { //Find out how many packets we have to send int packets_to_send = state[sock_id].last_packet[pnum]-state[sock_id].curr[pnum]->num; if (packets_to_send>state[sock_id].window_size[pnum]) packets_to_send = state[sock_id].window_size[pnum]; int i; for (i=0; i<packets_to_send; i++) { //Move to next packet in queue state[sock_id].curr[pnum] = state[sock_id].curr[pnum]->next; //Create a full RUDP packet smalloc(struct entire_rudp_packet, erp); erp->rh.seqno = htonl(state[sock_id].curr[pnum]->seqno); erp->rh.type = htons(RUDP_DATA); erp->rh.version = htons(RUDP_VERSION); erp->rpb.len = state[sock_id].curr[pnum]->rp.len; erp->rpb.data = (char*)malloc(erp->rpb.len); memcpy(erp->rpb.data,state[sock_id].curr[pnum]->rp.data,erp->rpb.len); //Actually send packet int nbytes = sizeof(struct rudp_hdr)+erp->rpb.len+16; size_t size = sizeof(struct sockaddr_in); if (sendto(socket_desc,(void*)erp,nbytes,0,(struct sockaddr*)to,size)==-1) return -1; fprintf(stderr,"Sent a DATA packet with seqno %d\r\n",ntohl(erp->rh.seqno)); //Decrease window size by 1 state[sock_id].window_size[pnum] -= 1; //Get the time at which the timeout handler for the packet should be called smalloc(struct timeval,current_time); if (gettimeofday(current_time,NULL)<0) { perror("rudp_event_handler: gettimeofday"); return -1; } current_time->tv_usec += RUDP_TIMEOUT*2000; //Create an argument for the event_timeout function state[sock_id].curr[pnum]->tap = (struct timeout_arg*)malloc(sizeof(struct timeout_arg)); state[sock_id].curr[pnum]->tap->seqno = ntohl(erp->rh.seqno); state[sock_id].curr[pnum]->tap->sock_id = sock_id; state[sock_id].curr[pnum]->tap->socket_desc = socket_desc; state[sock_id].curr[pnum]->timed_out = 0; state[sock_id].curr[pnum]->tap->to = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); memcpy(state[sock_id].curr[pnum]->tap->to,to,sizeof(struct sockaddr_in*)); state[sock_id].curr[pnum]->tap->to->sin_addr = to->sin_addr; //Actually register the timeout handlet event_timeout(*current_time,udp_timeoutf,(void*)(state[sock_id].curr[pnum]->tap),"packet timeout"); } //Send a FIN if no data was left if (packets_to_send<1) send_fin(socket_desc,sock_id,pnum,to); return 0; }