2 #include <sys/socket.h>
3 #include <netinet/in.h>
14 #include "stg/common.h"
15 #include "stg/ia_packets.h"
16 #include "stg/locker.h"
20 class HasIP : public std::unary_function<std::pair<uint32_t, USER>, bool> {
22 explicit HasIP(uint32_t i) : ip(i) {}
23 bool operator()(const std::pair<uint32_t, USER> & value) { return value.first == ip; }
28 PROTO::PROTO(const std::string & server,
36 uint32_t ip = inet_addr(server.c_str());
37 if (ip == INADDR_NONE)
39 struct hostent * hePtr = gethostbyname(server.c_str());
42 ip = *((uint32_t *)hePtr->h_addr_list[0]);
46 errorStr = "Unknown host: '";
49 printfd(__FILE__, "PROTO::PROTO() - %s\n", errorStr.c_str());
50 throw std::runtime_error(errorStr);
54 localAddr.sin_family = AF_INET;
55 localAddr.sin_port = htons(localPort);
56 localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
58 serverAddr.sin_family = AF_INET;
59 serverAddr.sin_port = htons(port);
60 serverAddr.sin_addr.s_addr = ip;
62 unsigned char key[IA_PASSWD_LEN];
63 memset(key, 0, IA_PASSWD_LEN);
64 strncpy(reinterpret_cast<char *>(key), "pr7Hhen", 8);
65 Blowfish_Init(&ctx, key, IA_PASSWD_LEN);
67 processors["CONN_SYN_ACK"] = &PROTO::CONN_SYN_ACK_Proc;
68 processors["ALIVE_SYN"] = &PROTO::ALIVE_SYN_Proc;
69 processors["DISCONN_SYN_ACK"] = &PROTO::DISCONN_SYN_ACK_Proc;
70 processors["FIN"] = &PROTO::FIN_Proc;
71 processors["INFO"] = &PROTO::INFO_Proc;
72 // ERR_Proc will be handled explicitly
74 pthread_mutex_init(&mutex, NULL);
79 pthread_mutex_destroy(&mutex);
82 void * PROTO::Runner(void * data)
85 sigfillset(&signalSet);
86 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
88 PROTO * protoPtr = static_cast<PROTO *>(data);
97 if (pthread_create(&tid, NULL, &Runner, this))
99 errorStr = "Failed to create listening thread: '";
100 errorStr += strerror(errno);
102 printfd(__FILE__, "PROTO::Start() - %s\n", errorStr.c_str());
112 while (!stopped && time < timeout)
114 struct timespec ts = {1, 0};
115 nanosleep(&ts, NULL);
120 errorStr = "Failed to stop listening thread - timed out";
121 printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str());
124 if (pthread_join(tid, NULL))
126 errorStr = "Failed to join listening thread after stop: '";
127 errorStr += strerror(errno);
129 printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str());
135 void PROTO::AddUser(const USER & user, bool connect)
137 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
138 users.push_back(std::make_pair(user.GetIP(), user));
139 users.back().second.InitNetwork();
142 pfd.fd = users.back().second.GetSocket();
145 pollFds.push_back(pfd);
149 RealConnect(&users.back().second);
153 bool PROTO::Connect(uint32_t ip)
155 std::list<std::pair<uint32_t, USER> >::iterator it;
156 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
157 it = std::find_if(users.begin(), users.end(), HasIP(ip));
158 if (it == users.end())
163 return RealConnect(&it->second);
166 bool PROTO::Disconnect(uint32_t ip)
168 std::list<std::pair<uint32_t, USER> >::iterator it;
169 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
170 it = std::find_if(users.begin(), users.end(), HasIP(ip));
171 if (it == users.end())
176 return RealDisconnect(&it->second);
185 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
186 res = poll(&pollFds.front(), pollFds.size(), timeout);
194 printfd(__FILE__, "PROTO::Run() - events: %d\n", res);
206 void PROTO::CheckTimeouts()
208 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
209 std::list<std::pair<uint32_t, USER> >::iterator it;
210 for (it = users.begin(); it != users.end(); ++it)
212 int delta = difftime(time(NULL), it->second.GetPhaseChangeTime());
213 if ((it->second.GetPhase() == 3) &&
214 (delta > it->second.GetUserTimeout()))
216 printfd(__FILE__, "PROTO::CheckTimeouts() - user alive timeout (ip: %s, login: '%s', delta: %d > %d)\n", inet_ntostring(it->second.GetIP()).c_str(), it->second.GetLogin().c_str(), delta, it->second.GetUserTimeout());
217 it->second.SetPhase(1);
219 if ((it->second.GetPhase() == 2) &&
220 (delta > it->second.GetAliveTimeout()))
222 printfd(__FILE__, "PROTO::CheckTimeouts() - user connect timeout (ip: %s, login: '%s', delta: %d > %d)\n", inet_ntostring(it->second.GetIP()).c_str(), it->second.GetLogin().c_str(), delta, it->second.GetAliveTimeout());
223 it->second.SetPhase(1);
228 bool PROTO::RecvPacket()
231 std::vector<struct pollfd>::iterator it;
232 std::list<std::pair<uint32_t, USER> >::iterator userIt;
233 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
234 for (it = pollFds.begin(), userIt = users.begin(); it != pollFds.end() && userIt != users.end(); ++it, ++userIt)
239 assert(it->fd == userIt->second.GetSocket() && "File descriptors from poll fds and users must be syncked");
240 struct sockaddr_in addr;
241 socklen_t fromLen = sizeof(addr);
243 int res = recvfrom(userIt->second.GetSocket(), buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &fromLen);
251 result = result && HandlePacket(buffer, res, &(userIt->second));
258 bool PROTO::HandlePacket(const char * buffer, size_t length, USER * user)
260 if (!strncmp(buffer + 4 + sizeof(HDR_8), "ERR", 3))
262 return ERR_Proc(buffer, user);
265 for (size_t i = 0; i < length / 8; i++)
266 Blowfish_Decrypt(user->GetCtx(),
267 (uint32_t *)(buffer + i * 8),
268 (uint32_t *)(buffer + i * 8 + 4));
270 std::string packetName(buffer + 12);
272 std::map<std::string, PacketProcessor>::const_iterator it;
273 it = processors.find(packetName);
274 if (it != processors.end())
275 return (this->*it->second)(buffer, user);
277 printfd(__FILE__, "PROTO::HandlePacket() - invalid packet signature: '%s'\n", packetName.c_str());
282 bool PROTO::CONN_SYN_ACK_Proc(const void * buffer, USER * user)
284 const CONN_SYN_ACK_8 * packet = static_cast<const CONN_SYN_ACK_8 *>(buffer);
286 uint32_t rnd = packet->rnd;
287 uint32_t userTimeout = packet->userTimeOut;
288 uint32_t aliveTimeout = packet->aliveDelay;
292 SwapBytes(userTimeout);
293 SwapBytes(aliveDelay);
296 if (user->GetPhase() != 2)
298 errorStr = "Unexpected CONN_SYN_ACK";
299 printfd(__FILE__, "PROTO::CONN_SYN_ACK_Proc() - wrong phase: %d\n", user->GetPhase());
304 user->SetAliveTimeout(aliveTimeout);
305 user->SetUserTimeout(userTimeout);
310 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());
315 bool PROTO::ALIVE_SYN_Proc(const void * buffer, USER * user)
317 const ALIVE_SYN_8 * packet = static_cast<const ALIVE_SYN_8 *>(buffer);
319 uint32_t rnd = packet->rnd;
325 if (user->GetPhase() != 3)
327 errorStr = "Unexpected ALIVE_SYN";
328 printfd(__FILE__, "PROTO::ALIVE_SYN_Proc() - wrong phase: %d\n", user->GetPhase());
333 user->SetRnd(rnd); // Set new rnd value for ALIVE_ACK
335 Send_ALIVE_ACK(user);
340 bool PROTO::DISCONN_SYN_ACK_Proc(const void * buffer, USER * user)
342 const DISCONN_SYN_ACK_8 * packet = static_cast<const DISCONN_SYN_ACK_8 *>(buffer);
344 uint32_t rnd = packet->rnd;
350 if (user->GetPhase() != 4)
352 errorStr = "Unexpected DISCONN_SYN_ACK";
353 printfd(__FILE__, "PROTO::DISCONN_SYN_ACK_Proc() - wrong phase: %d\n", user->GetPhase());
357 if (user->GetRnd() + 1 != rnd)
359 errorStr = "Wrong control value at DISCONN_SYN_ACK";
360 printfd(__FILE__, "PROTO::DISCONN_SYN_ACK_Proc() - wrong control value: %d, expected: %d\n", rnd, user->GetRnd() + 1);
366 Send_DISCONN_ACK(user);
371 bool PROTO::FIN_Proc(const void * buffer, USER * user)
373 if (user->GetPhase() != 5)
375 errorStr = "Unexpected FIN";
376 printfd(__FILE__, "PROTO::FIN_Proc() - wrong phase: %d\n", user->GetPhase());
385 bool PROTO::INFO_Proc(const void * buffer, USER * user)
387 //const INFO_8 * packet = static_cast<const INFO_8 *>(buffer);
392 bool PROTO::ERR_Proc(const void * /*buffer*/, USER * user)
394 //uint32_t len = packet->len;
400 user->SetPhase(1); //TODO: Check
401 /*KOIToWin((const char*)err.text, &messageText);
402 if (pErrorCb != NULL)
403 pErrorCb(messageText, IA_SERVER_ERROR, errorCbData);
404 phaseTime = GetTickCount();
405 codeError = IA_SERVER_ERROR;*/
410 bool PROTO::Send_CONN_SYN(USER * user)
414 packet.len = sizeof(packet);
417 SwapBytes(packet.len);
420 strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
421 strncpy((char *)packet.type, "CONN_SYN", sizeof(packet.type));
422 strncpy((char *)packet.login, user->GetLogin().c_str(), sizeof(packet.login));
423 packet.dirs = 0xFFffFFff;
425 return SendPacket(&packet, sizeof(packet), user);
428 bool PROTO::Send_CONN_ACK(USER * user)
432 packet.len = sizeof(packet);
433 packet.rnd = user->IncRnd();
436 SwapBytes(packet.len);
437 SwapBytes(packet.rnd);
440 strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
441 strncpy((char *)packet.type, "CONN_ACK", sizeof(packet.type));
443 return SendPacket(&packet, sizeof(packet), user);
446 bool PROTO::Send_ALIVE_ACK(USER * user)
450 packet.len = sizeof(packet);
451 packet.rnd = user->IncRnd();
454 SwapBytes(packet.len);
455 SwapBytes(packet.rnd);
458 strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
459 strncpy((char *)packet.type, "ALIVE_ACK", sizeof(packet.type));
461 return SendPacket(&packet, sizeof(packet), user);
464 bool PROTO::Send_DISCONN_SYN(USER * user)
466 DISCONN_SYN_8 packet;
468 packet.len = sizeof(packet);
471 SwapBytes(packet.len);
474 strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
475 strncpy((char *)packet.type, "DISCONN_SYN", sizeof(packet.type));
476 strncpy((char *)packet.login, user->GetLogin().c_str(), sizeof(packet.login));
478 return SendPacket(&packet, sizeof(packet), user);
481 bool PROTO::Send_DISCONN_ACK(USER * user)
483 DISCONN_ACK_8 packet;
485 packet.len = sizeof(packet);
486 packet.rnd = user->IncRnd();
489 SwapBytes(packet.len);
490 SwapBytes(packet.rnd);
493 strncpy((char *)packet.loginS, user->GetLogin().c_str(), sizeof(packet.loginS));
494 strncpy((char *)packet.type, "DISCONN_ACK", sizeof(packet.type));
496 return SendPacket(&packet, sizeof(packet), user);
499 bool PROTO::SendPacket(const void * packet, size_t length, USER * user)
503 assert(length < 2048 && "Packet length must not exceed 2048 bytes");
505 strncpy((char *)hdr.magic, IA_ID, sizeof(hdr.magic));
507 hdr.protoVer[1] = 8; // IA_PROTO_VER
509 unsigned char buffer[2048];
510 memcpy(buffer, packet, length);
511 memcpy(buffer, &hdr, sizeof(hdr));
513 size_t offset = sizeof(HDR_8);
514 for (size_t i = 0; i < IA_LOGIN_LEN / 8; i++)
516 Blowfish_Encrypt(&ctx,
517 (uint32_t *)(buffer + offset + i * 8),
518 (uint32_t *)(buffer + offset + i * 8 + 4));
521 offset += IA_LOGIN_LEN;
522 size_t encLen = (length - IA_LOGIN_LEN) / 8;
523 for (size_t i = 0; i < encLen; i++)
525 Blowfish_Encrypt(user->GetCtx(),
526 (uint32_t*)(buffer + offset + i * 8),
527 (uint32_t*)(buffer + offset + i * 8 + 4));
530 int res = sendto(user->GetSocket(), buffer, length, 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
534 errorStr = "Failed to send packet: '";
535 errorStr += strerror(errno);
537 printfd(__FILE__, "PROTO::SendPacket() - %s, fd: %d\n", errorStr.c_str(), user->GetSocket());
543 errorStr = "Packet sent partially";
544 printfd(__FILE__, "PROTO::SendPacket() - %s\n", errorStr.c_str());
551 bool PROTO::RealConnect(USER * user)
553 if (user->GetPhase() != 1 &&
554 user->GetPhase() != 5)
556 errorStr = "Unexpected connect";
557 printfd(__FILE__, "PROTO::RealConnect() - wrong phase: %d\n", user->GetPhase());
561 return Send_CONN_SYN(user);
564 bool PROTO::RealDisconnect(USER * user)
566 if (user->GetPhase() != 3)
568 errorStr = "Unexpected disconnect";
569 printfd(__FILE__, "PROTO::RealDisconnect() - wrong phase: %d\n", user->GetPhase());
573 return Send_DISCONN_SYN(user);