Index: Daodan/Flatline/src/Flatline.c
===================================================================
--- Daodan/Flatline/src/Flatline.c	(revision 459)
+++ Daodan/Flatline/src/Flatline.c	(revision 460)
@@ -1,92 +1,5 @@
 #include "Flatline.h"
 
-bool Net_Listen(uint16_t port, bool (*packet_callback)(char* data, int datalen, int from))
-{
-	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	
-	if (sock < 0)
-	{
-		DDrStartupMessage("could not create socket");
-		return false;
-	}
-	
-	sockaddr_in address;
-	memset(&address, 0, sizeof(sockaddr_in));
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = htonl(INADDR_ANY);
-	address.sin_port = htons(port);
-	
-	if (bind(sock, (sockaddr*)&address, sizeof(sockaddr_in)) < 0)
-	{
-		DDrStartupMessage("could not bind port %d", port);
-		closesocket(sock);
-		return false;
-	}
-	
-	char data[65537];
-	data[sizeof(data) - 1] = '\0';
-	sockaddr_in from;
-	int recvlen;
-	for (;;)
-	{
-		int fromlen = sizeof(sockaddr_in);
-		memset(&from, 0, sizeof(sockaddr_in));
-		recvlen = recvfrom(sock, data, sizeof(data) - 1, 0, (sockaddr*)&from, (void*)&fromlen);
-		if (!packet_callback(data, recvlen, ntohl(from.sin_addr.s_addr)))
-			break;
-	}
-	closesocket(sock);
-	return true;
-}
-
-int Net_CreateSocket(uint16_t port)
-{
-	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	
-	if (sock < 0)
-	{
-		DDrStartupMessage("could not create socket");
-		return -1;
-	}
-	
-	sockaddr_in address;
-	memset(&address, 0, sizeof(sockaddr_in));
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = htonl(INADDR_ANY);
-	address.sin_port = htons(port);
-	
-	if (bind(sock, (sockaddr*)&address, sizeof(sockaddr_in)) < 0)
-	{
-		DDrStartupMessage("could not bind port %d", port);
-		return false;
-	}
-	
-	unsigned long nonBlocking = 1;
-	if (ioctlsocket(sock, FIONBIO, &nonBlocking))
-	{
-		DDrStartupMessage("failed to set non-blocking socket");
-		return false;
-	}
-	
-	return sock;
-}
-
-bool Net_Send(int socket, int ip, uint16_t port, char* data, int datalen)
-{
-	sockaddr_in address;
-	memset(&address, 0, sizeof(sockaddr_in));
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = ip;
-	address.sin_port = htons(port);
-	
-	return sendto(socket, data, datalen, 0, (sockaddr*)&address, sizeof(address));
-}
-
-void Net_CloseSocket(int sock)
-{
-	closesocket(sock);
-}
-
-bool FLrListen_PacketCallback(char* data, int datalen, int from)
+bool FLrServer_PacketCallback(char* data, int datalen, int from)
 {
 	static int recieved = 0;
@@ -98,5 +11,5 @@
 }
 
-bool FLrListen_Run()
+bool FLrServer_Run()
 {
 	return Net_Listen(27777, FLrListen_PacketCallback);
Index: Daodan/Flatline/src/Flatline.h
===================================================================
--- Daodan/Flatline/src/Flatline.h	(revision 459)
+++ Daodan/Flatline/src/Flatline.h	(revision 460)
@@ -8,4 +8,6 @@
 #include <stdbool.h>
 #include <stdint.h>
+
+#define thread __thread
 
 #ifdef WIN32
@@ -27,8 +29,19 @@
 #endif
 
+#define pad1_size (sizeof(int64_t) - sizeof(short))
+#define pad2_size (128 - (sizeof(short) + pad1_size + sizeof(int64_t)))
+
+typedef struct {
+	short ss_family;
+	char pad1[pad1_size];
+	uint64_t pad64;
+	char pad2[pad2_size];
+} sockaddr_storage;
+
 typedef struct sockaddr sockaddr;
 typedef struct sockaddr_in sockaddr_in;
 
-bool Net_Listen(uint16_t port, bool (*packet_callback)(char* data, int datalen, int from));
+bool NetUDPServer_Listen(uint16_t port, bool (*packet_callback)(char* data, int datalen, int from));
+bool NetUDPServer_Send(sockaddr* address, char* data, int datalen)
 
 int NetUDPSocket_Create(uint16_t port);
@@ -36,4 +49,21 @@
 void NetUDPSocket_Close(int sock);
 
+typedef struct {
+	char signature[8];
+	uint16_t protocol_version;
+	char data[0];
+} handshake_packet;
+
+typedef struct {
+	char country[2];
+	char name[256];
+} connect_send; //signature="CONNECT\0"
+
+typedef struct {
+	char name[256];
+	uint32_t numplayers; //signature="STATUS\0\0"
+} status_recv;
+
+
 bool FLrListen_PacketCallback(char* data, int datalen, int from);
 bool FLrListen_Run();
Index: Daodan/Flatline/src/Flatline_Net.c
===================================================================
--- Daodan/Flatline/src/Flatline_Net.c	(revision 460)
+++ Daodan/Flatline/src/Flatline_Net.c	(revision 460)
@@ -0,0 +1,111 @@
+#include "Flatline.h"
+
+thread int UDPServer_Socket = 0;
+
+bool NetUDPServer_Listen(uint16_t port, bool (*packet_callback)(char* data, int datalen, int from))
+{
+	UDPServer_Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	
+	if (UDPServer_Socket < 0)
+	{
+		DDrStartupMessage("could not create socket");
+		return false;
+	}
+	
+	sockaddr_in address;
+	memset(&address, 0, sizeof(sockaddr_in));
+	address.sin_family = AF_INET;
+	address.sin_addr.s_addr = htonl(INADDR_ANY);
+	address.sin_port = htons(port);
+	
+	if (bind(UDPServer_Socket, (sockaddr*)&address, sizeof(sockaddr_in)) < 0)
+	{
+		DDrStartupMessage("could not bind port %d", port);
+		closesocket(UDPServer_Socket);
+		return false;
+	}
+	
+	char data[65537];
+	data[sizeof(data) - 1] = '\0';
+	sockaddr_in from;
+	int recvlen;
+	for (;;)
+	{
+		int fromlen = sizeof(sockaddr_in);
+		memset(&from, 0, sizeof(sockaddr_in));
+		recvlen = recvfrom(UDPServer_Socket, data, sizeof(data) - 1, 0, (sockaddr*)&from, (void*)&fromlen);
+		if (!packet_callback(data, recvlen, ntohl(from.sin_addr.s_addr)))
+			break;
+	}
+	closesocket(UDPServer_Socket);
+	return true;
+}
+
+bool NetUDPServer_Send(sockaddr* address, char* data, int datalen)
+{
+	return NetUDPSocket_Send(UDPServer_Socket, address, data, datalen);
+}
+
+int NetUDPSocket_Create(uint16_t port)
+{
+	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	
+	if (sock < 0)
+	{
+		DDrStartupMessage("could not create socket");
+		return -1;
+	}
+	
+	sockaddr_in address;
+	memset(&address, 0, sizeof(sockaddr_in));
+	address.sin_family = AF_INET;
+	address.sin_addr.s_addr = htonl(INADDR_ANY);
+	address.sin_port = htons(port);
+	
+	if (bind(sock, (sockaddr*)&address, sizeof(sockaddr_in)) < 0)
+	{
+		DDrStartupMessage("could not bind port %d", port);
+		return false;
+	}
+	
+	unsigned long nonBlocking = 1;
+	if (ioctlsocket(sock, FIONBIO, &nonBlocking))
+	{
+		DDrStartupMessage("failed to set non-blocking socket");
+		return false;
+	}
+	
+	return sock;
+}
+
+void NetUDPSocket_Close(int socket)
+{
+	closesocket(socket);
+}
+
+bool NetUDPSocket_Send(int socket, sockaddr* address, char* data, int datalen)
+{
+	uint32_t addr_size;
+	switch (address->sa_family)
+	{
+		case AF_INET:
+			addr_size = sizeof(sockaddr_in);
+			break;
+		case AF_INET6:
+			addr_size = sizeof(sockaddr_in6);
+			break;
+	}
+	return sendto(socket, data, datalen, 0, address, addr_size);
+}
+
+bool NetUDPSocket_Recieve(int socket, sockaddr_storage* address, char* data, uint16_t* datalen)
+{
+	uint32_t msg_size = recvfrom(socket, data, 512, 0, address, sizeof(sockaddr_storage));
+	if (msg_size == 0)
+		return false;
+	else
+	{
+		*datalen = msg_size;
+		return true;
+	}
+}
