Пример #1
0
/* 
 * Send a message to the other end of the socket.
 *
 * The send call should block until the remote host has ACKnowledged receipt of
 * the message.  This does not necessarily imply that the application has called
 * 'minisocket_receive', only that the packet is buffered pending a future
 * receive.
 *
 * It is expected that the order of calls to 'minisocket_send' implies the order
 * in which the concatenated messages will be received.
 *
 * 'minisocket_send' should block until the whole message is reliably
 * transmitted or an error/timeout occurs
 *
 * Arguments: the socket on which the communication is made (socket), the
 *            message to be transmitted (msg) and its length (len).
 * Return value: returns the number of successfully transmitted bytes. Sets the
 *               error code and returns -1 if an error is encountered.
 */
int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error)
{
	int portNumber;
	int sentLength;
	int sentData = 0;
	int maxDataSize;
	int check;
	//interrupt_level_t prev_level;

	if (error == NULL)
		return -1;

	if (socket == NULL || msg == NULL || len <= 0)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	portNumber = socket->port_number;

	if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_TO_CLOSE
			|| minisockets[portNumber] == NULL)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	/*prev_level = set_interrupt_level(DISABLED);
	socket->num_waiting_on_mutex++;

	semaphore_P(socket->mutex);

	socket->num_waiting_on_mutex--;
	set_interrupt_level(prev_level);
*/
	if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_TO_CLOSE
			|| minisockets[portNumber] == NULL)
	{
		*error = SOCKET_SENDERROR;
//		semaphore_V(socket->mutex);
		return -1;
	}

	maxDataSize = MAX_NETWORK_PKT_SIZE - sizeof(struct mini_header_reliable);
	while (len > 0)
	{
		sentLength = (maxDataSize > len ? len : maxDataSize);
		check = transmit_packet(socket, socket->destination_addr, socket->destination_port, 1,
				MSG_ACK, sentLength, (msg+sentData), error);

		if (check == -1)
		{
//			semaphore_V(socket->mutex);
			minisocket_destroy(socket, 0);
			return (sentData == 0 ? -1 : sentData);
		}
		len -= maxDataSize;
		sentData += sentLength;
	}

//	semaphore_V(socket->mutex);
	*error = SOCKET_NOERROR;

	return sentData;
}
Пример #2
0
/* Close a connection. If minisocket_close is issued, any send or receive should
 * fail.  As soon as the other side knows about the close, it should fail any
 * send or receive in progress. The minisocket is destroyed by minisocket_close
 * function.  The function should never fail.
 */
void minisocket_close(minisocket_t socket)
{
  interrupt_level_t l;
  minisocket_error error;
  resend_arg_t resend_alarm_arg;

  resend_alarm_arg = (resend_arg_t)calloc(1,sizeof(struct resend_arg));
  if (!resend_alarm_arg){
    return;
  }
  error = SOCKET_NOERROR;

  //printf("in minisocket_close\n");
  
  //set state to close_wait
  //send close, wait using alarms
  //(after 7 retries, close connection)
  //P on ack_ready
  //if ack_ready, close connection
 
  //ill formed argument 
  if (!sock_array){
    free(resend_alarm_arg);
    return;
  }

  l = set_interrupt_level(DISABLED);
  //ill formed argument
  if (sock_array[socket->src_port] == NULL){
    set_interrupt_level(l);
    free(resend_alarm_arg);
    return;
  }
  if (socket->curr_state == CLOSE_SEND || socket->curr_state == CLOSE_RCV){
    set_interrupt_level(l);
    free(resend_alarm_arg);
    return;
  }
  socket->curr_state = CLOSE_SEND;
  socket->try_count = 0;
  socket->curr_seq++;

  minisocket_send_ctrl( MSG_FIN, socket, &error);
  //printf("in minisocket_close, sent my MSG_FIN\n");
  resend_alarm_arg->sock = socket;
  resend_alarm_arg->msg_type = MSG_FIN;
  resend_alarm_arg->data_len = 0;
  resend_alarm_arg->data = (char*) &socket; //placeholder
  resend_alarm_arg->error = &error;
  if (socket->resend_alarm){
    deregister_alarm(socket->resend_alarm);
  }
  socket->resend_alarm = NULL;
  socket->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
  //printf("in minisocket_close, set my alarm.\n");
  set_interrupt_level(l);

  semaphore_P(socket->ack_ready_sem); //wait for ack packet...
  //received ack, close connection
  //printf("in minisocket_close, got my ACK baby\n");
  l = set_interrupt_level(DISABLED);
  if (socket->resend_alarm){
    deregister_alarm(socket->resend_alarm);
  }
  socket->resend_alarm = NULL;

  minisocket_destroy(socket, &error);
  //printf("Closed. Error is %d", error);
  if (error != SOCKET_NOERROR){
    //printf("Something went wrong. Close connection failure.\n");
  }
  set_interrupt_level(l);

  //printf("in minisocket_close, SUCCESS\n");
  free(resend_alarm_arg);
  return;

}
Пример #3
0
void delete_socket(void* arg)
{
	minisocket_t socket = (minisocket_t) arg;
	minisocket_destroy(socket, 0);
}
Пример #4
0
void self_destruct(void* arg) {
  minisocket_error error;
  minisocket_destroy((minisocket_t)arg, &error);
  //printf("Goodby cruel world\n");
  return;
}
Пример #5
0
/* Initiate the communication with a remote site. When communication is
 * established create a minisocket through which the communication can be made
 * from now on.
 *
 * The first argument is the network address of the remote machine. 
 *
 * The argument "port" is the port number on the remote machine to which the
 * connection is made. The port number of the local machine is one of the free
 * port numbers.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_client_create(network_address_t addr, int port, minisocket_error *error)
{
  minisocket_t new_sock;
  interrupt_level_t l;
  resend_arg* resend_alarm_arg;
  unsigned short start; 
  char tmp;

  //check valid portnum
  if (port < 0 || port >= CLIENT_START) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }

  semaphore_P(client_lock);
  start = curr_client_idx;
  while (sock_array[curr_client_idx] != NULL){
    curr_client_idx++;
    if (curr_client_idx >= NUM_SOCKETS){
      curr_client_idx = CLIENT_START;
    }
    if (curr_client_idx == start){ // client sockets full
      semaphore_V(client_lock);
      *error = SOCKET_NOMOREPORTS; 
      return NULL;
    }
  }
 
  new_sock = (minisocket_t)malloc(sizeof(struct minisocket));
  if (!new_sock){
    semaphore_V(client_lock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_ready_sem = semaphore_create();
  if (!(new_sock->pkt_ready_sem)){
    semaphore_V(client_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_q = queue_new();
  if (!(new_sock->pkt_q)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->sock_lock = semaphore_create();
  if (!(new_sock->sock_lock)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->ack_ready_sem = semaphore_create();
  if (!(new_sock->ack_ready_sem)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    semaphore_destroy(new_sock->sock_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  
  semaphore_initialize(new_sock->pkt_ready_sem, 0);
  semaphore_initialize(new_sock->ack_ready_sem, 0);
  semaphore_initialize(new_sock->sock_lock, 1);

  new_sock->curr_state = CONNECT_WAIT;
  new_sock->try_count = 0;
  new_sock->curr_ack = 0;
  new_sock->curr_seq = 1;
  new_sock->resend_alarm = NULL; //no alarm set
  new_sock->src_port = curr_client_idx;
  new_sock->dst_port = port; 
  network_address_copy(addr, new_sock->dst_addr);

  sock_array[curr_client_idx] = new_sock;
  semaphore_V(client_lock);
 
  l = set_interrupt_level(DISABLED);
  minisocket_send_ctrl(MSG_SYN, new_sock, error);
  resend_alarm_arg = (resend_arg*)calloc(1, sizeof(resend_arg));
  resend_alarm_arg->sock = new_sock;
  resend_alarm_arg->msg_type = MSG_SYN;
  resend_alarm_arg->data_len = 0;
  resend_alarm_arg->data = &tmp; //placeholder
  resend_alarm_arg->error = error; 
  new_sock->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
  set_interrupt_level(l);

  semaphore_P(new_sock->ack_ready_sem);
  l = set_interrupt_level(DISABLED);

  switch(new_sock->curr_state) {
  case CONNECTED: //we are connected
    // must have gotten a MSG_SYNACK
    new_sock->curr_state = CONNECTED;
    new_sock->try_count = 0;
    if (new_sock->resend_alarm){
      deregister_alarm(new_sock->resend_alarm);
    }
    new_sock->resend_alarm = NULL;
    *error = SOCKET_NOERROR;
    set_interrupt_level(l); 
    break;
  
  case CLOSE_RCV:
    *error = SOCKET_BUSY;
    minisocket_destroy(new_sock, error);
    if (new_sock->resend_alarm){
      deregister_alarm(new_sock->resend_alarm);
    }
    new_sock->resend_alarm = NULL;
    *error = SOCKET_BUSY;
    set_interrupt_level(l);
    new_sock = NULL;
    break; 
  
  default:
    // error
    *error = SOCKET_NOSERVER;
    minisocket_destroy(new_sock, error);
    set_interrupt_level(l); 
    new_sock = NULL;
    break;
  }
  free(resend_alarm_arg);
  return new_sock;
}
Пример #6
0
void minisocket_close(minisocket_t *socket) {
  if (socket == NULL || mini_socket_data[socket->local_port_number] == NULL || socket->state == CLOSED) {
    return; // no cleanup necessary 
  }

  fprintf(stderr, "Closing time \n");
  mini_header_reliable_t header;
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, socket->remote_address, MSG_FIN); 
  int send_success = 0;
  int timeout = START_TIMEOUT / 2; 
  
  for (int i = 0; i < MAX_FAILURES; i++) {
    if (socket->state == CLOSED) {
      return; //received a MSG_FIN message in network_handler, so stop re-tries
    } 
    timeout = timeout * 2;
    network_send_pkt(socket->remote_address, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message); 
    alarm_id timeout_alarm_id = register_alarm(timeout, handshake_timeout_handler, (void *) socket->ack_ready);
    int alarm_fired = 0;
    
    //keep looking through received packets until either the alarm fires or it finds the correct packet
    while (!send_success && !alarm_fired) {
      semaphore_P(socket->ack_ready);

      //alarm has fired, since there are no packets to be received
      if (queue_length(socket->acknowledgements) == 0) {
        printf("CLOSE queue length: %d\n", queue_length(socket->acknowledgements)); 
        alarm_fired = 1; //goes to next iteration of for loop
      }
      //There is a packet (alarm hasnt fired yet)
      else {
        network_interrupt_arg_t* interrupt_message = NULL;
        interrupt_level_t old_level = set_interrupt_level(DISABLED);
        queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
        set_interrupt_level(old_level); 

        // verify non null message
        if (interrupt_message != NULL) {
          mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
         
          //already checked port and address in network_handler 
          if (received_header->message_type == MSG_ACK) { 
            deregister_alarm(timeout_alarm_id); //only deregister alarm when the right packet is found
            send_success = 1; 
            free(interrupt_message); 
            break;
          }
          else {
            free(interrupt_message);
          }
        }
      }
    }
    if (send_success) {
      break;
    }
  }
  printf("out of CLOSE\n");
  //sender considers the connection closed, even if MSG_ACK not received
  if (socket->state != CLOSED) {
    printf("calling DESTROY from CLOSE\n"); 
    minisocket_destroy(socket);
  }
}
Пример #7
0
int minisocket_send(minisocket_t *socket, const char *msg, int len, minisocket_error *error) {
  //Check params
  if (socket == NULL || mini_socket_data[socket->local_port_number] != socket || len < 0 || msg == NULL) {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  if (socket->state == CLOSED) {
    *error = SOCKET_SENDERROR;
    return -1;
  }
  if (len == 0) {
    return 0;
  }
  //can't send more bytes than we have
  if (len > strlen(msg)) {
    len = strlen(msg);
  }

  int bytes_sent = 0;
  int max_data_size = MAX_NETWORK_PKT_SIZE - sizeof(mini_header_reliable_t);
  int data_left = len;
  int packet_size;
 
  mini_header_reliable_t header; 
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, socket->remote_address, MSG_ACK);

  //Keep sending until all is sent
  while (data_left != 0) {
    if (data_left >= max_data_size) {
      packet_size = max_data_size;
    }
    else {
      packet_size = data_left;
    }
    data_left -= packet_size;
    pack_unsigned_int(header.seq_number, socket->seq);
    int send_success = 0;

    //Attempt to send message
    int timeout = START_TIMEOUT/2; 
    for (int i = 0; i < MAX_FAILURES; i++) {
      //printf("i: %d\n", i); 
      timeout = timeout * 2;
      //update the seq and ack numbers for the header from the socket  
      //printf("seq: %u, ack: %u\n", socket->seq, socket->ack);
      
      pack_unsigned_int(header.ack_number, socket->ack);
      pack_unsigned_int(header.seq_number, socket->seq);

      network_send_pkt(socket->remote_address, sizeof(mini_header_reliable_t), (char *) &header, packet_size, (char *) msg); 
      alarm_id timeout_alarm_id = register_alarm(timeout, handshake_timeout_handler, (void *) socket->ack_ready);
      int alarm_fired = 0;

      //keep looking through received packets until either the alarm fires or it finds the correct packet
      while (!send_success && !alarm_fired) {
        semaphore_P(socket->ack_ready);

        if (queue_length(socket->acknowledgements) == 0) {
       //   printf("no message in queue\n");
          alarm_fired = 1; //goes to next iteration of for loop
        }
        else {
        //  printf("length of queue currently %d\n", queue_length(socket->acknowledgements));
          network_interrupt_arg_t* interrupt_message = NULL;
          interrupt_level_t old_level = set_interrupt_level(DISABLED);
          queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
          set_interrupt_level(old_level); 

          if (interrupt_message != NULL) {
            mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
            network_address_t temp_address;
            unpack_address(received_header->source_address, temp_address);
            unsigned int new_ack = unpack_unsigned_int(received_header->ack_number);
            //printf("Received an acknowledgment with ack number %u \n", new_ack);
          
            if (socket->remote_port_number == unpack_unsigned_short(received_header->source_port) &&
              network_compare_network_addresses(socket->remote_address, temp_address) != 0 &&
                received_header->message_type == MSG_ACK && new_ack == (socket->seq + packet_size)) {
                  //same address, same ports, right message, right ack
                  deregister_alarm(timeout_alarm_id); //only deregister alarm when the right packet is found
                  send_success = 1; 
                  bytes_sent += packet_size;
                  msg += packet_size;
                  socket->seq += packet_size;
                  free(interrupt_message); 
                  break;
            }
            else {
              free(interrupt_message);
            }
          }
        }
      }
      if (send_success) {
        break;
      }
      
    }
    if (!send_success) { //Got a timeout, should close down socket
      *error = SOCKET_SENDERROR;
      minisocket_destroy(socket);
      return bytes_sent;
    }
  }
  //printf("\n\n");
  return bytes_sent;
}
Пример #8
0
minisocket_t* minisocket_client_create(const network_address_t addr, int port, minisocket_error *error) {
    //Check socket number first 
  if (valid_server_port(port) == 0) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }       
  //Then check if we can make another client
  if (client_count >= MAX_CLIENTS) {
    *error = SOCKET_NOMOREPORTS;
    return NULL;
  }
  //create new minisocket
  minisocket_t* socket = (minisocket_t *) malloc(sizeof(minisocket_t));
  if (socket == NULL) {
    *error = SOCKET_OUTOFMEMORY;
    return NULL; //OOM
  }
  
  while (mini_socket_data[next_port]) {
    next_port = ((next_port + 1) % PORT_RANGE);
  }
 
  socket->socket_type = CLIENT_TYPE;
  socket->local_port_number = next_port;
  next_port = ((next_port + 1) % PORT_RANGE);
  socket->state = CONNECTING;
  socket->seq = 0;
  socket->ack = 0;
  network_address_copy(addr, socket->remote_address);
  socket->remote_port_number = (unsigned short) port;
  network_address_copy(addr, socket->remote_address);
  socket->next_read = 0;

  network_address_t my_address;
  network_get_my_address(my_address);
  network_address_copy(my_address, socket->local_address);

  socket->datagrams_ready = semaphore_create();
  semaphore_initialize(socket->datagrams_ready, 0);
  socket->ack_ready = semaphore_create();
  semaphore_initialize(socket->ack_ready, 0);
  socket->incoming_data = queue_new();
  socket->acknowledgements = queue_new();

  //add socket to global array
  mini_socket_data[socket->local_port_number] = socket; 
  

  mini_header_reliable_t header; 
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, addr, MSG_SYN);

  //minisocket and header now created, try to establish connection
  pack_unsigned_int(header.seq_number, socket->seq);
  pack_unsigned_int(header.ack_number, socket->ack); 

  //send first message and wait for response
  int response = 0; //no response yet
  int timeout = START_TIMEOUT / 2; //this way first timeout will be at START_TIMEOUT
  for (int i = 0; i < MAX_FAILURES; i++) {
    printf("sending MSG_SYN in client, i: %d\n", i);
    timeout = timeout * 2;
    network_send_pkt(addr, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message); 
    alarm_id timeout_alarm_id = register_alarm(timeout, handshake_timeout_handler, (void *) socket->ack_ready);
    int alarm_fired = 0;

    while (!response && !alarm_fired) {
      semaphore_P(socket->ack_ready);
      
      //If queue length == 0, then the alarm must have fired
      if (queue_length(socket->acknowledgements) == 0) {
        alarm_fired = 1; //goes to next iteration of for loop
      }
      //otherwise, we received a packet
      else {
        network_interrupt_arg_t *interrupt_message;
        interrupt_level_t old_level = set_interrupt_level(DISABLED);
        queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
        set_interrupt_level(old_level); 

        // if message not null
        if (interrupt_message != NULL) { 
          mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
          network_address_t temp_address;
          unpack_address(received_header->source_address, temp_address);

          if (socket->remote_port_number == unpack_unsigned_short(received_header->source_port) &&
            network_compare_network_addresses(socket->remote_address, temp_address) != 0) {
            //if SYNACK
             printf("CLIENT\n");

            if (received_header->message_type == MSG_SYNACK) {
              printf("GOT message SYN_ACK\n"); 
              deregister_alarm(timeout_alarm_id);
              response = 1;
              break;
            }
            //if MSG_FIN
            else if (received_header->message_type == MSG_FIN) {
              printf("got message MSG_FIN in client\n");
              //server already in use
              deregister_alarm(timeout_alarm_id);
              *error = SOCKET_BUSY;
              response = 1;
              minisocket_destroy(socket);
              return NULL; 
            }
            //WRONG MESSAGE TYPE
            else {
              printf("wrong message type received in client\n");
              //TODO : try another message type, maybe do nothing?
            }
          }
        }
      }
    }
    if (response) {
      break;
    }
  }
  // timeout after 12.8s occured, close down socket
  if (response != 1) {
    printf("full timeout in client sending SYN\n"); 
    *error = SOCKET_NOSERVER;
    minisocket_destroy(socket);
    return NULL;
  }

  // send final MSG_ACK once to server (future data packets will also have MSG_ACK as header type)
  header.message_type = MSG_ACK; 
  printf("sending final MSG_ACK and leaving client create\n"); 
  network_send_pkt(addr, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message);   
  socket->state = CONNECTED;
  client_count++;
  return socket;
}
Пример #9
0
/* Close a connection. If minisocket_close is issued, any send or receive should
 * fail.  As soon as the other side knows about the close, it should fail any
 * send or receive in progress. The minisocket is destroyed by minisocket_close
 * function.  The function should never fail.
 */
void minisocket_close(minisocket_t socket)
{
	minisocket_destroy(socket, 1);
}
Пример #10
0
/* 
 * Send a message to the other end of the socket.
 *
 * The send call should block until the remote host has ACKnowledged receipt of
 * the message.  This does not necessarily imply that the application has called
 * 'minisocket_receive', only that the packet is buffered pending a future
 * receive.
 *
 * It is expected that the order of calls to 'minisocket_send' implies the order
 * in which the concatenated messages will be received.
 *
 * 'minisocket_send' should block until the whole message is reliably
 * transmitted or an error/timeout occurs
 *
 * Arguments: the socket on which the communication is made (socket), the
 *            message to be transmitted (msg) and its length (len).
 * Return value: returns the number of successfully transmitted bytes. Sets the
 *               error code and returns -1 if an error is encountered.
 */
int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error)
{
	int ret;
	int max_data_size;
	int data_sent = 0;
	int len_sent;
	int port_number;

	if (socket == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (msg == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (len <= 0)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (error == NULL)
	{
		return -1;
	}

	port_number = socket->port_number;

	// First, check if the socket is closing
	if (socket->status == TCP_PORT_CLOSING 
		|| socket->waiting == TCP_PORT_WAITING_CLOSE
		|| minisockets[port_number] == NULL)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	socket->num_waiting_on_mutex++;
	semaphore_P(socket->mutex);
	socket->num_waiting_on_mutex--;

	// Check again - maybe we were awoken because it's now closing
	if (socket->status == TCP_PORT_CLOSING 
		|| socket->waiting == TCP_PORT_WAITING_CLOSE
		|| minisockets[port_number] == NULL)
	{
		*error = SOCKET_SENDERROR;
		semaphore_V(socket->mutex);
		return -1;
	}

	// Determine the max data size
	max_data_size = MAX_NETWORK_PKT_SIZE - sizeof(struct mini_header_reliable);

	if (len > max_data_size)
	{
		// Partition the large message into smaller packets
		while (len > 0)
		{
			// See how much we can fit into the next packet
			len_sent = (max_data_size > len ? len : max_data_size);
	
			// Send the packet
			ret = transmit_packet(socket, socket->dst_addr, socket->dst_port, 1, 
									MSG_ACK, len_sent, msg+data_sent, error);

			// Check for errors
			if (ret == -1)
			{
				// If we can't reach the host, close the connection
				semaphore_V(socket->mutex);
				minisocket_destroy(socket, 0);
				return (data_sent == 0 ? -1 : data_sent);
			}

			// Update the amount of data left to send
			len -= max_data_size; // can also be - len_sent, doesn't matter

			// Update the number of bytes we've sent - also used w/ msg as a ptr
			data_sent += len_sent;
		}
	}
	 else
	{
		// This can be transmitted as a single packet
		ret = transmit_packet(socket, socket->dst_addr, 
						socket->dst_port, 1, 
						MSG_ACK, len, msg, error);

		if (ret == -1)
		{
			// If we can't reach the host, close the connection
			semaphore_V(socket->mutex);
			minisocket_destroy(socket, 0);
			return -1;
		}

		data_sent = len;
	}

	semaphore_V(socket->mutex);
	*error = SOCKET_NOERROR;
	return data_sent;
}