#include "IPMsg.h" #include "path.h" #include //// time_t Time(void) { SYSTEMTIME st; _int64 ft; #define UNIXTIME_BASE ((_int64)0x019db1ded53e8000) ::GetLocalTime(&st); ::SystemTimeToFileTime(&st, (FILETIME *)&ft); return (time_t)((ft - UNIXTIME_BASE) / 10000000); } IPMsg::IPMsg(void) { pConfig = Configuration::GetInstance(); WSADATA wsaData; if (::WSAStartup(0x0101, &wsaData) != 0) throw WSAGetLastError(); if ((udp_skt = ::socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) throw WSAGetLastError(); if ((tcp_skt = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) throw WSAGetLastError(); default_port = 2425; SOCKADDR_IN addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(default_port); if (::bind(udp_skt, (LPSOCKADDR)&addr, sizeof(addr)) != 0) throw WSAGetLastError(); if (::bind(tcp_skt, (LPSOCKADDR)&addr, sizeof(addr)) != 0) { ::closesocket(tcp_skt); tcp_skt = INVALID_SOCKET; throw WSAGetLastError(); } /* BOOL flg = TRUE; // Non Block if (::ioctlsocket(udp_skt, FIONBIO, (unsigned long *)&flg) != 0) throw WSAGetLastError(); if ( ::ioctlsocket(tcp_skt, FIONBIO, (unsigned long *)&flg) != 0) throw WSAGetLastError(); */ BOOL flg = TRUE; // allow broadcast if (::setsockopt(udp_skt, SOL_SOCKET, SO_BROADCAST, (char *)&flg, sizeof(flg)) != 0) throw WSAGetLastError(); int buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2; // UDP Buffer if (::setsockopt(udp_skt, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(int)) != 0 && ::setsockopt(udp_skt, SOL_SOCKET, SO_SNDBUF, (char *)&buf_minsize, sizeof(int)) != 0) throw WSAGetLastError(); buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2; if (::setsockopt(udp_skt, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(int)) != 0 && ::setsockopt(udp_skt, SOL_SOCKET, SO_RCVBUF, (char *)&buf_minsize, sizeof(int)) != 0) throw WSAGetLastError(); flg = TRUE; // REUSE ADDR if (::setsockopt(tcp_skt, SOL_SOCKET, SO_REUSEADDR, (char *)&flg, sizeof(flg)) != 0) throw WSAGetLastError(); if ( ::listen(tcp_skt, 5) != 0) throw WSAGetLastError(); hostname = new char[MAX_BUF]; ::gethostname(hostname, MAX_BUF); _packetNo =(int) Time(); DWORD id; recv_thread_hwnd = ::CreateThread(NULL, 0, IPMsg::Recv_Thread, this, 0 , &id); listen_thread_hwnd = ::CreateThread(NULL, 0, IPMsg::Listen_Thread, this, 0, &id); } void IPMsg::CloseSocket(void) { if (udp_skt != INVALID_SOCKET) { ::closesocket(udp_skt); udp_skt = INVALID_SOCKET; } if (tcp_skt != INVALID_SOCKET) { ::closesocket(tcp_skt); tcp_skt = INVALID_SOCKET; } } void IPMsg::WSockTerm(void) { CloseSocket(); WSACleanup(); } IPMsg::~IPMsg(void) { //exit(); DWORD exitCode = 0; if (tcp_skt != INVALID_SOCKET) { ::closesocket(tcp_skt); tcp_skt = INVALID_SOCKET; } TerminateThread(this->Recv_Thread,exitCode); //WSockTerm(); //::SuspendThread(this->recv_thread); //::SuspendThread(this->listen_thread); //TerminateThread(this->listen_thread_hwnd,exitCode); //::Sleep(100); if (udp_skt != INVALID_SOCKET) { ::closesocket(udp_skt); udp_skt = INVALID_SOCKET; } delete[] hostname; WSACleanup(); } ULONG IPMsg::MakeMsg(char *buf, ULONG command, const char *msg, const char *exMsg, int *packet_len) { return this->MakeMsg(buf, ++ this->_packetNo, command, msg, exMsg, packet_len); } ULONG IPMsg::MakeMsg(char *buf, int _packetNo, ULONG command, const char *msg, const char *exMsg, int *packet_len) { W2A(pConfig->NickName(), sender); int len, ex_len = exMsg ? strlen(exMsg) + 1 : 0, max_len = MAX_UDPBUF; if (packet_len == NULL) packet_len = &len; *packet_len = sprintf_s(buf, MAX_UDPBUF, "%d:%ld:%s:%s:%ld:", IPMSG_VERSION, _packetNo, sender.c_str(), hostname, command); if (ex_len + *packet_len + 1 >= MAX_UDPBUF) ex_len = 0; max_len -= ex_len; if (msg != NULL) // sprintf *packet_len += LocalNewLineToUnix(msg, buf + *packet_len, max_len - *packet_len); (*packet_len)++; if (ex_len) { memcpy(buf + *packet_len, exMsg, ex_len); *packet_len += ex_len; } return _packetNo; } int IPMsg::LocalNewLineToUnix(const char *src, char *dest, int maxlen) { int len = 0; maxlen--; // while (*src != '\0' && len < maxlen) if ((dest[len] = *src++) != '\r') len++; dest[len] = 0; return len; } int IPMsg::UnixNewLineToLocal(const char *src, char *dest, int maxlen) { int len = 0; char *tmpbuf = NULL; if (src == dest) tmpbuf = _strdup(src), src = tmpbuf; maxlen--; // while (*src != '\0' && len < maxlen) { if ((dest[len] = *src++) == '\n') { dest[len++] = '\r'; if (len < maxlen) dest[len] = '\n'; } len++; } dest[len] = 0; if (tmpbuf) free(tmpbuf); return len; } void IPMsg::entry() { ULONG host = inet_addr("255.255.255.255"); SendCommand(host, IPMSG_M8 | IPMSG_BR_ENTRY); vector broadcastList; pConfig->GetBroadcastList(broadcastList); for( vector::iterator it = broadcastList.begin() ; it != broadcastList.end(); it ++) { host = inet_addr(it->c_str()); SendCommand(host, IPMSG_M8 | IPMSG_BR_ENTRY); } } void IPMsg::exit() { ULONG host = inet_addr("255.255.255.255"); SendCommand(host, IPMSG_BR_EXIT); vector broadcastList; pConfig->GetBroadcastList(broadcastList); for( vector::iterator it = broadcastList.begin() ; it != broadcastList.end(); it ++) { host = inet_addr(it->c_str()); SendCommand(host, IPMSG_BR_EXIT); } } int IPMsg::SendCommand(ULONG host , int port , int _packgeNo, ULONG command, const char* msg, const char* exMsg) { char buf[MAX_UDPBUF]; SOCKADDR_IN addrSvr; addrSvr.sin_family = AF_INET; addrSvr.sin_port = htons(port); addrSvr.sin_addr.S_un.S_addr = host; int buf_len = 0; this->MakeMsg(buf, command, msg, exMsg , &buf_len); if(!sendto(udp_skt,buf,buf_len,0,(sockaddr*) &addrSvr,sizeof(sockaddr))) { throw WSAGetLastError(); } return buf_len; } BOOL IPMsg::ResolveMsg(RecvBuf *buf, MsgBuf *msg) { char *exStr = NULL, *tok, *p; int len; if (buf->size > (len = strlen(buf->msgBuf)) +1) exStr = buf->msgBuf + len +1; msg->hostSub.addr = buf->addr.sin_addr.s_addr; msg->hostSub.portNo = buf->addr.sin_port; if ((tok = separate_token(buf->msgBuf, ':', &p)) == NULL) return FALSE; if ((msg->version = atoi(tok)) != IPMSG_VERSION) return FALSE; if ((tok = separate_token(NULL, ':', &p)) == NULL) return FALSE; msg->packetNo = atol(tok); if ((tok = separate_token(NULL, ':', &p)) == NULL) return FALSE; strncpy_s(msg->hostSub.userName,50, tok, sizeof(msg->hostSub.userName)); if ((tok = separate_token(NULL, ':', &p)) == NULL) return FALSE; strncpy_s(msg->hostSub.hostName,50, tok, sizeof(msg->hostSub.hostName)); if ((tok = separate_token(NULL, ':', &p)) == NULL) return FALSE; msg->command = atol(tok); int cnt = 0, ex_len; *msg->msgBuf = 0; if ((tok = separate_token(NULL, 0, &p)) != NULL) // { while (*tok != '\0' && cnt < MAX_UDPBUF -1) { if ((msg->msgBuf[cnt++] = *tok++) == '\n') { msg->msgBuf[cnt-1] = '\r'; if (cnt < MAX_UDPBUF -1) msg->msgBuf[cnt++] = '\n'; } } msg->msgBuf[cnt] = '\0'; } msg->exOffset = cnt; if (exStr && (ex_len = strlen(exStr) + 1) < MAX_UDPBUF -1) { if (++msg->exOffset + ex_len >= MAX_UDPBUF) msg->msgBuf[(msg->exOffset = MAX_UDPBUF - ex_len) -1] = '\0'; // exStr memcpy(msg->msgBuf + msg->exOffset, exStr, ex_len); } return TRUE; } BOOL IPMsg::Recv(MsgBuf *msg) { RecvBuf buf; UdpRecv(&buf); if ( buf.size == 0) return FALSE; return ResolveMsg(&buf, msg); } void IPMsg::UdpRecv(RecvBuf *buf) { buf->addrSize = sizeof(buf->addr); if ((buf->size = ::recvfrom(udp_skt, buf->msgBuf, MAX_UDPBUF, 0, (LPSOCKADDR)&(buf->addr), &(buf->addrSize))) == SOCKET_ERROR) throw ::WSAGetLastError(); buf->msgBuf[buf->size] = 0; } DWORD WINAPI IPMsg::Recv_Thread(LPVOID param) { IPMsg * ipMsg = (IPMsg *)param; while(true) { MsgBuf* pMsgBuf = new MsgBuf(); ipMsg->Recv(pMsgBuf); if(ipMsg->msgProcess != NULL) ipMsg->msgProcess->processMsg(pMsgBuf); else{ break; } } return 0; } DWORD WINAPI IPMsg::Listen_Thread(LPVOID param) { IPMsg * ipMsg = (IPMsg *)param; while(true) { SOCKET client = ::accept(ipMsg->tcp_skt, NULL, NULL); if (client != INVALID_SOCKET && client != SOCKET_ERROR) { Client* c = new Client; c->cltskt = client; c->ipMsg = ipMsg; DWORD threadId; ::CreateThread(NULL, 0, IPMsg::SendFile_Thread, c, 0, &threadId); }else{ break; } ::Sleep(100); } return 0; } DWORD WINAPI IPMsg::SendFile_Thread(LPVOID param) { Client* c = (Client*) param; IPMsg * ipMsg = c->ipMsg; RecvBuf* pRecvBuf = new RecvBuf; SOCKET client = c->cltskt; fd_set fdread; FD_ZERO(&fdread); FD_SET(client,&fdread); char request[MAX_BUF]; int offset = 0; /* bool readable = true; while(readable) { readable = select(NULL,&fdread,NULL,NULL,NULL) > 0 && FD_ISSET(client,&fread); if(readable) offset = ::recv(client, request+offset, MAX_BUF - offset, NULL); readable = readable && offset < MAX_BUF; } request[offset+1] = '\0'; */ offset = ::recv(client, request+offset, MAX_BUF - offset, NULL); request[offset+1] = '\0'; MsgBuf msgBuf; memset(pRecvBuf,0,sizeof(RecvBuf)); strcpy_s(pRecvBuf->msgBuf, sizeof(pRecvBuf->msgBuf) ,request); if(ipMsg->ResolveMsg( pRecvBuf, &msgBuf)) { if(msgBuf.command == IPMSG_GETFILEDATA) { char* pChar; for(pChar = msgBuf.msgBuf; *pChar != '\0' && *pChar != ':'; pChar ++ ); pChar++; int id = (int)::hex2ll(pChar); wstring fileName = ipMsg->fileMap[id]; ipMsg->DoSendFile(client,fileName); ipMsg->fileMap.erase(id); } else if ( msgBuf.command == IPMSG_GETDIRFILES) { char* pChar; for(pChar = msgBuf.msgBuf; *pChar != '\0' && *pChar != ':'; pChar ++ ); pChar++; int id = (int)::hex2ll(pChar); wstring fileName = ipMsg->fileMap[id]; ipMsg->DoSendDirectory(client,fileName); ipMsg->fileMap.erase(id); } } ::closesocket(client); delete pRecvBuf; delete c; return 0; } void IPMsg::DoSendDirectory (SOCKET s, wstring& dir) { /* *header-size:filename:file-size:fileattr[:extend-attr=val1[,val2...][:extend-attr2=...]]:contents-data */ char header[MAX_BUF] = {0}; char buf[MAX_BUF] = {0}; string fullpath; string name; W2A(dir, fullpath); GetFileName(fullpath, name); //step1. 发送目录头 int len = sprintf_s(buf, MAX_BUF, ":%s:0:%x", name.c_str(), IPMSG_FILE_DIR); len = sprintf_s(header, MAX_BUF, "%04x%s",len + 4, buf); SendTCP(s, header, len ); //step2: 遍历,发送目录内容 wstring findPath = dir; findPath += L"\\*"; WIN32_FIND_DATA dirData; HANDLE findHandle = FindFirstFile(findPath.c_str(), &dirData); if(findHandle != INVALID_HANDLE_VALUE) { //dirData DoProcessDirfileData(s, dir, dirData); while(FindNextFile(findHandle, &dirData)) { DoProcessDirfileData(s, dir, dirData); } FindClose(findHandle); } //step3: 发送"."目录头 len = sprintf_s(header, MAX_BUF, "08:.:0:%x", IPMSG_FILE_RETPARENT ); SendTCP(s, header, len); } void IPMsg::DoProcessDirfileData (SOCKET s, wstring& path, WIN32_FIND_DATA& dirData) { WCHAR wfullName[MAX_PATH]; wsprintf(wfullName,L"%s\\%s", path.c_str(), dirData.cFileName); wstring fullName = wfullName; if(dirData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { DoSendDirectory(s, fullName); } else { char header[MAX_BUF] = {0}; char buf[MAX_BUF] = {0}; string name; W2A(dirData.cFileName, name); int len = sprintf_s(buf, MAX_BUF, ":%s:%x%x:%x", name.c_str(), dirData.nFileSizeHigh, dirData.nFileSizeLow , IPMSG_FILE_REGULAR); len = sprintf_s(header, MAX_BUF, "%04x%s",len + 4, buf); SendTCP(s,header, len); DoSendFile(s, fullName); } } void IPMsg::DoSendFile(SOCKET s, wstring& fileName) { HANDLE fHandle = CreateFile(fileName.c_str(), GENERIC_READ,0, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); char* buf = new char[MAX_UDPBUF]; while(true) { buf[0] = '\0'; DWORD read; BOOL ret = ::ReadFile(fHandle,buf,MAX_UDPBUF , &read, NULL); if(read <= 0 || SendTCP(s,buf,read) <= 0 ) { break; } } ::CloseHandle(fHandle); delete[] buf; } int IPMsg::AddFileToSendList(wstring& fileName) { int size = fileMap.size(); fileMap[size] = fileName; return size; } int IPMsg::NotifyToSendFile( vector& fileList,HostSub &host ) { /* fileID:filename:size:mtime:fileattr[:extend-attr=val1 [,val2...][:extend-attr2=...]]:\a:fileID. */ int offset = 0; char exMsg[MAX_UDPBUF]; // char buf[MAX_UDPBUF]; for(unsigned int i=0;i < fileList.size(); i++) { wstring fileName = fileList[i]; int id = AddFileToSendList(fileName); const WCHAR* wFileName = fileName.c_str(); HANDLE fHand = ::CreateFile(wFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if(fHand != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION info; BOOL info_ret = ::GetFileInformationByHandle(fHand, &info); ::CloseHandle(fHand); /* int len = ::WideCharToMultiByte(CP_ACP, NULL, wFileName, fileName.size(), NULL, 0, NULL, NULL); char* fullPath = new char[len+1]; WideCharToMultiByte( CP_ACP, 0, wFileName, -1, fullPath,len, NULL,NULL ); fullPath[len] = '\0'; */ string fullPath; W2A(wFileName,fullPath); string fileName; GetFileName(fullPath, fileName); if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) offset += sprintf_s(exMsg + offset,MAX_UDPBUF - offset , "%x:%s:%x%x:%x:2\a",id, fileName.c_str(), info.nFileSizeHigh, info.nFileSizeLow, info.ftCreationTime); else offset += sprintf_s(exMsg + offset,MAX_UDPBUF - offset , "%x:%s:%x%x:%x:1\a",id, fileName.c_str(), info.nFileSizeHigh, info.nFileSizeLow, info.ftCreationTime); exMsg[offset] = '\0'; } } this->SendCommand(host.addr, IPMSG_NOOPERATION); ::Sleep(500); this->SendCommand(host.addr,IPMSG_SENDMSG | IPMSG_FILEATTACHOPT,"" ,exMsg); return 0; }