+
+bool PROTO::CONN_SYN_ACK_Proc(const void * buffer, USER * user)
+{
+const CONN_SYN_ACK_8 * packet = static_cast<const CONN_SYN_ACK_8 *>(buffer);
+
+uint32_t rnd = packet->rnd;
+uint32_t userTimeout = packet->userTimeOut;
+uint32_t aliveTimeout = packet->aliveDelay;
+
+#ifdef ARCH_BE
+SwapBytes(rnd);
+SwapBytes(userTimeout);
+SwapBytes(aliveDelay);
+#endif
+
+if (user->GetPhase() != 2)
+ {
+ errorStr = "Unexpected CONN_SYN_ACK";
+ printfd(__FILE__, "PROTO::CONN_SYN_ACK_Proc() - wrong phase: %d\n", user->GetPhase());
+ return false;
+ }
+
+user->SetPhase(3);
+user->SetAliveTimeout(aliveTimeout);
+user->SetUserTimeout(userTimeout);
+user->SetRnd(rnd);
+
+Send_CONN_ACK(user);
+
+printfd(__FILE__, "PROTO::CONN_SYN_ACK_Proc() - user '%s' successfully logged in from IP %s\n", user->GetLogin().c_str(), inet_ntostring(user->GetIP()).c_str());
+
+return true;
+}
+
+bool PROTO::ALIVE_SYN_Proc(const void * buffer, USER * user)
+{
+const ALIVE_SYN_8 * packet = static_cast<const ALIVE_SYN_8 *>(buffer);
+
+uint32_t rnd = packet->rnd;
+
+#ifdef ARCH_BE
+SwapBytes(rnd);
+#endif
+
+if (user->GetPhase() != 3)
+ {
+ errorStr = "Unexpected ALIVE_SYN";
+ printfd(__FILE__, "PROTO::ALIVE_SYN_Proc() - wrong phase: %d\n", user->GetPhase());
+ return false;
+ }
+
+user->SetPhase(3);
+user->SetRnd(rnd); // Set new rnd value for ALIVE_ACK
+
+Send_ALIVE_ACK(user);
+
+return true;
+}
+
+bool PROTO::DISCONN_SYN_ACK_Proc(const void * buffer, USER * user)
+{
+const DISCONN_SYN_ACK_8 * packet = static_cast<const DISCONN_SYN_ACK_8 *>(buffer);
+
+uint32_t rnd = packet->rnd;
+
+#ifdef ARCH_BE
+SwapBytes(rnd);
+#endif
+
+if (user->GetPhase() != 4)
+ {
+ errorStr = "Unexpected DISCONN_SYN_ACK";
+ printfd(__FILE__, "PROTO::DISCONN_SYN_ACK_Proc() - wrong phase: %d\n", user->GetPhase());
+ return false;
+ }
+
+if (user->GetRnd() + 1 != rnd)
+ {
+ errorStr = "Wrong control value at DISCONN_SYN_ACK";
+ printfd(__FILE__, "PROTO::DISCONN_SYN_ACK_Proc() - wrong control value: %d, expected: %d\n", rnd, user->GetRnd() + 1);
+ }
+
+user->SetPhase(5);
+user->SetRnd(rnd);
+
+Send_DISCONN_ACK(user);
+
+return true;
+}
+
+bool PROTO::FIN_Proc(const void * buffer, USER * user)
+{
+if (user->GetPhase() != 5)
+ {
+ errorStr = "Unexpected FIN";
+ printfd(__FILE__, "PROTO::FIN_Proc() - wrong phase: %d\n", user->GetPhase());
+ return false;
+ }
+
+user->SetPhase(1);
+
+return true;
+}
+
+bool PROTO::INFO_Proc(const void * buffer, USER * user)
+{
+//const INFO_8 * packet = static_cast<const INFO_8 *>(buffer);
+
+return true;
+}
+
+bool PROTO::ERR_Proc(const void * buffer, USER * user)
+{
+const ERR_8 * packet = static_cast<const ERR_8 *>(buffer);
+const char * ptr = static_cast<const char *>(buffer);
+
+//uint32_t len = packet->len;
+
+#ifdef ARCH_BE
+//SwapBytes(len);
+#endif
+
+user->SetPhase(1); //TODO: Check
+/*KOIToWin((const char*)err.text, &messageText);
+if (pErrorCb != NULL)
+ pErrorCb(messageText, IA_SERVER_ERROR, errorCbData);
+phaseTime = GetTickCount();
+codeError = IA_SERVER_ERROR;*/
+
+return true;
+}
+
+bool PROTO::Send_CONN_SYN(USER * user)
+{
+CONN_SYN_8 packet;
+
+packet.len = sizeof(packet);
+
+#ifdef ARCH_BE
+SwapBytes(packet.len);
+#endif
+
+strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
+strncpy((char *)packet.type, "CONN_SYN", sizeof(packet.type));
+strncpy((char *)packet.login, user->GetLogin().c_str(), sizeof(packet.login));
+packet.dirs = 0xFFffFFff;
+
+return SendPacket(&packet, sizeof(packet), user);
+}
+
+bool PROTO::Send_CONN_ACK(USER * user)
+{
+CONN_ACK_8 packet;
+
+packet.len = sizeof(packet);
+packet.rnd = user->IncRnd();
+
+#ifdef ARCH_BE
+SwapBytes(packet.len);
+SwapBytes(packet.rnd);
+#endif
+
+strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
+strncpy((char *)packet.type, "CONN_ACK", sizeof(packet.type));
+
+return SendPacket(&packet, sizeof(packet), user);
+}
+
+bool PROTO::Send_ALIVE_ACK(USER * user)
+{
+ALIVE_ACK_8 packet;
+
+packet.len = sizeof(packet);
+packet.rnd = user->IncRnd();
+
+#ifdef ARCH_BE
+SwapBytes(packet.len);
+SwapBytes(packet.rnd);
+#endif
+
+strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
+strncpy((char *)packet.type, "ALIVE_ACK", sizeof(packet.type));
+
+return SendPacket(&packet, sizeof(packet), user);
+}
+
+bool PROTO::Send_DISCONN_SYN(USER * user)
+{
+DISCONN_SYN_8 packet;
+
+packet.len = sizeof(packet);
+
+#ifdef ARCH_BE
+SwapBytes(packet.len);
+#endif
+
+strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
+strncpy((char *)packet.type, "DISCONN_SYN", sizeof(packet.type));
+strncpy((char *)packet.login, user->GetLogin().c_str(), sizeof(packet.login));
+
+return SendPacket(&packet, sizeof(packet), user);
+}
+
+bool PROTO::Send_DISCONN_ACK(USER * user)
+{
+DISCONN_ACK_8 packet;
+
+packet.len = sizeof(packet);
+packet.rnd = user->IncRnd();
+
+#ifdef ARCH_BE
+SwapBytes(packet.len);
+SwapBytes(packet.rnd);
+#endif
+
+strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
+strncpy((char *)packet.type, "DISCONN_ACK", sizeof(packet.type));
+
+return SendPacket(&packet, sizeof(packet), user);
+}
+
+bool PROTO::SendPacket(const void * packet, size_t length, USER * user)
+{
+HDR_8 hdr;
+
+assert(length < 2048 && "Packet length must not exceed 2048 bytes");
+
+strncpy((char *)hdr.magic, IA_ID, sizeof(hdr.magic));
+hdr.protoVer[0] = 0;
+hdr.protoVer[1] = 8; // IA_PROTO_VER
+
+unsigned char buffer[2048];
+memset(buffer, 0, sizeof(buffer));
+memcpy(buffer, packet, length);
+memcpy(buffer, &hdr, sizeof(hdr));
+
+size_t offset = sizeof(HDR_8);
+for (size_t i = 0; i < IA_LOGIN_LEN / 8; i++)
+ {
+ Blowfish_Encrypt(&ctx,
+ (uint32_t *)(buffer + offset + i * 8),
+ (uint32_t *)(buffer + offset + i * 8 + 4));
+ }
+
+offset += IA_LOGIN_LEN;
+size_t encLen = (length - IA_LOGIN_LEN) / 8;
+for (size_t i = 0; i < encLen; i++)
+ {
+ Blowfish_Encrypt(user->GetCtx(),
+ (uint32_t*)(buffer + offset + i * 8),
+ (uint32_t*)(buffer + offset + i * 8 + 4));
+ }
+
+int res = sendto(user->GetSocket(), buffer, length, 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
+
+if (res < 0)
+ {
+ errorStr = "Failed to send packet: '";
+ errorStr += strerror(errno);
+ errorStr += "'";
+ printfd(__FILE__, "PROTO::SendPacket() - %s, fd: %d\n", errorStr.c_str(), user->GetSocket());
+ return false;
+ }
+
+if (res < length)
+ {
+ errorStr = "Packet sent partially";
+ printfd(__FILE__, "PROTO::SendPacket() - %s\n", errorStr.c_str());
+ return false;
+ }
+
+return true;
+}
+
+bool PROTO::RealConnect(USER * user)
+{
+if (user->GetPhase() != 1 &&
+ user->GetPhase() != 5)
+ {
+ errorStr = "Unexpected connect";
+ printfd(__FILE__, "PROTO::RealConnect() - wrong phase: %d\n", user->GetPhase());
+ }
+user->SetPhase(2);
+
+return Send_CONN_SYN(user);
+}
+
+bool PROTO::RealDisconnect(USER * user)
+{
+if (user->GetPhase() != 3)
+ {
+ errorStr = "Unexpected disconnect";
+ printfd(__FILE__, "PROTO::RealDisconnect() - wrong phase: %d\n", user->GetPhase());
+ }
+user->SetPhase(4);
+
+return Send_DISCONN_SYN(user);
+}