2 ** This program is free software; you can redistribute it and/or modify
3 ** it under the terms of the GNU General Public License as published by
4 ** the Free Software Foundation; either version 1, or (at your option)
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
12 ** You should have received a copy of the GNU General Public License
13 ** along with this program; if not, write to the Free Software
14 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Date: 2010/04/16 11:28:03 $
25 * Boris Mikhailenko <stg34@stargazer.dp.ua>
26 * Maxim Mamontov <faust@stargazer.dp.ua>
27 * Andrey Rakhmanov <andrey_rakhmanov@yahoo.com> - bugfixes.
30 //---------------------------------------------------------------------------
40 #include <arpa/inet.h>
50 #include "stg/common.h"
54 #define IA_CONNECT (1)
55 #define IA_DISCONNECT (2)
57 #define IA_DEBUGPROTO 1
60 //---------------------------------------------------------------------------
61 //---------------------------------------------------------------------------
62 //---------------------------------------------------------------------------
67 long long res = ms * 1000000;
68 struct timespec ts = {res / 1000000000, res % 1000000000};
71 //---------------------------------------------------------------------------
72 void * RunL(void * data)
75 sigfillset(&signalSet);
76 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
78 IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
87 while (c->GetNonstop())
93 //---------------------------------------------------------------------------
97 gettimeofday(&tv, NULL);
98 return tv.tv_sec*1000 + tv.tv_usec/1000;
101 //---------------------------------------------------------------------------
102 unsigned long WINAPI RunW(void * data)
104 IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
105 while (c->GetNonstop())
109 //---------------------------------------------------------------------------
111 //---------------------------------------------------------------------------
112 //---------------------------------------------------------------------------
113 //---------------------------------------------------------------------------
114 IA_CLIENT_PROT::IA_CLIENT_PROT(const string & sn, unsigned short p, uint16_t localPort)
120 isNetPrepared(false),
125 localPort(localPort),
133 pStatusChangedCb(NULL),
134 pStatChangedCb(NULL),
138 statusChangedCbData(NULL),
139 statChangedCbData(NULL),
149 disconnSynAck8(NULL),
153 memset(&stat, 0, sizeof(stat));
156 WSAStartup(MAKEWORD(2, 0), &wsaData);
159 packetTypes["CONN_SYN"] = CONN_SYN_N;
160 packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
161 packetTypes["CONN_ACK"] = CONN_ACK_N;
162 packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
163 packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
164 packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
165 packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
166 packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
167 packetTypes["FIN"] = FIN_N;
168 packetTypes["ERR"] = ERROR_N;
169 packetTypes["INFO"] = INFO_N;
170 packetTypes["INFO_7"] = INFO_7_N;
171 packetTypes["INFO_8"] = INFO_8_N;
173 unsigned char key[IA_PASSWD_LEN];
174 memset(key, 0, IA_PASSWD_LEN);
175 strncpy((char *)key, "pr7Hhen", 8);
176 Blowfish_Init(&ctxHdr, key, IA_PASSWD_LEN);
178 memset(key, 0, IA_PASSWD_LEN);
179 Blowfish_Init(&ctxPass, key, IA_PASSWD_LEN);
181 for (size_t i = 0; i < DIR_NUM; ++i)
183 selectedDirs[i] = false;
186 servAddr.sin_family = AF_INET;
187 servAddr.sin_port = htons(port);
188 servAddr.sin_addr.s_addr = ip;
190 //---------------------------------------------------------------------------
191 void IA_CLIENT_PROT::PrepareNet()
193 struct hostent * phe;
196 ip = inet_addr(serverName.c_str());
197 if (ip == INADDR_NONE)
199 phe = gethostbyname(serverName.c_str());
202 ip = *((unsigned long*)phe->h_addr_list[0]);
206 strError = string("Unknown host ") + "\'" + serverName + "\'";
207 codeError = IA_GETHOSTBYNAME_ERROR;
208 if (pErrorCb != NULL)
209 pErrorCb(strError, IA_GETHOSTBYNAME_ERROR, errorCbData);
219 sockr = socket(AF_INET, SOCK_DGRAM, 0);
221 struct sockaddr_in localAddrR;
222 localAddrR.sin_family = AF_INET;
225 localAddrR.sin_port = htons(localPort);
227 localAddrR.sin_port = htons(port);
228 localAddrR.sin_addr.s_addr = inet_addr("0.0.0.0");
230 servAddr.sin_family = AF_INET;
231 servAddr.sin_port = htons(port);
232 servAddr.sin_addr.s_addr = ip;
234 int res = bind(sockr, (struct sockaddr*)&localAddrR, sizeof(localAddrR));
237 strError = "bind error";
238 codeError = IA_BIND_ERROR;
239 if (pErrorCb != NULL)
240 pErrorCb(strError, IA_BIND_ERROR, errorCbData);
245 unsigned long arg = 1;
246 res = ioctlsocket(sockr, FIONBIO, &arg);
248 if (0 != fcntl(sockr, F_SETFL, O_NONBLOCK))
250 strError = "fcntl error";
251 codeError = IA_FCNTL_ERROR;
252 if (pErrorCb != NULL)
253 pErrorCb(strError, IA_FCNTL_ERROR, errorCbData);
258 //---------------------------------------------------------------------------
259 IA_CLIENT_PROT::~IA_CLIENT_PROT()
268 //---------------------------------------------------------------------------
269 int IA_CLIENT_PROT::DeterminatePacketType(const char * buffer)
271 map<string, int>::iterator pi;
272 pi = packetTypes.find(buffer);
273 if (pi == packetTypes.end())
282 //---------------------------------------------------------------------------
283 void IA_CLIENT_PROT::FillHdr8(char * buffer, unsigned long)
285 strncpy(buffer, IA_ID, 6);
286 buffer[IA_MAGIC_LEN] = 0;
287 buffer[IA_MAGIC_LEN + 1] = IA_PROTO_VER;
288 strncpy(buffer + sizeof(HDR_8), login.c_str(), IA_LOGIN_LEN);
290 //---------------------------------------------------------------------------
291 int IA_CLIENT_PROT::Send(char * buffer, int len)
296 isNetPrepared = true;
299 int db = sizeof(HDR_8);
300 for (int i = 0; i < IA_LOGIN_LEN/8; i++)
302 Blowfish_Encrypt(&ctxHdr, (uint32_t*)(buffer + db + i*8), (uint32_t*)(buffer + db + i*8 + 4));
306 int encLen = (len - sizeof(HDR_8) - IA_LOGIN_LEN)/8;
307 for (int i = 0; i < encLen; i++)
309 Blowfish_Encrypt(&ctxPass, (uint32_t*)(buffer + db), (uint32_t*)(buffer + db + 4));
313 return sendto(sockr, buffer, len, 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
315 //---------------------------------------------------------------------------
316 int IA_CLIENT_PROT::Recv(char * buffer, int len)
324 struct sockaddr_in addr;
325 fromLen = sizeof(addr);
326 int res = recvfrom(sockr, buffer, len, 0, (struct sockaddr*)&addr, &fromLen);
331 if (strcmp(buffer + 4 + sizeof(HDR_8), "ERR"))
333 for (int i = 0; i < len/8; i++)
334 Blowfish_Decrypt(&ctxPass, (uint32_t*)(buffer + i*8), (uint32_t*)(buffer + i*8 + 4));
339 //---------------------------------------------------------------------------
340 int IA_CLIENT_PROT::NetSend(int n)
345 memset(buffer, 0, 2048);
350 msgLen = Prepare_CONN_SYN_8(buffer);
354 msgLen = Prepare_CONN_ACK_8(buffer);
358 msgLen = Prepare_ALIVE_ACK_8(buffer);
362 msgLen = Prepare_DISCONN_SYN_8(buffer);
366 msgLen = Prepare_DISCONN_ACK_8(buffer);
374 Send(buffer, msgLen);
378 //---------------------------------------------------------------------------
379 int IA_CLIENT_PROT::NetRecv()
383 if (Recv(buffer, sizeof(buffer)) < 0)
387 strncpy(packetName, buffer + 12, sizeof(packetName));
388 packetName[sizeof(packetName) - 1] = 0;
389 int pn = DeterminatePacketType(buffer + 12);
395 ret = Process_CONN_SYN_ACK_8(buffer);
399 ret = Process_ALIVE_SYN_8(buffer);
402 case DISCONN_SYN_ACK_N:
403 ret = Process_DISCONN_SYN_ACK_8(buffer);
407 ret = Process_FIN_8(buffer);
411 ret = Process_INFO_8(buffer);
415 ret = Process_ERROR(buffer);
423 //---------------------------------------------------------------------------
424 void IA_CLIENT_PROT::Start()
429 CreateThread(NULL, 16384, RunW, this, 0, &pt);
431 pthread_create(&thread, NULL, RunL, this);
434 //---------------------------------------------------------------------------
435 void IA_CLIENT_PROT::Stop()
439 //---------------------------------------------------------------------------
440 void IA_CLIENT_PROT::Run()
447 if (action == IA_CONNECT)
452 phaseTime = GetTickCount();
454 if (reconnect && !firstConnect)
461 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
464 phaseTime = GetTickCount();
465 if (pStatusChangedCb != NULL)
466 pStatusChangedCb(0, statusChangedCbData);
469 if (action == IA_DISCONNECT)
472 NetSend(DISCONN_SYN_N);
474 phaseTime = GetTickCount();
480 if ((int)(GetTickCount() - phaseTime)/1000 > userTimeout)
483 phaseTime = GetTickCount();
484 if (pStatusChangedCb != NULL)
485 pStatusChangedCb(0, statusChangedCbData);
486 firstConnect = false;
489 if (action == IA_DISCONNECT)
492 NetSend(DISCONN_SYN_N);
494 phaseTime = GetTickCount();
500 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
503 phaseTime = GetTickCount();
504 if (pStatusChangedCb != NULL)
505 pStatusChangedCb(0, statusChangedCbData);
508 if (action == IA_CONNECT)
513 phaseTime = GetTickCount();
519 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
522 phaseTime = GetTickCount();
523 if (pStatusChangedCb != NULL)
524 pStatusChangedCb(0, statusChangedCbData);
527 if (action == IA_CONNECT)
532 phaseTime = GetTickCount();
540 //---------------------------------------------------------------------------
541 void IA_CLIENT_PROT::GetStat(LOADSTAT * ls)
543 memcpy(ls, &stat, sizeof(stat));
545 //---------------------------------------------------------------------------
546 void IA_CLIENT_PROT::SetServer(const string & sn, unsigned short p)
552 //---------------------------------------------------------------------------
553 void IA_CLIENT_PROT::SetLogin(const string & l)
557 //---------------------------------------------------------------------------
558 void IA_CLIENT_PROT::SetPassword(const string & p)
562 unsigned char keyL[IA_PASSWD_LEN];
563 memset(keyL, 0, IA_PASSWD_LEN);
564 strncpy((char *)keyL, password.c_str(), IA_PASSWD_LEN);
565 Blowfish_Init(&ctxPass, keyL, IA_PASSWD_LEN);
567 //---------------------------------------------------------------------------
568 void IA_CLIENT_PROT::SetEnabledDirs(const bool * selectedDirs)
570 memcpy(IA_CLIENT_PROT::selectedDirs, selectedDirs, sizeof(bool) * DIR_NUM);
572 //---------------------------------------------------------------------------
573 int IA_CLIENT_PROT::Connect()
578 //---------------------------------------------------------------------------
579 int IA_CLIENT_PROT::Disconnect()
582 action = IA_DISCONNECT;
585 //---------------------------------------------------------------------------
586 int IA_CLIENT_PROT::GetStrError(string * error) const
594 //---------------------------------------------------------------------------
595 int IA_CLIENT_PROT::Process_CONN_SYN_ACK_8(const char * buffer)
597 vector<string> dirNames;
598 connSynAck8 = (CONN_SYN_ACK_8*)buffer;
601 SwapBytes(connSynAck8->len);
602 SwapBytes(connSynAck8->rnd);
603 SwapBytes(connSynAck8->userTimeOut);
604 SwapBytes(connSynAck8->aliveDelay);
607 rnd = connSynAck8->rnd;
608 userTimeout = connSynAck8->userTimeOut;
609 aliveTimeout = connSynAck8->aliveDelay;
611 for (int i = 0; i < DIR_NUM; i++)
613 dirNames.push_back((const char*)connSynAck8->dirName[i]);
616 if (pDirNameCb != NULL)
617 pDirNameCb(dirNames, dirNameCbData);
621 phaseTime = GetTickCount();
623 return CONN_SYN_ACK_N;
625 //---------------------------------------------------------------------------
626 int IA_CLIENT_PROT::Process_ALIVE_SYN_8(const char * buffer)
628 aliveSyn8 = (ALIVE_SYN_8*)buffer;
631 SwapBytes(aliveSyn8->len);
632 SwapBytes(aliveSyn8->rnd);
633 SwapBytes(aliveSyn8->cash);
634 SwapBytes(aliveSyn8->status);
635 for (int i = 0; i < DIR_NUM; ++i)
637 SwapBytes(aliveSyn8->mu[i]);
638 SwapBytes(aliveSyn8->md[i]);
639 SwapBytes(aliveSyn8->su[i]);
640 SwapBytes(aliveSyn8->sd[i]);
644 rnd = aliveSyn8->rnd;
645 memcpy(&stat, (char*)aliveSyn8->mu, sizeof(stat));
647 if (pStatChangedCb != NULL)
648 pStatChangedCb(stat, statChangedCbData);
650 if (pStatusChangedCb != NULL)
651 pStatusChangedCb(1, statusChangedCbData);
652 NetSend(ALIVE_ACK_N);
653 phaseTime = GetTickCount();
657 //---------------------------------------------------------------------------
658 int IA_CLIENT_PROT::Process_DISCONN_SYN_ACK_8(const char * buffer)
660 disconnSynAck8 = (DISCONN_SYN_ACK_8*)buffer;
663 SwapBytes(disconnSynAck8->len);
664 SwapBytes(disconnSynAck8->rnd);
667 rnd = disconnSynAck8->rnd;
669 NetSend(DISCONN_ACK_N);
671 phaseTime = GetTickCount();
673 return DISCONN_SYN_ACK_N;
675 //---------------------------------------------------------------------------
676 int IA_CLIENT_PROT::Process_FIN_8(const char *)
679 phaseTime = GetTickCount();
680 if (pStatusChangedCb != NULL)
681 pStatusChangedCb(0, statusChangedCbData);
685 //---------------------------------------------------------------------------
686 int IA_CLIENT_PROT::Process_INFO_8(const char * buffer)
688 info = (INFO_8*)buffer;
691 SwapBytes(info->len);
692 SwapBytes(info->sendTime);
696 pInfoCb((char*)info->text, info->infoType, info->showTime, info->sendTime, infoCbData);
699 //---------------------------------------------------------------------------
700 int IA_CLIENT_PROT::Process_ERROR(const char * buffer)
703 memcpy(&err, buffer, sizeof(err));
709 KOIToWin((const char*)err.text, &messageText);
710 if (pErrorCb != NULL)
711 pErrorCb(messageText, IA_SERVER_ERROR, errorCbData);
713 phaseTime = GetTickCount();
714 codeError = IA_SERVER_ERROR;
718 //---------------------------------------------------------------------------
719 int IA_CLIENT_PROT::Prepare_CONN_SYN_8(char * buffer)
721 connSyn8 = (CONN_SYN_8*)buffer;
724 SwapBytes(connSyn8->len);
727 assert(sizeof(CONN_SYN_8) == Min8(sizeof(CONN_SYN_8)) && "CONN_SYN_8 is not aligned to 8 bytes");
729 connSyn8->len = sizeof(CONN_SYN_8);
730 strncpy((char*)connSyn8->type, "CONN_SYN", IA_MAX_TYPE_LEN);
731 strncpy((char*)connSyn8->login, login.c_str(), IA_LOGIN_LEN);
733 for (int i = 0; i < DIR_NUM; i++)
735 connSyn8->dirs |= (selectedDirs[i] << i);
737 return connSyn8->len;
739 //---------------------------------------------------------------------------
740 int IA_CLIENT_PROT::Prepare_CONN_ACK_8(char * buffer)
742 connAck8 = (CONN_ACK_8*)buffer;
745 SwapBytes(connAck8->len);
746 SwapBytes(connAck8->rnd);
749 assert(sizeof(CONN_ACK_8) == Min8(sizeof(CONN_ACK_8)) && "CONN_ACK_8 is not aligned to 8 bytes");
751 connAck8->len = sizeof(CONN_ACK_8);
752 strncpy((char*)connAck8->loginS, login.c_str(), IA_LOGIN_LEN);
753 strncpy((char*)connAck8->type, "CONN_ACK", IA_MAX_TYPE_LEN);
757 return connAck8->len;
759 //---------------------------------------------------------------------------
760 int IA_CLIENT_PROT::Prepare_ALIVE_ACK_8(char * buffer)
762 aliveAck8 = (ALIVE_ACK_8*)buffer;
765 SwapBytes(aliveAck8->len);
766 SwapBytes(aliveAck8->rnd);
769 assert(Min8(sizeof(ALIVE_ACK_8)) == sizeof(ALIVE_ACK_8) && "ALIVE_ACK_8 is not aligned to 8 bytes");
771 aliveAck8 = (ALIVE_ACK_8*)buffer;
772 aliveAck8->len = sizeof(ALIVE_ACK_8);
773 strncpy((char*)aliveAck8->loginS, login.c_str(), IA_LOGIN_LEN);
774 strncpy((char*)aliveAck8->type, "ALIVE_ACK", IA_MAX_TYPE_LEN);
775 aliveAck8->rnd = ++rnd;
776 return aliveAck8->len;
778 //---------------------------------------------------------------------------
779 int IA_CLIENT_PROT::Prepare_DISCONN_SYN_8(char * buffer)
781 disconnSyn8 = (DISCONN_SYN_8*)buffer;
784 SwapBytes(disconnSyn8->len);
787 assert(Min8(sizeof(DISCONN_SYN_8)) == sizeof(DISCONN_SYN_8) && "DISCONN_SYN_8 is not aligned to 8 bytes");
789 disconnSyn8->len = sizeof(DISCONN_SYN_8);
790 strncpy((char*)disconnSyn8->loginS, login.c_str(), IA_LOGIN_LEN);
791 strncpy((char*)disconnSyn8->type, "DISCONN_SYN", IA_MAX_TYPE_LEN);
792 strncpy((char*)disconnSyn8->login, login.c_str(), IA_LOGIN_LEN);
793 return disconnSyn8->len;
795 //---------------------------------------------------------------------------
796 int IA_CLIENT_PROT::Prepare_DISCONN_ACK_8(char * buffer)
798 disconnAck8 = (DISCONN_ACK_8*)buffer;
801 SwapBytes(disconnAck8->len);
802 SwapBytes(disconnAck8->rnd);
805 assert(Min8(sizeof(DISCONN_ACK_8)) == sizeof(DISCONN_ACK_8) && "DISCONN_ACK_8 is not aligned to 8 bytes");
807 disconnAck8->len = Min8(sizeof(DISCONN_ACK_8));
808 disconnAck8->rnd = rnd + 1;
809 strncpy((char*)disconnAck8->loginS, login.c_str(), IA_LOGIN_LEN);
810 strncpy((char*)disconnAck8->type, "DISCONN_ACK", IA_MAX_TYPE_LEN);
811 return disconnAck8->len;
813 //---------------------------------------------------------------------------
814 void IA_CLIENT_PROT::SetStatusChangedCb(tpStatusChangedCb p, void * data)
816 pStatusChangedCb = p;
817 statusChangedCbData = data;
819 //---------------------------------------------------------------------------
820 void IA_CLIENT_PROT::SetStatChangedCb(tpStatChangedCb p, void * data)
823 statChangedCbData = data;
825 //---------------------------------------------------------------------------
826 void IA_CLIENT_PROT::SetInfoCb(tpCallBackInfoFn p, void * data)
831 //---------------------------------------------------------------------------
832 void IA_CLIENT_PROT::SetDirNameCb(tpCallBackDirNameFn p, void * data)
835 dirNameCbData = data;
837 //---------------------------------------------------------------------------
838 void IA_CLIENT_PROT::SetErrorCb(tpCallBackErrorFn p, void * data)
843 //---------------------------------------------------------------------------