#ifndef __NET_UTILS_H__
#define __NET_UTILS_H__

#include <stdint.h>

#include <pthread.h>
#include <signal.h>
#include <time.h>
#include <arpa/inet.h>
#include <sys/time.h>

#define max(x, y) ({ \
	__typeof__(x) _x = (x); \
	__typeof__(x) _y = (y); \
	(_x > _y) ? _x : _y; \
})

#define RELAY_BUFSZ     128

/* Relay connection status */
#define S_CREATED       1
#define S_UNPAIRED      2
#define S_WAITING       3
#define S_RUNNING       4
#define S_TERMINATED    5

struct conn_context {
	sig_atomic_t status;
	int sockets[2];

	socklen_t len[2];
	struct sockaddr_in addr[2];

	pthread_t tid;
	uint64_t timestamp;
};

int test_connection(int sockfd);
void *resolve_host(const char *hostname, struct sockaddr_in *addr);
int tcp_server_socket(uint16_t port, int backlog);
int tcp_client_socket(const char *hostname, uint16_t port);
void *tcp_relay(void *arg);

void mark_all_connections(struct node *head, int new_status);
struct conn_context *find_unpaired_node(struct node *head);
void run_connection_scheduler(struct node **head_ref);

static inline struct conn_context empty_conn_context(void)
{
	struct conn_context _cc = {
		.status = S_CREATED,
		.len[0] = sizeof *_cc.addr,
		.len[1] = sizeof *_cc.addr,
	};

	return _cc;
}

static inline uint64_t get_timestamp_ms(void)
{
	uint64_t timestamp;

#if _POSIX_C_SOURCE >= 199309L
	struct timespec ts;
	clock_gettime(CLOCK_REALTIME, &ts);
	timestamp = (ts.tv_sec * UINT64_C(1000) + ts.tv_nsec / 1000000);
#else
	struct timeval tv;
	gettimeofday(&tv, NULL);
	timestamp = (tv.tv_sec * UINT64_C(1000) + tv.tv_usec / 1000);
#endif

	return timestamp;
}

#endif /* __NET_UTILS_H__ */
