[10134] MaNGOS 0.16 release.
[getmangos.git] / src / realmd / PatchHandler.cpp
blob0527c313c3075f0c3363ef264944532ab2110976
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /** \file
20 \ingroup realmd
23 #include "PatchHandler.h"
24 #include "AuthCodes.h"
25 #include "Log.h"
26 #include "Common.h"
28 #include <ace/OS_NS_sys_socket.h>
29 #include <ace/OS_NS_dirent.h>
30 #include <ace/OS_NS_errno.h>
31 #include <ace/OS_NS_unistd.h>
33 #include <ace/os_include/netinet/os_tcp.h>
35 #ifndef MSG_NOSIGNAL
36 #define MSG_NOSIGNAL 0
37 #endif
39 #if defined( __GNUC__ )
40 #pragma pack(1)
41 #else
42 #pragma pack(push,1)
43 #endif
45 struct Chunk
47 ACE_UINT8 cmd;
48 ACE_UINT16 data_size;
49 ACE_UINT8 data[4096]; // 4096 - page size on most arch
52 #if defined( __GNUC__ )
53 #pragma pack()
54 #else
55 #pragma pack(pop)
56 #endif
58 PatchHandler::PatchHandler(ACE_HANDLE socket, ACE_HANDLE patch)
60 reactor(NULL);
61 set_handle(socket);
62 patch_fd_ = patch;
65 PatchHandler::~PatchHandler()
67 if(patch_fd_ != ACE_INVALID_HANDLE)
68 ACE_OS::close(patch_fd_);
71 int PatchHandler::open(void*)
73 if(get_handle() == ACE_INVALID_HANDLE || patch_fd_ == ACE_INVALID_HANDLE)
74 return -1;
76 int nodelay = 0;
77 if (-1 == peer().set_option(ACE_IPPROTO_TCP,
78 TCP_NODELAY,
79 &nodelay,
80 sizeof(nodelay)))
82 return -1;
85 #if defined(TCP_CORK)
86 int cork = 1;
87 if (-1 == peer().set_option(ACE_IPPROTO_TCP,
88 TCP_CORK,
89 &cork,
90 sizeof(cork)))
92 return -1;
94 #endif //TCP_CORK
96 (void) peer().disable(ACE_NONBLOCK);
98 return activate(THR_NEW_LWP | THR_DETACHED | THR_INHERIT_SCHED);
101 int PatchHandler::svc(void)
103 // Do 1 second sleep, similar to the one in game/WorldSocket.cpp
104 // Seems client have problems with too fast sends.
105 ACE_OS::sleep(1);
107 int flags = MSG_NOSIGNAL;
109 Chunk data;
110 data.cmd = XFER_DATA;
112 ssize_t r;
114 while((r = ACE_OS::read(patch_fd_, data.data, sizeof(data.data))) > 0)
116 data.data_size = (ACE_UINT16)r;
118 if(peer().send((const char*)&data,
119 ((size_t) r) + sizeof(data) - sizeof(data.data),
120 flags) == -1)
122 return -1;
126 if(r == -1)
128 return -1;
131 return 0;
134 PatchCache::~PatchCache()
136 for (Patches::iterator i = patches_.begin (); i != patches_.end (); i++)
137 delete i->second;
140 PatchCache::PatchCache()
142 LoadPatchesInfo();
145 PatchCache* PatchCache::instance()
147 return ACE_Singleton<PatchCache, ACE_Thread_Mutex>::instance();
150 void PatchCache::LoadPatchMD5(const char* szFileName)
152 // Try to open the patch file
153 std::string path = "./patches/";
154 path += szFileName;
155 FILE * pPatch = fopen(path.c_str (), "rb");
156 sLog.outDebug("Loading patch info from %s", path.c_str());
158 if(!pPatch)
159 return;
161 // Calculate the MD5 hash
162 MD5_CTX ctx;
163 MD5_Init(&ctx);
165 const size_t check_chunk_size = 4*1024;
167 ACE_UINT8 buf[check_chunk_size];
169 while(!feof (pPatch))
171 size_t read = fread(buf, 1, check_chunk_size, pPatch);
172 MD5_Update(&ctx, buf, read);
175 fclose(pPatch);
177 // Store the result in the internal patch hash map
178 patches_[path] = new PATCH_INFO;
179 MD5_Final((ACE_UINT8 *) & patches_[path]->md5, &ctx);
182 bool PatchCache::GetHash(const char * pat, ACE_UINT8 mymd5[MD5_DIGEST_LENGTH])
184 for (Patches::iterator i = patches_.begin (); i != patches_.end (); i++)
185 if (!stricmp(pat, i->first.c_str ()))
187 memcpy(mymd5, i->second->md5, MD5_DIGEST_LENGTH);
188 return true;
191 return false;
194 void PatchCache::LoadPatchesInfo()
196 ACE_DIR* dirp = ACE_OS::opendir(ACE_TEXT("./patches/"));
198 if(!dirp)
199 return;
201 ACE_DIRENT* dp;
203 while((dp = ACE_OS::readdir(dirp)) != NULL)
205 int l = strlen(dp->d_name);
206 if (l < 8)
207 continue;
209 if(!memcmp(&dp->d_name[l - 4], ".mpq", 4))
210 LoadPatchMD5(dp->d_name);
213 ACE_OS::closedir(dirp);