
#ifndef RUDP_H
#define RUDP_H

#include <apr_network_io.h> 

#define RUDP_VERSION 1
#define RUDP_MAXPKTSIZE 65000
#define RUDP_TIMEOUT 2000
#define RUDP_MAXRETRANS 1
#define RUDP_WINDOW 1
#define RUDP_DATA 1
#define RUDP_ACK 2
#define RUDP_SYN 4


//#define SEQ_LT(a, b) ((short)((a) - (b)) < 0)
//#define SEQ_GEQ(a, b) ((short)((a) - (b)) >= 0)
//#define SEQ_LT(a, b) ((int32_t)((a) - (b)) < 0)
//#define SEQ_GEQ(a, b) ((int32_t)((a) - (b)) >= 0)

typedef struct event_data {
	struct event_data* e_next;
	int (*e_fn)(apr_socket_t*, apr_sockaddr_t*,void *);
	apr_sockaddr_t* sa;
	enum { EVENT_FD, EVENT_TIME } e_type;
	apr_socket_t* e_fd;
	apr_interval_time_t e_time;
	void* e_arg;
} event_data_t;

enum { SYN_SENT, OPENING, OPEN };

typedef enum {
	RUDP_EVENT_TIMEOUT,
	RUDP_EVENT_CLOSED,
} rudp_event_t;

struct timeoutargs {
	apr_socket_t* fd;
	struct rudp_packet* packet;
	apr_sockaddr_t* recipient;

};

struct sockets {
	apr_socket_t* rsock;

	//int (*recv_handler)(apr_socket_t*, apr_sockaddr_t*, char*, int);
//	int (*handler)(apr_socket_t*, rudp_event_t, apr_sockaddr_t*);
	struct session* sessions_list_head;
	struct sockets* next;
};

struct data {
	void* item;
	int len;
	struct data* next;
};

struct sender_session {
	int status;
	uint8_t seqNo;
	struct rudp_packet* sliding_window[RUDP_WINDOW];
	int retransmission_attempts[RUDP_WINDOW];
	struct data* data_queue;
	void* syn_timeout_arg;
	int syn_retransmit_attempts;

	void* data_timeout_arg[RUDP_WINDOW];

};

struct receiver_session {
	int status;
	uint8_t expected_seqNo;

};

typedef struct session {
	struct sender_session* sender;
	struct receiver_session* receiver;
	apr_sockaddr_t address;
	struct session* next;
}session;

typedef struct  {

	

	session* session_writeList;
	session* session_writeListLast;
	apr_thread_mutex_t* session_bufferWriteLock;

}rudpList_session;

extern rudpList_session rudpList;

int eventloop(apr_pool_t* pool);
apr_socket_t* rudp_socket(apr_sockaddr_t* sa, int port, apr_pool_t* pool);
int receiveCallback(apr_socket_t* file, apr_sockaddr_t* sender2,void *arg);
int send_packet(apr_socket_t* rsocket, struct rudp_packet *p, apr_sockaddr_t* recipient);
int sendingAck(apr_socket_t* file, apr_sockaddr_t* sender1, struct rudp_packet *received_packet);



#endif /* RUDP_H */


