diff --git a/common.cpp b/common.cpp
index 8719d8b..edfe258 100644
--- a/common.cpp
+++ b/common.cpp
@@ -8,3 +8,4 @@
 void Address::print() const
 	{ printf("%hhu.%hhu.%hhu.%hhu:%hu", ip[0], ip[1], ip[2], ip[3], port); }
 
+
diff --git a/common.h b/common.h
index cdfa08d..e72b161 100644
--- a/common.h
+++ b/common.h
@@ -3,10 +3,10 @@
 
 
 enum {
-	PACKET_SIZE     = 1024,
+	PACKET_SIZE     = 502,
 	PACKETS_COUNT   = 8*PACKET_SIZE,
 	TCP_BUFFER_SIZE = PACKET_SIZE*PACKETS_COUNT,
-	CRYPT_BLOCK     = 64,
+	CRYPT_BLOCK     = 128,
 };
 
 
diff --git a/socket.cpp b/socket.cpp
index 72c09eb..ffddddf 100644
--- a/socket.cpp
+++ b/socket.cpp
@@ -1,2 +1,121 @@
 
+#include <cstring>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+
 #include "socket.h"
+
+
+
+static void addressToInaddr(const Address &address, struct sockaddr_in addr) {
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = address.ipUInt;
+	addr.sin_port = htons(address.port);
+}
+
+static bool configureTcpSocket(int sockId) {
+	int tcp_nodelay = 1;
+	return 0 == setsockopt(sockId, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int))
+	    && 0 == fcntl(sockId, F_SETFL, fcntl(sockId, F_GETFL, 0) | O_NONBLOCK);
+}
+
+
+
+int Socket::tcpConnect(const Address &address) {
+	int sockId = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (sockId < 0) return -1;
+	struct sockaddr_in addr;
+	addressToInaddr(address, addr);
+	if ( 0 != ::connect(sockId, (struct sockaddr*)&addr, sizeof(addr))
+	  || !configureTcpSocket(sockId) )
+		{ ::close(sockId); return -1; }
+	return sockId;
+}
+
+
+int Socket::tcpListen(const Address &address) {
+	int sockId = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (sockId < 0) return -1;
+	struct sockaddr_in addr;
+	addressToInaddr(address, addr);
+	if ( 0 != ::bind(sockId, (struct sockaddr*)&addr, sizeof(addr))
+	  || 0 != ::listen(sockId, 16)
+	  || !configureTcpSocket(sockId) )
+		{ ::close(sockId); return -1; }
+	return sockId;
+}
+
+
+int Socket::tcpAccept(int sockId) {
+	struct sockaddr_in addr = {};
+	addr.sin_family = AF_INET;
+	socklen_t len = sizeof(addr);
+	int newSockId = ::accept(sockId, (struct sockaddr*)&addr, &len);
+	if (newSockId < 0) return -1;
+	if (!configureTcpSocket(newSockId))
+		{ ::close(newSockId); return -1; }
+	return newSockId;
+}
+
+
+int Socket::tcpSendAsync(int sockId, const void *data, int size) {
+	int res = ::send(sockId, data, size, MSG_DONTWAIT);
+	return res > 0 ? res : 0;
+}
+
+
+int Socket::tcpRecvAsync(int sockId, void *data, int size) {
+	int res = ::recv(sockId, data, size, MSG_DONTWAIT);
+	return res > 0 ? res : 0;
+}
+
+
+int Socket::udpBind(const Address &address) {
+	int sockId = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (sockId < 0) return -1;
+	
+	struct sockaddr_in addr;
+	addressToInaddr(address, addr);
+	if (0 != ::bind(sockId, (struct sockaddr*)&addr, sizeof(addr))) {
+		::close(sockId);
+		return -1;
+	}
+	
+	return sockId;
+}
+
+
+int Socket::udpSend(int sockId, const Address &address, const void *data, int size) {
+	struct sockaddr_in addr;
+	addressToInaddr(address, addr);
+	int res = ::sendto(sockId, data, size, 0, (struct sockaddr*)&addr, sizeof(addr));
+	return res > 0 ? res : 0;
+}
+
+
+int Socket::udpRecvAsync(int sockId, Address &address, void *data, int size) {
+	address = Address();
+	struct sockaddr_in addr = {};
+	addr.sin_family = AF_INET;
+	socklen_t len = sizeof(addr);
+	int res = ::recvfrom(sockId, data, size, MSG_DONTWAIT, (struct sockaddr*)&addr, &len);
+	if (res <= 0) return 0;
+	address.ipUInt = addr.sin_addr.s_addr;
+	address.port = ntohs(addr.sin_port);
+	return res;
+}
+
+
+void Socket::close(int sockId)
+	{ ::close(sockId); }
+
diff --git a/socket.h b/socket.h
index fb815d2..445e077 100644
--- a/socket.h
+++ b/socket.h
@@ -46,13 +46,13 @@ private:
 public:
 	static int tcpConnect(const Address &address);
 	static int tcpListen(const Address &address);
-	static int tcpAccept(int soskId);
-	static int tcpSendAsync(int soskId, const void *data, int size);
-	static int tcpRecvAsync(int soskId, void *data, int size);
+	static int tcpAccept(int sockId);
+	static int tcpSendAsync(int sockId, const void *data, int size);
+	static int tcpRecvAsync(int sockId, void *data, int size);
 	
 	static int udpBind(const Address &address);
-	static int udpSend(int soskId, const Address &address, const void *data, int size);
-	static int udpRecvAsync(int soskId, Address &address, void *data, int size);
+	static int udpSend(int sockId, const Address &address, const void *data, int size);
+	static int udpRecvAsync(int sockId, Address &address, void *data, int size);
 	
 	static void close(int soskId);
 };