00001 #include <time.h>
00002 #include "phupdate.h"
00003 #include "common/log.h"
00004 #include "common/blowfish.h"
00005
00006 #include "common/generate.h"
00007 #include "common/lutil.h"
00008
00009
00010 bool CUpdateBase::InitializeSockets()
00011 {
00012 DestroySockets();
00013 if (!m_tcpsocket.Create(0,SOCK_STREAM,phglobal.szBindAddress))
00014 {
00015 return false;
00016 }
00017
00018 if (!m_udpsocket.Create(0,SOCK_DGRAM,phglobal.szBindAddress))
00019 {
00020 return false;
00021 }
00022 return true;
00023 }
00024
00025 bool CUpdateBase::DestroySockets()
00026 {
00027 m_tcpsocket.Close();
00028 m_udpsocket.Close();
00029 return true;
00030 }
00031
00032 bool CUpdateBase::BeginKeepAlive()
00033 {
00034 if (!m_udpsocket.Connect(phglobal.szTcpConnectAddress,phglobal.nPort,&phglobal.nAddressIndex)) return false;
00035 phglobal.nLastResponseID = time(0);
00036 return true;
00037 }
00038
00039 bool CUpdateBase::SendKeepAlive(int opCode)
00040 {
00041 if (!phglobal.bTcpUpdateSuccessed) return false;
00042
00043 LOG(1) ("SendKeepAlive() %d\n",opCode);
00044
00045 DATA_KEEPALIVE data;
00046 memset(&data,0,sizeof(data));
00047 data.lChatID = phglobal.nChatID;
00048 data.lID = phglobal.nStartID;
00049 data.lOpCode = opCode;
00050 data.lSum = 0 - (data.lID + data.lOpCode);
00051 data.lReserved = 0;
00052
00053 CBlowfish bf;
00054 bf.SetKey((unsigned char*)phglobal.szChallenge,phglobal.nChallengeLen);
00055 char p1[KEEPALIVE_PACKET_LEN],p2[KEEPALIVE_PACKET_LEN];
00056 memcpy(p1,&data,KEEPALIVE_PACKET_LEN);
00057 memcpy(p2,&data,KEEPALIVE_PACKET_LEN);
00058 bf.EnCode(p1+4,p2+4,KEEPALIVE_PACKET_LEN-4);
00059 m_udpsocket.Send(p2,KEEPALIVE_PACKET_LEN,0);
00060
00061 return true;
00062 }
00063
00064 int CUpdateBase::RecvKeepaliveResponse()
00065 {
00066 if (!phglobal.bTcpUpdateSuccessed) return errorOccupyReconnect;
00067
00068
00069 if (m_udpsocket.DataReadable(0)<=0)
00070 {
00071 return okNoData;
00072 }
00073
00074
00075 char temp[100];
00076 DATA_KEEPALIVE_EXT rdata;
00077 if (m_udpsocket.Receive(temp,sizeof(temp),0)<=0) return okNoData;
00078 memcpy(&rdata, temp, sizeof(DATA_KEEPALIVE_EXT));
00079
00080 DATA_KEEPALIVE data = rdata.keepalive;
00081
00082 CBlowfish bf;
00083 bf.SetKey((unsigned char*)phglobal.szChallenge,phglobal.nChallengeLen);
00084 char p1[KEEPALIVE_PACKET_LEN],p2[KEEPALIVE_PACKET_LEN];
00085 memcpy(p1,&data,KEEPALIVE_PACKET_LEN);
00086 memcpy(p2,&data,KEEPALIVE_PACKET_LEN);
00087 bf.DeCode(p1+4,p2+4,KEEPALIVE_PACKET_LEN-4);
00088 memcpy(&data,p2,KEEPALIVE_PACKET_LEN);
00089 phglobal.nStartID = data.lID + 1;
00090
00091 LOG(1) (("RecvKeepaliveResponse() Data comes, OPCODE:%d\n"),data.lOpCode);
00092 if (data.lID - phglobal.nLastResponseID > 3 && phglobal.nLastResponseID != -1)
00093 {
00094 return errorOccupyReconnect;
00095 }
00096
00097 phglobal.nLastResponseID = data.lID;
00098 phglobal.tmLastResponse = time(0);
00099
00100 phglobal.ip = rdata.ip;
00101
00102 if (data.lOpCode == UDP_OPCODE_UPDATE_ERROR) return okServerER;
00103
00104
00105 return okKeepAliveRecved;
00106 }
00107
00108 int CUpdateBase::ExecuteUpdate()
00109 {
00110 char buffer[1024];
00111
00112 char username[128] = "";
00113 char key[128] = "";
00114 char sendbuffer[256];
00115
00116 char domains[255][255];
00117 char regicommand[255];
00118 int i,len, totaldomains;
00119 long challengetime = 0;
00120
00121
00122 LOG(1) ("ExecuteUpdate Connecting %s.\n",phglobal.szHost);
00123
00124 if (!m_tcpsocket.Connect(phglobal.szHost,phglobal.nPort,&phglobal.nAddressIndex,phglobal.szTcpConnectAddress))
00125 {
00126 LOG(1) ("ExecuteUpdate errorConnectFailed.\n");
00127 phglobal.nAddressIndex++;
00128 return errorConnectFailed;
00129 }
00131
00132 memset(buffer, 0, 128);
00133 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00134 if (len <=0 )
00135 {
00136 LOG(1) ("ExecuteUpdate Recv server hello string failed.\n");
00137 m_tcpsocket.Close();
00138 phglobal.nAddressIndex++;
00139 return errorConnectFailed;
00140 }
00141
00142 LOG(1) (("SEND AUTH REQUEST COMMAND..."));
00143 m_tcpsocket.Send((char*)COMMAND_AUTH,sizeof(COMMAND_AUTH),0);
00144 LOG(1) (("OK.\n"));
00145
00147
00148 memset(buffer, 0, 128);
00149 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00150 if (len <=0 )
00151 {
00152 LOG(1) (("ExecuteUpdate Recv server key string failed.\n"));
00153 m_tcpsocket.Close();
00154 return errorConnectFailed;
00155 }
00156 LOG(1) (("SERVER SIDE KEY \"%s\" RECEIVED.\n"),buffer);
00157
00158 phglobal.nChallengeLen = lutil_b64_pton(buffer+4, (unsigned char *)phglobal.szChallenge, 256);
00159
00160
00164
00165 len = GenerateCrypt(phglobal.szUserID, phglobal.szUserPWD, buffer+4, phglobal.clientinfo, phglobal.challengekey, sendbuffer);
00166 strcat(sendbuffer, "\r\n");
00167
00171
00173
00174 LOG(1) (("SEND AUTH DATA..."));
00175 m_tcpsocket.Send(sendbuffer,strlen(sendbuffer),0);
00176 LOG(1) (("OK\n"));
00177
00178 memset(buffer, 0, 128);
00179 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00180 buffer[3] = 0;
00181
00182 if (len <=0 )
00183 {
00184 LOG(1) (("ExecuteUpdate Recv server auth response failed.\n"));
00185 m_tcpsocket.Close();
00186
00187
00188 return errorConnectFailed;
00189 }
00190 if (strcmp(buffer,"250")!=0 && strcmp(buffer,"536")!=0)
00191 {
00192 LOG(1) ("CTcpThread::ExecuteUpdate auth failed.\n");
00193 m_tcpsocket.Close();
00194
00195 if (strstr(buffer + 4, "Busy.") != NULL) return errorAuthBusy;
00196 return errorAuthFailed;
00197 }
00198 if (strcmp(buffer,"536") == 0)
00199 {
00200 char *pos0 = strchr(buffer + 4, '<');
00201 if (pos0)
00202 {
00203 char *pos1 = strchr(pos0 + 1, '>');
00204 if (pos1)
00205 {
00206 *pos1 = '\0';
00207 strcpy(phglobal.szHost, pos0 + 1);
00208
00209 m_tcpsocket.Close();
00210 return okRedirecting;
00211 }
00212 }
00213 return errorAuthFailed;
00214 }
00215 if (strcmp(buffer,"250") == 0)
00216 {
00217 char *pos0 = strchr(buffer + 4, '<');
00218 if (pos0)
00219 {
00220 char *pos1 = strchr(pos0 + 1, '>');
00221 if (pos1)
00222 {
00223 *pos1 = '\0';
00224 phglobal.nUserType = atoi(pos0 + 1);
00225 }
00226 }
00227 }
00228
00230
00231 for (i=0,totaldomains=0;i<255;i++)
00232 {
00233 memset(domains[i], 0, 255);
00234 m_tcpsocket.ReadOneLine(domains[i],255);
00235 LOG(1) (("ExecuteUpdate domain \"%s\"\n"),domains[i]);
00236 totaldomains++;
00237 strcpy(phglobal.szActiveDomains[i],domains[i]);
00238 if (domains[i][0] == '.') break;
00239 }
00240 if (totaldomains<=0)
00241 {
00242 LOG(1) (("ExecuteUpdate Domain List Failed.\n"));
00243 m_tcpsocket.Close();
00244 return errorDomainListFailed;
00245 }
00246
00247 phglobal.cLastResult = okDomainListed;
00248 OnStatusChanged(phglobal.cLastResult, 0);
00249
00251
00252 for (i=0;;i++)
00253 {
00254 if (domains[i][0] == '.') break;
00255 memset(regicommand, 0, 128);
00256 strcpy(regicommand, COMMAND_REGI);
00257 strcat(regicommand, " ");
00258 strcat(regicommand, domains[i]);
00259 strcat(regicommand, "\r\n");
00260
00261 m_tcpsocket.Send(regicommand,strlen(regicommand),0);
00262 }
00263
00265
00266 LOG(1) (("SEND CNFM DATA..."));
00267 m_tcpsocket.Send((char*)COMMAND_CNFM,strlen(COMMAND_CNFM),0);
00268 LOG(1) (("OK\n"));
00269
00270 for (i=0;i<totaldomains-1;i++)
00271 {
00272 memset(buffer, 0, 128);
00273 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00274 if (len <= 0)
00275 {
00276 LOG(1) (("ExecuteUpdate Recv server confirm response failed.\n"));
00277 m_tcpsocket.Close();
00278 return errorDomainRegisterFailed;
00279 }
00280 LOG(1) (("ExecuteUpdate %s\n"),buffer);
00281 OnDomainRegistered(domains[i]);
00282 }
00283
00284 memset(buffer, 0, 128);
00285 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00286 if (len <= 0)
00287 {
00288 LOG(1) (("ExecuteUpdate Recv server confirmed chatID response failed.\n"));
00289 m_tcpsocket.Close();
00290 return errorDomainRegisterFailed;
00291 }
00292 LOG(1) (("%s\n"),buffer);
00293
00295
00296 char *chatid = buffer + 4;
00297 char *startid = NULL;
00298
00299 for (i=4;i<strlen(buffer);i++)
00300 {
00301 if (buffer[i] == ' ')
00302 {
00303 buffer[i] = 0;
00304 startid = buffer + i + 1;
00305 break;
00306 }
00307 }
00308 phglobal.nChatID = atoi(chatid);
00309 if (startid) phglobal.nStartID = atoi(startid);
00310 LOG(1) (("ExecuteUpdate nChatID:%d, nStartID:%d\n"),phglobal.nChatID,phglobal.nStartID);
00313
00314 m_tcpsocket.Send((void *)COMMAND_STAT_USER,sizeof(COMMAND_STAT_USER),0);
00315 memset(buffer, 0, 1024);
00316 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00317 buffer[3] = 0;
00318 if (len <= 0 || strcmp(buffer,"250")!=0)
00319 {
00320 LOG(1) ("CTcpThread::ExecuteUpdate Recv server confirmed stat user response failed.\n");
00321 m_tcpsocket.Close();
00322 return errorStatDetailInfoFailed;
00323 }
00324
00325 phglobal.szUserInfo = "";
00326 for (;;)
00327 {
00328 memset(buffer, 0, 1024);
00329 len = m_tcpsocket.ReadOneLine(buffer,1024);
00330 if (buffer[0] == '.' || len <= 0) break;
00331 phglobal.szUserInfo += buffer;
00332 }
00333 LOG(1) ("userinfo: \r\n%s\r\n", phglobal.szUserInfo.c_str());
00334
00335
00336 m_tcpsocket.Send((void *)COMMAND_STAT_DOM,sizeof(COMMAND_STAT_DOM),0);
00337 memset(buffer, 0, 1024);
00338 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00339 buffer[3] = 0;
00340 if (len <= 0 || strcmp(buffer,"250")!=0)
00341 {
00342 LOG(1) ("CTcpThread::ExecuteUpdate Recv server confirmed stat user response failed.\n");
00343 m_tcpsocket.Close();
00344 return errorStatDetailInfoFailed;
00345 }
00346
00347 phglobal.szDomainInfo = "";
00348 for (;;)
00349 {
00350 memset(buffer, 0, 1024);
00351 len = m_tcpsocket.ReadOneLine(buffer,1024);
00352 if (buffer[0] == '.' || len <= 0) break;
00353 phglobal.szDomainInfo += buffer;
00354 }
00355 LOG(1) ("domaininfo: \r\n%s\r\n", phglobal.szDomainInfo.c_str());
00356
00358
00359 LOG(1) (("SEND QUIT COMMAND..."));
00360 m_tcpsocket.Send((char*)COMMAND_QUIT,sizeof(COMMAND_QUIT),0);
00361 LOG(1) (("OK.\n"));
00362
00363 memset(buffer, 0, 128);
00364 len = m_tcpsocket.ReadOneLine(buffer,sizeof(buffer));
00365 if (len <= 0)
00366 {
00367 LOG(1) (("ExecuteUpdate Recv server goodbye response failed.\n"));
00368 m_tcpsocket.Close();
00369 return okDomainsRegistered;
00370 }
00371 LOG(1) (("%s\n"),buffer);
00372 m_tcpsocket.Close();
00373 return okDomainsRegistered;
00374 }
00375
00376 int CUpdateBase::step()
00377 {
00378 if (bNeed_connect)
00379 {
00380 strcpy(phglobal.szActiveDomains[0],".");
00381
00382 phglobal.cLastResult = okConnecting;
00383 OnStatusChanged(phglobal.cLastResult, 0);
00384
00385 if (!InitializeSockets())
00386 {
00387 LOG(1) ("InitializeSockets failed, waiting for 5 seconds to retry...\n");
00388 phglobal.cLastResult = errorConnectFailed;
00389 OnStatusChanged(phglobal.cLastResult, 0);
00390 return 5;
00391 }
00392
00393 int ret = ExecuteUpdate();
00394 phglobal.cLastResult = ret;
00395 OnStatusChanged(phglobal.cLastResult, ret == okDomainsRegistered ? phglobal.nUserType : 0);
00396 if (ret == okDomainsRegistered)
00397 {
00398 OnUserInfo(phglobal.szUserInfo);
00399 OnAccountDomainInfo(phglobal.szDomainInfo);
00400 LOG(1) ("ExecuteUpdate OK, BeginKeepAlive!\n");
00401 phglobal.bTcpUpdateSuccessed = true;
00402 phglobal.tmLastResponse = time(0);
00403 bNeed_connect = false;
00404 BeginKeepAlive();
00405 phglobal.lasttcptime = tmLastSend = time(0);
00406 }
00407 else
00408 {
00409 if (ret == okRedirecting)
00410 {
00411 phglobal.bTcpUpdateSuccessed = false;
00412 bNeed_connect = true;
00413 LOG(1) ("Need redirect, waiting for 5 seconds...\n");
00414 return 5;
00415 }
00416
00417 LOG(1) ("ExecuteUpdate failed, waiting for 30 seconds to retry...\n");
00418 return 30;
00419 }
00420 phglobal.nLastResponseID = -1;
00421 }
00422 else
00423 {
00424 if (time(0) - tmLastSend > (phglobal.nUserType >= 1 ? 30 : 60))
00425 {
00426 SendKeepAlive(UDP_OPCODE_UPDATE_VER2);
00427 tmLastSend = time(0);
00428 }
00429 int ret = RecvKeepaliveResponse();
00430 if (ret != okNormal && ret != okNoData) phglobal.cLastResult = ret;
00431 if (ret == errorOccupyReconnect)
00432 {
00433 LOG(1) ("RecvKeepaliveResponse failed, waiting for 30 seconds to reconnect...\n");
00434 bNeed_connect = true;
00435 phglobal.bTcpUpdateSuccessed = false;
00436 return 30;
00437 }
00438 else
00439 {
00440 if (ret == okKeepAliveRecved)
00441 {
00442 in_addr t;
00443 t.s_addr = phglobal.ip;
00444 LOG(1) ("Keepalive response received, client ip: %s\n",inet_ntoa(t));
00445 OnStatusChanged(phglobal.cLastResult, phglobal.ip);
00446 }
00447 }
00448 if (time(0) - phglobal.tmLastResponse > (phglobal.nUserType >= 1 ? 160 : 320) && phglobal.tmLastResponse != -1)
00449 {
00450 LOG(1) ("No response from server for %d seconds, reconnect immediately...\n", (phglobal.nUserType == 1 ? 160 : 320));
00451 phglobal.bTcpUpdateSuccessed = false;
00452 bNeed_connect = true;
00453 return 1;
00454 }
00455 }
00456 return 1;
00457 }
00458
00459 void CUpdateBase::stop()
00460 {
00461 SendKeepAlive(UDP_OPCODE_LOGOUT);
00462 tmLastSend = time(0);
00463 sleep(1);
00464 DestroySockets();
00465 }