static SELECT_RESPONSE_t recv_callback(void *group, int s, uint8_t *data, size_t length, char *addr, uint16_t port, void *param) { options_t *options = (options_t*)param; /* Cleanup - if the buffer is empty, reset it */ if(buffer_get_remaining_bytes(options->buffer) == 0) buffer_clear(options->buffer); buffer_add_bytes(options->buffer, data, length); /* If we have at least a length value */ if(buffer_get_remaining_bytes(options->buffer) >= 2) { /* Read the length. */ uint16_t expected_length = buffer_peek_next_int16(options->buffer); /* Check if we have the full length. */ if(buffer_get_remaining_bytes(options->buffer) - 2 >= expected_length) { uint8_t *data; size_t returned_length; /* Consume the value we already know */ buffer_read_next_int16(options->buffer); /* Read the rest of the buffer. */ data = buffer_read_remaining_bytes(options->buffer, &returned_length, expected_length, TRUE); /* Sanity check. */ assert(expected_length == returned_length); /* Do the callback. */ session_recv(options->session, data, returned_length); /* Free it. */ safe_free(data); /* Clear the buffer if it's empty. */ if(buffer_get_remaining_bytes(options->buffer) == 0) buffer_clear(options->buffer); } } return SELECT_OK; }
command_packet_t *command_packet_read(buffer_t *stream) { size_t remaining_bytes = buffer_get_remaining_bytes(stream); uint32_t needed_bytes = -1; uint8_t *data; command_packet_t *out = NULL; size_t length; /* If we don't have a length, we're done. */ if(remaining_bytes < 4) return NULL; /* Check for an overflow. */ needed_bytes = buffer_peek_next_int32(stream); if(needed_bytes + 4 < needed_bytes) { LOG_FATAL("Overflow in command_packet!"); exit(1); } /* Make sure there are enough bytes present for the length + data. */ if(remaining_bytes < needed_bytes + 4) return NULL; /* Consume the length. */ buffer_read_next_int32(stream); /* Read the data. */ data = buffer_read_remaining_bytes(stream, &length, needed_bytes, TRUE); /* Sanity check. */ if(length != needed_bytes) { LOG_FATAL("Something went very wrong with the buffer class; the wrong number of bytes were read!"); exit(1); } /* Parse the data and free the buffer. */ out = command_packet_parse(data, length); safe_free(data); return out; }
/* Polls the driver for data and puts it in our own buffer. This is necessary * because the session needs to ACK data and such. */ static void poll_for_data(session_t *session) { size_t length = -1; /* Read all the data we can. */ uint8_t *data = driver_get_outgoing(session->driver, &length, -1); /* If a driver returns NULL, it means it's done - once the driver is * done and all our data is sent, go into 'shutdown' mode. */ if(!data) { if(buffer_get_remaining_bytes(session->outgoing_buffer) == 0) session_kill(session); } else { if(length) buffer_add_bytes(session->outgoing_buffer, data, length); safe_free(data); } }
NBBOOL session_data_incoming(session_t *session, uint8_t *data, size_t length) { /* Parse the packet to get the session id */ packet_t *packet = packet_parse(data, length, session->options); /* Set to TRUE if data was properly ACKed and we should send more right away. */ NBBOOL send_right_away = FALSE; /* Suck in any data we can from the driver. */ poll_for_data(session); /* Print packet data if we're supposed to. */ if(packet_trace) { printf("INCOMING: "); packet_print(packet, session->options); } if(session->is_ping) { /* This only returns if the receive is bad. */ driver_data_received(session->driver, (uint8_t*)packet->body.ping.data, strlen(packet->body.ping.data)); } else { switch(session->state) { case SESSION_STATE_NEW: if(packet->packet_type == PACKET_TYPE_SYN) { LOG_INFO("In SESSION_STATE_NEW, received SYN (ISN = 0x%04x)", packet->body.syn.seq); session->their_seq = packet->body.syn.seq; session->options = (options_t) packet->body.syn.options; session->state = SESSION_STATE_ESTABLISHED; /* Since we established a valid session, we can send stuff right away. */ session->last_transmit = 0; session->missed_transmissions = 0; send_right_away = TRUE; } else if(packet->packet_type == PACKET_TYPE_MSG) { LOG_WARNING("In SESSION_STATE_NEW, received unexpected MSG (ignoring)"); } else if(packet->packet_type == PACKET_TYPE_FIN) { /* TODO: I shouldn't exit here. */ LOG_FATAL("In SESSION_STATE_NEW, received FIN: %s", packet->body.fin.reason); exit(0); } else { /* TODO: I shouldn't exit here. */ LOG_FATAL("Unknown packet type: 0x%02x", packet->packet_type); exit(1); } break; case SESSION_STATE_ESTABLISHED: if(packet->packet_type == PACKET_TYPE_SYN) { LOG_WARNING("In SESSION_STATE_ESTABLISHED, recieved SYN (ignoring)"); } else if(packet->packet_type == PACKET_TYPE_MSG) { LOG_INFO("In SESSION_STATE_ESTABLISHED, received a MSG"); /* Validate the SEQ */ if(packet->body.msg.options.normal.seq == session->their_seq) { /* Verify the ACK is sane */ uint16_t bytes_acked = packet->body.msg.options.normal.ack - session->my_seq; /* If there's still bytes waiting in the buffer.. */ if(bytes_acked <= buffer_get_remaining_bytes(session->outgoing_buffer)) { /* Since we got a valid response back, the connection isn't dying. */ session->missed_transmissions = 0; /* Reset the retransmit counter since we got some valid data. */ if(bytes_acked > 0) { /* Only reset the counter if we want to re-transmit * right away. */ if(transmit_instantly_on_data) { session->last_transmit = 0; session->missed_transmissions = 0; send_right_away = TRUE; } } /* Increment their sequence number */ session->their_seq = (session->their_seq + packet->body.msg.data_length) & 0xFFFF; /* Remove the acknowledged data from the buffer */ buffer_consume(session->outgoing_buffer, bytes_acked); /* Increment my sequence number */ if(bytes_acked != 0) { session->my_seq = (session->my_seq + bytes_acked) & 0xFFFF; } /* Print the data, if we received any, and then immediately receive more. */ if(packet->body.msg.data_length > 0) { driver_data_received(session->driver, packet->body.msg.data, packet->body.msg.data_length); } } else { LOG_WARNING("Bad ACK received (%d bytes acked; %d bytes in the buffer)", bytes_acked, buffer_get_remaining_bytes(session->outgoing_buffer)); } } else { LOG_WARNING("Bad SEQ received (Expected %d, received %d)", session->their_seq, packet->body.msg.options.normal.seq); } } else if(packet->packet_type == PACKET_TYPE_FIN) { LOG_FATAL("In SESSION_STATE_ESTABLISHED, received FIN: %s - closing session", packet->body.fin.reason); session->last_transmit = 0; session->missed_transmissions = 0; session_kill(session); } else { LOG_FATAL("Unknown packet type: 0x%02x - closing session", packet->packet_type); session_kill(session); } break; default: LOG_FATAL("Wound up in an unknown state: 0x%x", session->state); packet_destroy(packet); session_kill(session); exit(1); } } packet_destroy(packet); return send_right_away; }