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 //---------------------------------------------------------------------------
45 #include <arpa/inet.h>
49 #include "stg/common.h"
53 #define IA_CONNECT (1)
54 #define IA_DISCONNECT (2)
56 #define IA_DEBUGPROTO 1
59 //---------------------------------------------------------------------------
60 //---------------------------------------------------------------------------
61 //---------------------------------------------------------------------------
64 void * RunL(void * data)
67 IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
76 while (c->GetNonstop())
82 //---------------------------------------------------------------------------
87 //---------------------------------------------------------------------------
91 gettimeofday(&tv, NULL);
92 return tv.tv_sec*1000 + tv.tv_usec/1000;
95 //---------------------------------------------------------------------------
96 unsigned long WINAPI RunW(void * data)
98 IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
99 while (c->GetNonstop())
103 //---------------------------------------------------------------------------
105 //---------------------------------------------------------------------------
106 //---------------------------------------------------------------------------
107 //---------------------------------------------------------------------------
108 IA_CLIENT_PROT::IA_CLIENT_PROT(const string & sn, unsigned short p, uint16_t localPort)
114 isNetPrepared(false),
119 localPort(localPort),
127 pStatusChangedCb(NULL),
128 pStatChangedCb(NULL),
132 statusChangedCbData(NULL),
133 statChangedCbData(NULL),
143 disconnSynAck8(NULL),
147 memset(&stat, 0, sizeof(stat));
150 WSAStartup(MAKEWORD(2, 0), &wsaData);
153 packetTypes["CONN_SYN"] = CONN_SYN_N;
154 packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
155 packetTypes["CONN_ACK"] = CONN_ACK_N;
156 packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
157 packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
158 packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
159 packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
160 packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
161 packetTypes["FIN"] = FIN_N;
162 packetTypes["ERR"] = ERROR_N;
163 packetTypes["INFO"] = INFO_N;
164 packetTypes["INFO_7"] = INFO_7_N;
165 packetTypes["INFO_8"] = INFO_8_N;
167 unsigned char key[IA_PASSWD_LEN];
168 memset(key, 0, IA_PASSWD_LEN);
169 strncpy((char *)key, "pr7Hhen", 8);
170 Blowfish_Init(&ctxHdr, key, IA_PASSWD_LEN);
172 memset(key, 0, IA_PASSWD_LEN);
173 Blowfish_Init(&ctxPass, key, IA_PASSWD_LEN);
175 for (size_t i = 0; i < DIR_NUM; ++i)
177 selectedDirs[i] = false;
180 servAddr.sin_family = AF_INET;
181 servAddr.sin_port = htons(port);
182 servAddr.sin_addr.s_addr = ip;
184 //---------------------------------------------------------------------------
185 void IA_CLIENT_PROT::PrepareNet()
187 struct hostent * phe;
190 ip = inet_addr(serverName.c_str());
191 if (ip == INADDR_NONE)
193 phe = gethostbyname(serverName.c_str());
196 ip = *((unsigned long*)phe->h_addr_list[0]);
200 strError = string("Unknown host ") + "\'" + serverName + "\'";
201 codeError = IA_GETHOSTBYNAME_ERROR;
202 if (pErrorCb != NULL)
203 pErrorCb(strError, IA_GETHOSTBYNAME_ERROR, errorCbData);
213 sockr = socket(AF_INET, SOCK_DGRAM, 0);
215 struct sockaddr_in localAddrR;
216 localAddrR.sin_family = AF_INET;
219 localAddrR.sin_port = htons(localPort);
221 localAddrR.sin_port = htons(port);
222 localAddrR.sin_addr.s_addr = inet_addr("0.0.0.0");
224 servAddr.sin_family = AF_INET;
225 servAddr.sin_port = htons(port);
226 servAddr.sin_addr.s_addr = ip;
228 int res = bind(sockr, (struct sockaddr*)&localAddrR, sizeof(localAddrR));
231 strError = "bind error";
232 codeError = IA_BIND_ERROR;
233 if (pErrorCb != NULL)
234 pErrorCb(strError, IA_BIND_ERROR, errorCbData);
239 unsigned long arg = 1;
240 res = ioctlsocket(sockr, FIONBIO, &arg);
242 if (0 != fcntl(sockr, F_SETFL, O_NONBLOCK))
244 strError = "fcntl error";
245 codeError = IA_FCNTL_ERROR;
246 if (pErrorCb != NULL)
247 pErrorCb(strError, IA_FCNTL_ERROR, errorCbData);
252 //---------------------------------------------------------------------------
253 IA_CLIENT_PROT::~IA_CLIENT_PROT()
262 //---------------------------------------------------------------------------
263 int IA_CLIENT_PROT::DeterminatePacketType(const char * buffer)
265 map<string, int>::iterator pi;
266 pi = packetTypes.find(buffer);
267 if (pi == packetTypes.end())
276 //---------------------------------------------------------------------------
277 void IA_CLIENT_PROT::FillHdr8(char * buffer, unsigned long)
279 strncpy(buffer, IA_ID, 6);
280 buffer[IA_MAGIC_LEN] = 0;
281 buffer[IA_MAGIC_LEN + 1] = IA_PROTO_VER;
282 strncpy(buffer + sizeof(HDR_8), login.c_str(), IA_LOGIN_LEN);
284 //---------------------------------------------------------------------------
285 int IA_CLIENT_PROT::Send(char * buffer, int len)
290 isNetPrepared = true;
293 int db = sizeof(HDR_8);
294 for (int i = 0; i < IA_LOGIN_LEN/8; i++)
296 Blowfish_Encrypt(&ctxHdr, (uint32_t*)(buffer + db + i*8), (uint32_t*)(buffer + db + i*8 + 4));
300 int encLen = (len - sizeof(HDR_8) - IA_LOGIN_LEN)/8;
301 for (int i = 0; i < encLen; i++)
303 Blowfish_Encrypt(&ctxPass, (uint32_t*)(buffer + db), (uint32_t*)(buffer + db + 4));
307 return sendto(sockr, buffer, len, 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
309 //---------------------------------------------------------------------------
310 int IA_CLIENT_PROT::Recv(char * buffer, int len)
318 struct sockaddr_in addr;
319 fromLen = sizeof(addr);
320 int res = recvfrom(sockr, buffer, len, 0, (struct sockaddr*)&addr, &fromLen);
325 if (strcmp(buffer + 4 + sizeof(HDR_8), "ERR"))
327 for (int i = 0; i < len/8; i++)
328 Blowfish_Decrypt(&ctxPass, (uint32_t*)(buffer + i*8), (uint32_t*)(buffer + i*8 + 4));
333 //---------------------------------------------------------------------------
334 int IA_CLIENT_PROT::NetSend(int n)
339 memset(buffer, 0, 2048);
344 msgLen = Prepare_CONN_SYN_8(buffer);
348 msgLen = Prepare_CONN_ACK_8(buffer);
352 msgLen = Prepare_ALIVE_ACK_8(buffer);
356 msgLen = Prepare_DISCONN_SYN_8(buffer);
360 msgLen = Prepare_DISCONN_ACK_8(buffer);
368 Send(buffer, msgLen);
372 //---------------------------------------------------------------------------
373 int IA_CLIENT_PROT::NetRecv()
377 if (Recv(buffer, sizeof(buffer)) < 0)
381 strncpy(packetName, buffer + 12, sizeof(packetName));
382 packetName[sizeof(packetName) - 1] = 0;
383 int pn = DeterminatePacketType(buffer + 12);
389 ret = Process_CONN_SYN_ACK_8(buffer);
393 ret = Process_ALIVE_SYN_8(buffer);
396 case DISCONN_SYN_ACK_N:
397 ret = Process_DISCONN_SYN_ACK_8(buffer);
401 ret = Process_FIN_8(buffer);
405 ret = Process_INFO_8(buffer);
409 ret = Process_ERROR(buffer);
417 //---------------------------------------------------------------------------
418 void IA_CLIENT_PROT::Start()
423 CreateThread(NULL, 16384, RunW, this, 0, &pt);
425 pthread_create(&thread, NULL, RunL, this);
428 //---------------------------------------------------------------------------
429 void IA_CLIENT_PROT::Stop()
433 //---------------------------------------------------------------------------
434 void IA_CLIENT_PROT::Run()
441 if (action == IA_CONNECT)
446 phaseTime = GetTickCount();
448 if (reconnect && !firstConnect)
455 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
458 phaseTime = GetTickCount();
459 if (pStatusChangedCb != NULL)
460 pStatusChangedCb(0, statusChangedCbData);
463 if (action == IA_DISCONNECT)
466 NetSend(DISCONN_SYN_N);
468 phaseTime = GetTickCount();
474 if ((int)(GetTickCount() - phaseTime)/1000 > userTimeout)
477 phaseTime = GetTickCount();
478 if (pStatusChangedCb != NULL)
479 pStatusChangedCb(0, statusChangedCbData);
480 firstConnect = false;
483 if (action == IA_DISCONNECT)
486 NetSend(DISCONN_SYN_N);
488 phaseTime = GetTickCount();
494 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
497 phaseTime = GetTickCount();
498 if (pStatusChangedCb != NULL)
499 pStatusChangedCb(0, statusChangedCbData);
502 if (action == IA_CONNECT)
507 phaseTime = GetTickCount();
513 if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
516 phaseTime = GetTickCount();
517 if (pStatusChangedCb != NULL)
518 pStatusChangedCb(0, statusChangedCbData);
521 if (action == IA_CONNECT)
526 phaseTime = GetTickCount();
534 //---------------------------------------------------------------------------
535 void IA_CLIENT_PROT::GetStat(LOADSTAT * ls)
537 memcpy(ls, &stat, sizeof(stat));
539 //---------------------------------------------------------------------------
540 void IA_CLIENT_PROT::SetServer(const string & sn, unsigned short p)
546 //---------------------------------------------------------------------------
547 void IA_CLIENT_PROT::SetLogin(const string & l)
551 //---------------------------------------------------------------------------
552 void IA_CLIENT_PROT::SetPassword(const string & p)
556 unsigned char keyL[IA_PASSWD_LEN];
557 memset(keyL, 0, IA_PASSWD_LEN);
558 strncpy((char *)keyL, password.c_str(), IA_PASSWD_LEN);
559 Blowfish_Init(&ctxPass, keyL, IA_PASSWD_LEN);
561 //---------------------------------------------------------------------------
562 void IA_CLIENT_PROT::SetEnabledDirs(const bool * selectedDirs)
564 memcpy(IA_CLIENT_PROT::selectedDirs, selectedDirs, sizeof(bool) * DIR_NUM);
566 //---------------------------------------------------------------------------
567 int IA_CLIENT_PROT::Connect()
572 //---------------------------------------------------------------------------
573 int IA_CLIENT_PROT::Disconnect()
576 action = IA_DISCONNECT;
579 //---------------------------------------------------------------------------
580 int IA_CLIENT_PROT::GetStrError(string * error) const
588 //---------------------------------------------------------------------------
589 int IA_CLIENT_PROT::Process_CONN_SYN_ACK_8(const char * buffer)
591 vector<string> dirNames;
592 connSynAck8 = (CONN_SYN_ACK_8*)buffer;
595 SwapBytes(connSynAck8->len);
596 SwapBytes(connSynAck8->rnd);
597 SwapBytes(connSynAck8->userTimeOut);
598 SwapBytes(connSynAck8->aliveDelay);
601 rnd = connSynAck8->rnd;
602 userTimeout = connSynAck8->userTimeOut;
603 aliveTimeout = connSynAck8->aliveDelay;
605 for (int i = 0; i < DIR_NUM; i++)
607 dirNames.push_back((const char*)connSynAck8->dirName[i]);
610 if (pDirNameCb != NULL)
611 pDirNameCb(dirNames, dirNameCbData);
615 phaseTime = GetTickCount();
617 return CONN_SYN_ACK_N;
619 //---------------------------------------------------------------------------
620 int IA_CLIENT_PROT::Process_ALIVE_SYN_8(const char * buffer)
622 aliveSyn8 = (ALIVE_SYN_8*)buffer;
625 SwapBytes(aliveSyn8->len);
626 SwapBytes(aliveSyn8->rnd);
627 SwapBytes(aliveSyn8->cash);
628 SwapBytes(aliveSyn8->status);
629 for (int i = 0; i < DIR_NUM; ++i)
631 SwapBytes(aliveSyn8->mu[i]);
632 SwapBytes(aliveSyn8->md[i]);
633 SwapBytes(aliveSyn8->su[i]);
634 SwapBytes(aliveSyn8->sd[i]);
638 rnd = aliveSyn8->rnd;
639 memcpy(&stat, (char*)aliveSyn8->mu, sizeof(stat));
641 if (pStatChangedCb != NULL)
642 pStatChangedCb(stat, statChangedCbData);
644 if (pStatusChangedCb != NULL)
645 pStatusChangedCb(1, statusChangedCbData);
646 NetSend(ALIVE_ACK_N);
647 phaseTime = GetTickCount();
651 //---------------------------------------------------------------------------
652 int IA_CLIENT_PROT::Process_DISCONN_SYN_ACK_8(const char * buffer)
654 disconnSynAck8 = (DISCONN_SYN_ACK_8*)buffer;
657 SwapBytes(disconnSynAck8->len);
658 SwapBytes(disconnSynAck8->rnd);
661 rnd = disconnSynAck8->rnd;
663 NetSend(DISCONN_ACK_N);
665 phaseTime = GetTickCount();
667 return DISCONN_SYN_ACK_N;
669 //---------------------------------------------------------------------------
670 int IA_CLIENT_PROT::Process_FIN_8(const char *)
673 phaseTime = GetTickCount();
674 if (pStatusChangedCb != NULL)
675 pStatusChangedCb(0, statusChangedCbData);
679 //---------------------------------------------------------------------------
680 int IA_CLIENT_PROT::Process_INFO_8(const char * buffer)
682 info = (INFO_8*)buffer;
685 SwapBytes(info->len);
686 SwapBytes(info->sendTime);
690 pInfoCb((char*)info->text, info->infoType, info->showTime, info->sendTime, infoCbData);
693 //---------------------------------------------------------------------------
694 int IA_CLIENT_PROT::Process_ERROR(const char * buffer)
697 memcpy(&err, buffer, sizeof(err));
703 KOIToWin((const char*)err.text, &messageText);
704 if (pErrorCb != NULL)
705 pErrorCb(messageText, IA_SERVER_ERROR, errorCbData);
707 phaseTime = GetTickCount();
708 codeError = IA_SERVER_ERROR;
712 //---------------------------------------------------------------------------
713 int IA_CLIENT_PROT::Prepare_CONN_SYN_8(char * buffer)
715 connSyn8 = (CONN_SYN_8*)buffer;
718 SwapBytes(connSyn8->len);
721 assert(sizeof(CONN_SYN_8) == Min8(sizeof(CONN_SYN_8)) && "CONN_SYN_8 is not aligned to 8 bytes");
723 connSyn8->len = sizeof(CONN_SYN_8);
724 strncpy((char*)connSyn8->type, "CONN_SYN", IA_MAX_TYPE_LEN);
725 strncpy((char*)connSyn8->login, login.c_str(), IA_LOGIN_LEN);
727 for (int i = 0; i < DIR_NUM; i++)
729 connSyn8->dirs |= (selectedDirs[i] << i);
731 return connSyn8->len;
733 //---------------------------------------------------------------------------
734 int IA_CLIENT_PROT::Prepare_CONN_ACK_8(char * buffer)
736 connAck8 = (CONN_ACK_8*)buffer;
739 SwapBytes(connAck8->len);
740 SwapBytes(connAck8->rnd);
743 assert(sizeof(CONN_ACK_8) == Min8(sizeof(CONN_ACK_8)) && "CONN_ACK_8 is not aligned to 8 bytes");
745 connAck8->len = sizeof(CONN_ACK_8);
746 strncpy((char*)connAck8->loginS, login.c_str(), IA_LOGIN_LEN);
747 strncpy((char*)connAck8->type, "CONN_ACK", IA_MAX_TYPE_LEN);
751 return connAck8->len;
753 //---------------------------------------------------------------------------
754 int IA_CLIENT_PROT::Prepare_ALIVE_ACK_8(char * buffer)
756 aliveAck8 = (ALIVE_ACK_8*)buffer;
759 SwapBytes(aliveAck8->len);
760 SwapBytes(aliveAck8->rnd);
763 assert(Min8(sizeof(ALIVE_ACK_8)) == sizeof(ALIVE_ACK_8) && "ALIVE_ACK_8 is not aligned to 8 bytes");
765 aliveAck8 = (ALIVE_ACK_8*)buffer;
766 aliveAck8->len = sizeof(ALIVE_ACK_8);
767 strncpy((char*)aliveAck8->loginS, login.c_str(), IA_LOGIN_LEN);
768 strncpy((char*)aliveAck8->type, "ALIVE_ACK", IA_MAX_TYPE_LEN);
769 aliveAck8->rnd = ++rnd;
770 return aliveAck8->len;
772 //---------------------------------------------------------------------------
773 int IA_CLIENT_PROT::Prepare_DISCONN_SYN_8(char * buffer)
775 disconnSyn8 = (DISCONN_SYN_8*)buffer;
778 SwapBytes(disconnSyn8->len);
781 assert(Min8(sizeof(DISCONN_SYN_8)) == sizeof(DISCONN_SYN_8) && "DISCONN_SYN_8 is not aligned to 8 bytes");
783 disconnSyn8->len = sizeof(DISCONN_SYN_8);
784 strncpy((char*)disconnSyn8->loginS, login.c_str(), IA_LOGIN_LEN);
785 strncpy((char*)disconnSyn8->type, "DISCONN_SYN", IA_MAX_TYPE_LEN);
786 strncpy((char*)disconnSyn8->login, login.c_str(), IA_LOGIN_LEN);
787 return disconnSyn8->len;
789 //---------------------------------------------------------------------------
790 int IA_CLIENT_PROT::Prepare_DISCONN_ACK_8(char * buffer)
792 disconnAck8 = (DISCONN_ACK_8*)buffer;
795 SwapBytes(disconnAck8->len);
796 SwapBytes(disconnAck8->rnd);
799 assert(Min8(sizeof(DISCONN_ACK_8)) == sizeof(DISCONN_ACK_8) && "DISCONN_ACK_8 is not aligned to 8 bytes");
801 disconnAck8->len = Min8(sizeof(DISCONN_ACK_8));
802 disconnAck8->rnd = rnd + 1;
803 strncpy((char*)disconnAck8->loginS, login.c_str(), IA_LOGIN_LEN);
804 strncpy((char*)disconnAck8->type, "DISCONN_ACK", IA_MAX_TYPE_LEN);
805 return disconnAck8->len;
807 //---------------------------------------------------------------------------
808 void IA_CLIENT_PROT::SetStatusChangedCb(tpStatusChangedCb p, void * data)
810 pStatusChangedCb = p;
811 statusChangedCbData = data;
813 //---------------------------------------------------------------------------
814 void IA_CLIENT_PROT::SetStatChangedCb(tpStatChangedCb p, void * data)
817 statChangedCbData = data;
819 //---------------------------------------------------------------------------
820 void IA_CLIENT_PROT::SetInfoCb(tpCallBackInfoFn p, void * data)
825 //---------------------------------------------------------------------------
826 void IA_CLIENT_PROT::SetDirNameCb(tpCallBackDirNameFn p, void * data)
829 dirNameCbData = data;
831 //---------------------------------------------------------------------------
832 void IA_CLIENT_PROT::SetErrorCb(tpCallBackErrorFn p, void * data)
837 //---------------------------------------------------------------------------