Updated Copyright year to 2013
[getmangos.git] / src / mangosd / RASocket.cpp
blob4142233cf0ec750fdabb7c2023eab77d0e0662ca
1 /*
2 * Copyright (C) 2005-2013 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 mangosd
23 #include "Common.h"
24 #include "Database/DatabaseEnv.h"
25 #include "Log.h"
26 #include "RASocket.h"
27 #include "World.h"
28 #include "Config/Config.h"
29 #include "Util.h"
30 #include "AccountMgr.h"
31 #include "Language.h"
32 #include "ObjectMgr.h"
34 /// RASocket constructor
35 RASocket::RASocket()
36 : RAHandler(),
37 pendingCommands(0, USYNC_THREAD, "pendingCommands"),
38 outActive(false),
39 inputBufferLen(0),
40 outputBufferLen(0),
41 stage(NONE)
43 ///- Get the config parameters
44 bSecure = sConfig.GetBoolDefault("RA.Secure", true);
45 bStricted = sConfig.GetBoolDefault("RA.Stricted", false);
46 iMinLevel = AccountTypes(sConfig.GetIntDefault("RA.MinLevel", SEC_ADMINISTRATOR));
47 reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
50 /// RASocket destructor
51 RASocket::~RASocket()
53 peer().close();
54 sLog.outRALog("Connection was closed.");
57 /// Accept an incoming connection
58 int RASocket::open(void*)
60 if (reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
62 sLog.outError("RASocket::open: unable to register client handler errno = %s", ACE_OS::strerror(errno));
63 return -1;
66 ACE_INET_Addr remote_addr;
68 if (peer().get_remote_addr(remote_addr) == -1)
70 sLog.outError("RASocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror(errno));
71 return -1;
75 sLog.outRALog("Incoming connection from %s.", remote_addr.get_host_addr());
77 ///- print Motd
78 sendf(sWorld.GetMotd());
79 sendf("\r\n");
80 sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER));
82 return 0;
85 int RASocket::close(int)
87 if (closing_)
88 return -1;
89 DEBUG_LOG("RASocket::close");
90 shutdown();
92 closing_ = true;
94 remove_reference();
95 return 0;
98 int RASocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask)
100 if (closing_)
101 return -1;
102 DEBUG_LOG("RASocket::handle_close");
103 ACE_GUARD_RETURN(ACE_Thread_Mutex, Guard, outBufferLock, -1);
105 closing_ = true;
107 if (h == ACE_INVALID_HANDLE)
108 peer().close_writer();
109 remove_reference();
110 return 0;
113 int RASocket::handle_output(ACE_HANDLE)
115 ACE_GUARD_RETURN(ACE_Thread_Mutex, Guard, outBufferLock, -1);
117 if (closing_)
118 return -1;
120 if (!outputBufferLen)
122 if (reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1)
124 sLog.outError("RASocket::handle_output: error while cancel_wakeup");
125 return -1;
127 outActive = false;
128 return 0;
130 #ifdef MSG_NOSIGNAL
131 ssize_t n = peer().send(outputBuffer, outputBufferLen, MSG_NOSIGNAL);
132 #else
133 ssize_t n = peer().send(outputBuffer, outputBufferLen);
134 #endif // MSG_NOSIGNAL
136 if (n <= 0)
137 return -1;
139 ACE_OS::memmove(outputBuffer, outputBuffer + n, outputBufferLen - n);
141 outputBufferLen -= n;
143 return 0;
146 /// Read data from the network
147 int RASocket::handle_input(ACE_HANDLE)
149 DEBUG_LOG("RASocket::handle_input");
150 if (closing_)
152 sLog.outError("Called RASocket::handle_input with closing_ = true");
153 return -1;
156 size_t readBytes = peer().recv(inputBuffer + inputBufferLen, RA_BUFF_SIZE - inputBufferLen - 1);
158 if (readBytes <= 0)
160 DEBUG_LOG("read " SIZEFMTD " bytes in RASocket::handle_input", readBytes);
161 return -1;
164 ///- Discard data after line break or line feed
165 bool gotenter = false;
166 for (; readBytes > 0 ; --readBytes)
168 char c = inputBuffer[inputBufferLen];
169 if (c == '\r' || c == '\n')
171 gotenter = true;
172 break;
174 ++inputBufferLen;
177 if (gotenter)
179 inputBuffer[inputBufferLen] = 0;
180 inputBufferLen = 0;
181 switch (stage)
183 /// <ul> <li> If the input is '<username>'
184 case NONE:
186 std::string szLogin = inputBuffer;
188 accId = sAccountMgr.GetId(szLogin);
190 ///- If the user is not found, deny access
191 if (!accId)
193 sendf("-No such user.\r\n");
194 sLog.outRALog("User %s does not exist.", szLogin.c_str());
195 if (bSecure)
197 handle_output();
198 return -1;
200 sendf("\r\n");
201 sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER));
202 break;
205 accAccessLevel = sAccountMgr.GetSecurity(accId);
207 ///- if gmlevel is too low, deny access
208 if (accAccessLevel < iMinLevel)
210 sendf("-Not enough privileges.\r\n");
211 sLog.outRALog("User %s has no privilege.", szLogin.c_str());
212 if (bSecure)
214 handle_output();
215 return -1;
217 sendf("\r\n");
218 sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER));
219 break;
222 ///- allow by remotely connected admin use console level commands dependent from config setting
223 if (accAccessLevel >= SEC_ADMINISTRATOR && !bStricted)
224 accAccessLevel = SEC_CONSOLE;
226 stage = LG;
227 sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_PASS));
228 break;
230 ///<li> If the input is '<password>' (and the user already gave his username)
231 case LG:
233 // login+pass ok
234 std::string pw = inputBuffer;
236 if (sAccountMgr.CheckPassword(accId, pw))
238 stage = OK;
240 sendf("+Logged in.\r\n");
241 sLog.outRALog("User account %u has logged in.", accId);
242 sendf("mangos>");
244 else
246 ///- Else deny access
247 sendf("-Wrong pass.\r\n");
248 sLog.outRALog("User account %u has failed to log in.", accId);
249 if (bSecure)
251 handle_output();
252 return -1;
254 sendf("\r\n");
255 sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_PASS));
257 break;
259 ///<li> If user is logged, parse and execute the command
260 case OK:
261 if (strlen(inputBuffer))
263 sLog.outRALog("Got '%s' cmd.", inputBuffer);
264 if (strncmp(inputBuffer, "quit", 4) == 0)
265 return -1;
266 else
268 CliCommandHolder* cmd = new CliCommandHolder(accId, accAccessLevel, this, inputBuffer, &RASocket::zprint, &RASocket::commandFinished);
269 sWorld.QueueCliCommand(cmd);
270 pendingCommands.acquire();
273 else
274 sendf("mangos>");
275 break;
276 ///</ul>
280 // no enter yet? wait for next input...
281 return 0;
284 /// Output function
285 void RASocket::zprint(void* callbackArg, const char* szText)
287 if (!szText)
288 return;
290 ((RASocket*)callbackArg)->sendf(szText);
293 void RASocket::commandFinished(void* callbackArg, bool success)
295 RASocket* raSocket = (RASocket*)callbackArg;
296 raSocket->sendf("mangos>");
297 raSocket->pendingCommands.release();
300 int RASocket::sendf(const char* msg)
302 ACE_GUARD_RETURN(ACE_Thread_Mutex, Guard, outBufferLock, -1);
304 if (closing_)
305 return -1;
307 int msgLen = strlen(msg);
309 if (msgLen + outputBufferLen > RA_BUFF_SIZE)
310 return -1;
312 ACE_OS::memcpy(outputBuffer + outputBufferLen, msg, msgLen);
313 outputBufferLen += msgLen;
315 if (!outActive)
317 if (reactor()->schedule_wakeup
318 (this, ACE_Event_Handler::WRITE_MASK) == -1)
320 sLog.outError("RASocket::sendf error while schedule_wakeup");
321 return -1;
323 outActive = true;
325 return 0;