<commit_before>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>

#include "rlib.h"

// TODO:
//    - arbitrarily long receive / send buffer
//    - multiple connections

// Buffers are fixed at 10 megabytes for now
#define DEFAULT_BUFFER_SIZE (10 * 1024 *1024)

//this struct will match a chunk of data with its corresponding packet sequence number
typedef struct seqobj {
	struct seqobj *next;
	struct seqobj *prev;
	int seqno;
	char *data;
} seq_obj;

//seq_map should point to a linked list of seq_obj objects so that we can keep track of 
//which data chunks came with which sequence number; 
//should be useful for sending ACKs and retransmissions
seq_obj *seq_map;

typedef struct {
	void *last_byte_acked;
	void *last_byte_sent;
	void *last_byte_written;
} send_buffer_metadata;

typedef struct {
	void *last_byte_read;
	void *next_byte_expected;
	void *last_byte_received;
} receive_buffer_metadata;

// The mapping from rel_t to conn_t is one-to-one; for every connection, there is one
// rel_t and one conn_t instance.
// rel_t also contains a linked list for traversing all connections
struct reliable_state {
	rel_t *next;			/* Linked list for traversing all connections */
	rel_t **prev;

	conn_t *c;			/* This is the connection object */

	/* Add your own data fields below this */

	void *send_buffer;
	size_t send_buffer_size;
	send_buffer_metadata send_buffer_metadata;

	void *receive_buffer;
	size_t receive_buffer_size;
	receive_buffer_metadata receive_buffer_metadata;

	// config
	//   - window size
	//   - timer interval
	//   - timeout interval
	//   - whether single connection or not
	//
	const struct config_common *config;
};
rel_t *rel_list;

/* Creates a new reliable protocol session, returns NULL on failure.
 * Exactly one of c and ss should be NULL.  (ss is NULL when called
 * from rlib.c, while c is NULL when this function is called from
 * rel_demux.) */
// 1) if this is a new connection the conn_t is NULL
// 2) if the connection has already been created,
// then there is no need for the sockaddr_storage, so it will be NULL
// During startup, an initial connection is created for you, leading to 2)
// During runtime, if a new connection is created, then you have to deal with 1)
rel_t *
rel_create (conn_t *c, const struct sockaddr_storage *ss,
		const struct config_common *cc)
{
	rel_t *r;

	r = xmalloc (sizeof (*r));
	memset (r, 0, sizeof (*r));

	if (!c) {
		c = conn_create (r, ss);
		if (!c) {
			free (r);
			return NULL;
		}
	}

	r->c = c;
	r->next = rel_list;
	r->prev = &rel_list;
	if (rel_list)
		rel_list->prev = &r->next;
	rel_list = r;

	/* Do any other initialization you need here */

	r->send_buffer = malloc(DEFAULT_BUFFER_SIZE);
	r->send_buffer_size = DEFAULT_BUFFER_SIZE;
	r->send_buffer_metadata.last_byte_acked = r->send_buffer;
	r->send_buffer_metadata.last_byte_sent = r->send_buffer;
	r->send_buffer_metadata.last_byte_written = r->send_buffer;

	r->receive_buffer = malloc(DEFAULT_BUFFER_SIZE);
	r->receive_buffer_size = DEFAULT_BUFFER_SIZE;
	r->receive_buffer_metadata.last_byte_read = r->receive_buffer;
	r->receive_buffer_metadata.next_byte_expected = r->receive_buffer;
	r->receive_buffer_metadata.last_byte_received = r->receive_buffer;


	r->config = cc;

	return r;
}

void
rel_destroy (rel_t *r)
{
	if (r->next)
		r->next->prev = r->prev;
	*r->prev = r->next;
	conn_destroy (r->c);

	/* Free any other allocated memory here */

	free(r->send_buffer);
	free(r->receive_buffer);
}


/* This function only gets called when the process is running as a
 * server and must handle connections from multiple clients.  You have
 * to look up the rel_t structure based on the address in the
 * sockaddr_storage passed in.  If this is a new connection (sequence
 * number 1), you will need to allocate a new conn_t using rel_create
 * ().  (Pass rel_create NULL for the conn_t, so it will know to
 * allocate a new connection.)
 */
// Note: This is only called in server mode, i.e. when you supply the -s option when running
// This will add a new node to the linked list if this is a new connection
// if not, ???
void
rel_demux (const struct config_common *cc,
		const struct sockaddr_storage *ss,
		packet_t *pkt, size_t len)
{
}

// For receiving packets; these are either ACKs (for sending) or data packets (for receiving)
// For receiving: read in and buffer the packets so they can be consumed by by rel_output
// For sending: update how many unACKed packets there are
void
rel_recvpkt (rel_t *r, packet_t *pkt, size_t n)
{
}

// read in data using conn_input, break this data into packets, send the packets,
// and update how many unacked packets there are
void
rel_read (rel_t *s)
{
}

void send_ack(rel_t *r) {
	packet_t *ack = malloc(sizeof(packet_t));
	memset(ack, 0, sizeof(packet_t));
	ack->len = (uint16_t) sizeof(packet_t);
//	ack->ackno = (uint32_t) *r->receive_buffer_metadata.next_byte_expected; doesn't work ;___;
	ack->cksum = cksum((void *)ack, sizeof(packet_t));
	conn_sendpkt(r->c, ack, sizeof(packet_t));
	free(ack);
	return; <commit_msg>started rel_read<commit_after>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>

#include "rlib.h"

/*
 Nagles Algo: 
 
 When the application produces data to send
   if both the available data and the window ≥ MSS
     send a full segment 
   else
     if there is unACKed data in flight
       buffer the new data until an ACK arrives
     else
       send all the new data now
 
 */

// TODO:
//    - arbitrarily long receive / send buffer
//    - multiple connections

// Buffers are fixed at 10 megabytes for now
#define DEFAULT_BUFFER_SIZE (10 * 1024 *1024)
#define MAX_PACKET_DATA_SIZE 500

//this struct will match a chunk of data with its corresponding packet sequence number
typedef struct seqobj {
	struct seqobj *next;
	struct seqobj *prev;
	int seqno;
	char *data;
} seq_obj;

//seq_map should point to a linked list of seq_obj objects so that we can keep track of 
//which data chunks came with which sequence number; 
//should be useful for sending ACKs and retransmissions
seq_obj *seq_map;

typedef struct {
	void *last_byte_acked;
	void *last_byte_sent;
	void *last_byte_written;
} send_buffer_metadata;

typedef struct {
	void *last_byte_read;
	void *next_byte_expected;
	void *last_byte_received;
} receive_buffer_metadata;

// The mapping from rel_t to conn_t is one-to-one; for every connection, there is one
// rel_t and one conn_t instance.
// rel_t also contains a linked list for traversing all connections
struct reliable_state {
	rel_t *next;			/* Linked list for traversing all connections */
	rel_t **prev;

	conn_t *c;			/* This is the connection object */

	/* Add your own data fields below this */

	void *send_buffer;
	size_t send_buffer_size;
	send_buffer_metadata send_buffer_metadata;

	void *receive_buffer;
	size_t receive_buffer_size;
	receive_buffer_metadata receive_buffer_metadata;

	// config
	//   - window size
	//   - timer interval
	//   - timeout interval
	//   - whether single connection or not
	//
	const struct config_common *config;
};
rel_t *rel_list;

/* Creates a new reliable protocol session, returns NULL on failure.
 * Exactly one of c and ss should be NULL.  (ss is NULL when called
 * from rlib.c, while c is NULL when this function is called from
 * rel_demux.) */
// 1) if this is a new connection the conn_t is NULL
// 2) if the connection has already been created,
// then there is no need for the sockaddr_storage, so it will be NULL
// During startup, an initial connection is created for you, leading to 2)
// During runtime, if a new connection is created, then you have to deal with 1)
rel_t *
rel_create (conn_t *c, const struct sockaddr_storage *ss,
		const struct config_common *cc)
{
	rel_t *r;

	r = xmalloc (sizeof (*r));
	memset (r, 0, sizeof (*r));

	if (!c) {
		c = conn_create (r, ss);
		if (!c) {
			free (r);
			return NULL;
		}
	}

	r->c = c;
	r->next = rel_list;
	r->prev = &rel_list;
	if (rel_list)
		rel_list->prev = &r->next;
	rel_list = r;

	/* Do any other initialization you need here */

	r->send_buffer = malloc(DEFAULT_BUFFER_SIZE);
	r->send_buffer_size = DEFAULT_BUFFER_SIZE;
	r->send_buffer_metadata.last_byte_acked = r->send_buffer;
	r->send_buffer_metadata.last_byte_sent = r->send_buffer;
	r->send_buffer_metadata.last_byte_written = r->send_buffer;

	r->receive_buffer = malloc(DEFAULT_BUFFER_SIZE);
	r->receive_buffer_size = DEFAULT_BUFFER_SIZE;
	r->receive_buffer_metadata.last_byte_read = r->receive_buffer;
	r->receive_buffer_metadata.next_byte_expected = r->receive_buffer;
	r->receive_buffer_metadata.last_byte_received = r->receive_buffer;


	r->config = cc;

	return r;
}

void
rel_destroy (rel_t *r)
{
	if (r->next)
		r->next->prev = r->prev;
	*r->prev = r->next;
	conn_destroy (r->c);

	/* Free any other allocated memory here */

	free(r->send_buffer);
	free(r->receive_buffer);
}


/* This function only gets called when the process is running as a
 * server and must handle connections from multiple clients.  You have
 * to look up the rel_t structure based on the address in the
 * sockaddr_storage passed in.  If this is a new connection (sequence
 * number 1), you will need to allocate a new conn_t using rel_create
 * ().  (Pass rel_create NULL for the conn_t, so it will know to
 * allocate a new connection.)
 */
// Note: This is only called in server mode, i.e. when you supply the -s option when running
// This will add a new node to the linked list if this is a new connection
// if not, ???
void
rel_demux (const struct config_common *cc,
		const struct sockaddr_storage *ss,
		packet_t *pkt, size_t len)
{
}

// For receiving packets; these are either ACKs (for sending) or data packets (for receiving)
// For receiving: read in and buffer the packets so they can be consumed by by rel_output
// For sending: update how many unACKed packets there are
void
rel_recvpkt (rel_t *r, packet_t *pkt, size_t n)
{
}

// read in data using conn_input, break this data into packets, send the packets,
// and update how many unacked packets there are
/*
To get the data that you must transmit to the receiver, keep calling conn_input until it drains. conn_input reads data from standard input. If no data is available at the moment, conn_input will return 0. Do not loop calling conn_input if it returns 0, simply return. At the point data become available again, the library will call rel_read for ONCE, so you can read from conn_input again. When an EOF is received, conn_input will return -1. Also, do NOT try to buffer the data from conn_input more than expected. The sender's window is the only buffer you got. When the window is full, break from the loop even if there could still be available data from conn_input. When later some ack packets are received and some slots in sender's window become vacant again, call rel_read.
 
 
 struct packet {
	uint16_t cksum;
	uint16_t len;
	uint32_t ackno;
	uint32_t seqno;		 Only valid if length > 8
    char data[500];
    };
 typedef struct packet packet_t;
 */

void
rel_read (rel_t *s)
{


    int bytes_recv = 1;
    while (bytes_recv > 0) {
        packet_t new_packet;
        bytes_recv = conn_input(s->c, new_packet.data, MAX_PACKET_DATA_SIZE);

        
        new_packet.cksum = 0;
        new_packet.len = bytes_recv+12;
        //new_packet.ackno = ?
        //new_packet.seqno = ?
        
        //if LastByteWritten - LastByteAcked <= MaxSendBuffer and
        //   LastByteSent - LastByteAcked <= Advertised Window
        conn_sendpkt(s->c, &new_packet, sizeof(new_packet));
        //
        
        //else break;

        
        s->send_buffer_metadata.last_byte_sent++;
        s->send_buffer_metadata.last_byte_written++;
        //s->send_buffer_metadata.last_byte_acked;
        
        
    }
   //conn_input
    //conn_send_pckt
    
}

void send_ack(rel_t *r) {
	packet_t *ack = malloc(sizeof(packet_t));
	memset(ack, 0, sizeof(packet_t));
	ack->len = (uint16_t) sizeof(packet_t);
//	ack->ackno = (uint32_t) *r->receive_buffer_metadata.next_byte_expected; doesn't work ;___;
	ack->cksum = cksum((void *)ack, sizeof(packet_t));
	conn_sendpkt(r->c, ack, sizeof(packet_t));
	free(ack);
	return; 
{'fraction_non_alphanumeric': 0.09685384309040224, 'fraction_numerical': 0.005495818399044205, 'mean_word_length': 3.704383664293743, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 108, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1953621', 'n_tokens_mistral': 4279, 'n_tokens_neox': 4095, 'n_words': 1499}