Ticket #758: Server.cpp

File Server.cpp, 31.4 KB (added by mbobka, 16 years ago)

Patched Server.cpp

Line 
1// FileZilla Server - a Windows ftp server
2
3// Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
4
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 2
8// of the License, or (at your option) any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19// Server.cpp: Implementierung der Klasse CServer.
20//
21//////////////////////////////////////////////////////////////////////
22
23#include "stdafx.h"
24#include "Server.h"
25#include "Options.h"
26#include "ServerThread.h"
27#include "ListenSocket.h"
28#include "AdminListenSocket.h"
29#include "AdminInterface.h"
30#include "AdminSocket.h"
31#include "Permissions.h"
32#include "FileLogger.h"
33#include "version.h"
34
35#ifndef MB_SERVICE_NOTIFICATION
36#define MB_SERVICE_NOTIFICATION 0x00040000L
37#endif
38
39//////////////////////////////////////////////////////////////////////
40// Konstruktion/Destruktion
41//////////////////////////////////////////////////////////////////////
42
43CServer::CServer()
44{
45 m_hWnd=0;
46 m_pOptions = NULL;
47 m_pAdminInterface = new CAdminInterface(this);
48 m_nServerState = 0;
49 m_bQuit = FALSE;
50
51 m_nSendCount = m_nRecvCount = 0;
52 m_nTimerID = 0;
53
54 // Since this thread has to handle notifications, increase it's priority
55 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
56}
57
58CServer::~CServer()
59{
60 for (std::list<CListenSocket*>::iterator iter = m_ListenSocketList.begin(); iter != m_ListenSocketList.end(); iter++)
61 delete *iter;
62 m_ListenSocketList.clear();
63
64 for (std::list<CAdminListenSocket*>::iterator adminIter = m_AdminListenSocketList.begin(); adminIter != m_AdminListenSocketList.end(); adminIter++)
65 delete *adminIter;
66 m_AdminListenSocketList.clear();
67
68 delete m_pAdminInterface;
69
70 delete m_pFileLogger;
71 delete m_pOptions;
72
73 //Destroy window
74 if (m_hWnd)
75 {
76 hMainWnd = 0;
77 DestroyWindow(m_hWnd);
78 m_hWnd=0;
79 }
80}
81
82bool CServer::Create()
83{
84 //Create window
85 WNDCLASSEX wndclass;
86 wndclass.cbSize=sizeof wndclass;
87 wndclass.style=0;
88 wndclass.lpfnWndProc=WindowProc;
89 wndclass.cbClsExtra=0;
90 wndclass.cbWndExtra=0;
91 wndclass.hInstance=GetModuleHandle(0);
92 wndclass.hIcon=0;
93 wndclass.hCursor=0;
94 wndclass.hbrBackground=0;
95 wndclass.lpszMenuName=0;
96 wndclass.lpszClassName=_T("FileZilla Server Helper Window");
97 wndclass.hIconSm=0;
98
99 RegisterClassEx(&wndclass);
100
101 m_hWnd = CreateWindow(_T("FileZilla Server Helper Window"), _T("FileZilla Server Helper Window"), 0, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(0));
102 if (!m_hWnd)
103 return false;
104 SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
105
106 hMainWnd = m_hWnd;
107
108 m_pOptions = new COptions;
109 m_pFileLogger = new CFileLogger(m_pOptions);
110
111 //Create the threads
112 int num = (int)m_pOptions->GetOptionVal(OPTION_THREADNUM);
113 for (int i = 0; i < num; i++)
114 {
115 int index = GetNextThreadNotificationID();
116 CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index);
117 m_ThreadNotificationIDs[index] = pThread;
118 if (pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED))
119 {
120 pThread->ResumeThread();
121 m_ThreadArray.push_back(pThread);
122 }
123 }
124
125 m_pFileLogger->Log(GetVersionString() + " started");
126 m_pFileLogger->Log("Initializing Server.");
127
128 m_nTimerID = SetTimer(m_hWnd, 1234, 10000, NULL);
129 ASSERT(m_nTimerID);
130
131 if (CreateListenSocket())
132 {
133 m_nServerState = 1;
134 ShowStatus("Server online.", 0);
135 }
136 else
137 ShowStatus("Server not online.", 1);
138
139 CreateAdminListenSocket();
140
141 return true;
142}
143
144HWND CServer::GetHwnd()
145{
146 return m_hWnd;
147}
148
149LRESULT CALLBACK CServer::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
150{
151 CServer *pServer=(CServer *)GetWindowLong(hWnd, GWL_USERDATA);
152
153 if (message == WM_CLOSE)
154 {
155 pServer->OnClose();
156 return 0;
157 }
158 else if (hWnd && message == WM_DESTROY)
159 {
160 ASSERT( hWnd == pServer->m_hWnd);
161 HANDLE *handle = new HANDLE[pServer->m_ThreadArray.size()];
162 unsigned int i = 0;
163 std::list<CServerThread *>::iterator iter;
164 for (iter = pServer->m_ThreadArray.begin(); iter != pServer->m_ThreadArray.end(); iter++, i++)
165 {
166 handle[i]=(*iter)->m_hThread;
167 (*iter)->PostThreadMessage(WM_QUIT, 0, 0);
168 }
169 for (i=0; i<pServer->m_ThreadArray.size(); i++)
170 {
171 int res=WaitForSingleObject(handle[i],INFINITE);
172 if (res==WAIT_FAILED)
173 res=GetLastError();
174 }
175 delete [] handle;
176 handle = new HANDLE[pServer->m_ClosedThreads.size()];
177 i=0;
178 for (iter = pServer->m_ClosedThreads.begin(); iter != pServer->m_ClosedThreads.end(); iter++, i++)
179 {
180 handle[i]=(*iter)->m_hThread;
181 (*iter)->PostThreadMessage(WM_QUIT, 0, 0);
182 }
183 for (i = 0; i < pServer->m_ClosedThreads.size(); i++)
184 {
185 int res=WaitForSingleObject(handle[i],INFINITE);
186 if (res==WAIT_FAILED)
187 res=GetLastError();
188 }
189 delete [] handle;
190 for (std::list<CAdminListenSocket*>::iterator iter2 = pServer->m_AdminListenSocketList.begin(); iter2!=pServer->m_AdminListenSocketList.end(); iter2++)
191 {
192 (*iter2)->Close();
193 delete *iter2;
194 }
195 pServer->m_AdminListenSocketList.clear();
196 delete pServer->m_pAdminInterface;
197 pServer->m_pAdminInterface = NULL;
198 delete pServer->m_pOptions;
199 pServer->m_pOptions = NULL;
200 if (pServer->m_nTimerID)
201 KillTimer(pServer->m_hWnd, pServer->m_nTimerID);
202 PostQuitMessage(0);
203 return 0;
204 }
205 else if ( message == WM_TIMER)
206 pServer->OnTimer(wParam);
207 else if (message >= WM_FILEZILLA_SERVERMSG)
208 {
209 int index = message - WM_FILEZILLA_SERVERMSG;
210 if (index < 0 || index >= pServer->m_ThreadNotificationIDs.size())
211 return 0;
212
213 CServerThread *pThread = pServer->m_ThreadNotificationIDs[index];
214 if (pThread)
215 {
216 std::list<CServerThread::t_Notification> notifications = pThread->GetNotifications();
217 for (std::list<CServerThread::t_Notification>::const_iterator iter = notifications.begin(); iter != notifications.end(); iter++)
218 if (pServer->OnServerMessage(pThread, iter->wParam, iter->lParam) != 0)
219 break;
220 }
221 return 0;
222 }
223
224 return ::DefWindowProc(hWnd, message, wParam, lParam);
225}
226
227LRESULT CServer::OnServerMessage(CServerThread* pThread, WPARAM wParam, LPARAM lParam)
228{
229 if (wParam == FSM_STATUSMESSAGE)
230 {
231 t_statusmsg *msg = reinterpret_cast<t_statusmsg *>(lParam);
232 if (!msg)
233 return 0;
234
235 CStdString str;
236
237 FILETIME fFileTime;
238 SystemTimeToFileTime(&msg->time, &fFileTime);
239
240 str.Format("(%06d)- %s (%s)> %s", msg->userid, (LPCTSTR)msg->user, (LPCTSTR)msg->ip, (LPCTSTR)msg->status);
241 ShowStatus(fFileTime.dwHighDateTime, fFileTime.dwLowDateTime, str, msg->type);
242 delete [] msg->user;
243 delete [] msg->status;
244 delete msg;
245 }
246 else if (wParam == FSM_CONNECTIONDATA)
247 {
248 t_connop *pConnOp = reinterpret_cast<t_connop*>(lParam);
249 if (!pConnOp)
250 return 0;
251 if (pConnOp->op != USERCONTROL_CONNOP_REMOVE)
252 m_UsersList[pConnOp->data->userid] = *pConnOp->data;
253 else
254 {
255// PATCH HERE
256// std::map<int, t_connectiondata>::iterator iter=m_UsersList.find(pConnOp->data->userid);
257// if (iter!=m_UsersList.end())
258// m_UsersList.erase(iter);
259 std::map<int, t_connectiondata>::iterator iter=m_UsersList.find(pConnOp->data->userid);
260 t_connectiondata* tmp = new t_connectiondata;
261 *tmp = iter->second;
262 if (iter!=m_UsersList.end())
263 m_UsersList.erase(iter);
264 delete pConnOp->data;
265 pConnOp->data = tmp;
266// END PATCH
267 }
268 USES_CONVERSION;
269 int userlen = pConnOp->data->user ? strlen(pConnOp->data->user) : 0;
270 int len = 2 + 4 + strlen(pConnOp->data->ip)+2 + 4 + userlen+2;
271 unsigned char *buffer = new unsigned char[len];
272 buffer[0] = USERCONTROL_CONNOP;
273 buffer[1] = pConnOp->op;
274 memcpy(buffer+2, &pConnOp->data->userid, 4);
275 buffer[2 + 4] = strlen(pConnOp->data->ip)/256;
276 buffer[2 + 4 + 1] = strlen(pConnOp->data->ip)%256;
277 memcpy(buffer + 2 + 4 + 2, T2CA(pConnOp->data->ip), strlen(T2CA(pConnOp->data->ip)));
278 memcpy(buffer + 2 + 4 +2 + strlen(pConnOp->data->ip)+2, &pConnOp->data->port, 4);
279 buffer[2 + 4 + strlen(pConnOp->data->ip)+2 + 4]= userlen/256;
280 buffer[2 + 4 + strlen(pConnOp->data->ip)+2 + 4 + 1]= userlen%256;
281 if (pConnOp->data->user)
282 memcpy(buffer + 2 + 4 + strlen(pConnOp->data->ip)+2 + 4 + 2, T2CA(pConnOp->data->user), userlen);
283 m_pAdminInterface->SendCommand(2, 3, buffer, len);
284 delete [] buffer;
285 delete pConnOp->data;
286 delete pConnOp;
287 }
288 else if (wParam == FSM_THREADCANQUIT)
289 {
290 std::list<CServerThread *>::iterator iter;
291 for (iter = m_ThreadArray.begin(); iter != m_ThreadArray.end(); iter++)
292 {
293 if (*iter == pThread)
294 {
295 HANDLE handle=pThread->m_hThread;
296 pThread->PostThreadMessage(WM_QUIT, 0, 0);
297 int res=WaitForSingleObject(handle, INFINITE);
298 if (res==WAIT_FAILED)
299 res=GetLastError();
300 m_ThreadArray.erase(iter);
301 FreeThreadNotificationID(pThread);
302 if (!m_ThreadArray.size() && !m_ClosedThreads.size())
303 {
304 if (!m_bQuit)
305 ShowStatus(_T("Server offline."), 1);
306 else
307 DestroyWindow(m_hWnd);
308 }
309 return -1;
310 }
311
312 }
313 for (iter = m_ClosedThreads.begin(); iter != m_ClosedThreads.end(); iter++)
314 {
315 if (*iter == pThread)
316 {
317 HANDLE handle = pThread->m_hThread;
318 pThread->PostThreadMessage(WM_QUIT, 0, 0);
319 int res = WaitForSingleObject(handle, INFINITE);
320 if (res == WAIT_FAILED)
321 res = GetLastError();
322 m_ClosedThreads.erase(iter);
323 FreeThreadNotificationID(pThread);
324 if (!m_ThreadArray.size() && !m_ClosedThreads.size())
325 {
326 if (!m_bQuit)
327 ShowStatus(_T("Server offline."), 1);
328 else
329 DestroyWindow(m_hWnd);
330 }
331 return -1;
332 }
333
334 }
335 }
336 else if (wParam == FSM_SEND)
337 {
338 char buffer[5];
339 buffer[0] = 1;
340 memcpy(buffer+1, &lParam, 4);
341 m_pAdminInterface->SendCommand(2, 7, buffer, 5);
342 m_nSendCount += lParam;
343 }
344 else if (wParam == FSM_RECV)
345 {
346 char buffer[5];
347 buffer[0] = 0;
348 memcpy(buffer+1, &lParam, 4);
349 m_pAdminInterface->SendCommand(2, 7, buffer, 5);
350 m_nRecvCount += lParam;
351 }
352 else if (wParam == FSM_RELOADCONFIG)
353 {
354 COptions options;
355 options.ReloadConfig();
356 CPermissions perm;
357 perm.ReloadConfig();
358 }
359 return 0;
360}
361
362
363void CServer::OnClose()
364{
365 for (std::list<CListenSocket*>::iterator listIter = m_ListenSocketList.begin(); listIter != m_ListenSocketList.end(); listIter++)
366 {
367 (*listIter)->Close();
368 delete *listIter;
369 }
370 m_ListenSocketList.clear();
371
372 m_bQuit = TRUE;
373
374 if (!m_ThreadArray.size() && !m_ClosedThreads.size())
375 {
376 DestroyWindow(m_hWnd);
377 return;
378 }
379
380 std::list<CServerThread *>::iterator iter;
381 for (iter = m_ThreadArray.begin(); iter != m_ThreadArray.end(); iter++)
382 {
383 VERIFY((*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 0));
384 }
385 for (iter = m_ClosedThreads.begin(); iter != m_ClosedThreads.end(); iter++)
386 {
387 VERIFY((*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 0));
388 }
389}
390
391BOOL CServer::ProcessCommand(CAdminSocket *pAdminSocket, int nID, unsigned char *pData, int nDataLength)
392{
393 switch (nID)
394 {
395 case 2:
396 if (!nDataLength)
397 {
398 unsigned char buffer[2];
399 buffer[0]=m_nServerState/256;
400 buffer[1]=m_nServerState%256;
401 pAdminSocket->SendCommand(1, 2, buffer, 2);
402 }
403 else if (nDataLength == 2)
404 {
405 ToggleActive(*pData*256+pData[1]);
406 unsigned char buffer[2];
407 buffer[0]=m_nServerState/256;
408 buffer[1]=m_nServerState%256;
409 pAdminSocket->SendCommand(1, 2, buffer, 2);
410 }
411 else
412 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1);
413 break;
414 case 3:
415 if (!nDataLength)
416 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1);
417 else if (*pData == USERCONTROL_GETLIST)
418 {
419 int len = 3;
420 std::map<int, t_connectiondata>::iterator iter;
421 for (iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
422 len += 4 + strlen(iter->second.ip)+2 + 4 + strlen(iter->second.user)+2;
423 unsigned char *buffer = new unsigned char[len];
424 buffer[0] = USERCONTROL_GETLIST;
425 buffer[1] = m_UsersList.size() / 256;
426 buffer[2] = m_UsersList.size() % 256;
427 unsigned char *p = buffer + 3;
428 for (iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
429 {
430 USES_CONVERSION;
431 memcpy(p, &iter->second.userid, 4);
432 p+=4;
433 *p++ = strlen(iter->second.ip) / 256;
434 *p++ = strlen(iter->second.ip) % 256;
435 memcpy(p, T2CA(iter->second.ip), strlen(T2CA(iter->second.ip)));
436 p+=strlen(T2CA(iter->second.ip));
437
438 memcpy(p, &iter->second.port, 4);
439 p+=4;
440
441 if (iter->second.user)
442 {
443 *p++ = strlen(iter->second.user) / 256;
444 *p++ = strlen(iter->second.user) % 256;
445 memcpy(p, T2CA(iter->second.user), strlen(T2CA(iter->second.user)));
446 p+=strlen(T2CA(iter->second.user));
447 }
448 else
449 {
450 *p++ = 0;
451 *p++ = 0;
452 }
453
454 }
455 m_pAdminInterface->SendCommand(1, 3, buffer, len);
456 delete [] buffer;
457 }
458 else if (*pData == USERCONTROL_KICK)
459 {
460 if (nDataLength != 5)
461 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1);
462 else
463 {
464 int nUserID;
465 memcpy(&nUserID, pData+1, 4);
466
467 std::map<int, t_connectiondata>::iterator iter = m_UsersList.find(nUserID);
468 if (iter!=m_UsersList.end())
469 {
470 t_controlmessage *msg=new t_controlmessage;
471 msg->command=USERCONTROL_KICK;
472 msg->socketid=nUserID;
473 iter->second.pThread->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_CONTROL, (LPARAM)msg);
474 char buffer[2];
475 buffer[0] = USERCONTROL_KICK;
476 buffer[1] = 0;
477 pAdminSocket->SendCommand(1, 3, &buffer, 2);
478 }
479 else
480 {
481 char buffer[2];
482 buffer[0] = USERCONTROL_KICK;
483 buffer[1] = 1;
484 pAdminSocket->SendCommand(1, 3, &buffer, 2);
485 }
486 }
487 }
488 else
489 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data", strlen("\001Protocol error: Invalid data")+1);
490 break;
491 case 5:
492 if (!nDataLength)
493 {
494 char *pBuffer = NULL;
495 DWORD nBufferLength = 0;
496 if (m_pOptions && m_pOptions->GetAsCommand(&pBuffer, &nBufferLength))
497 {
498 pAdminSocket->SendCommand(1, 5, pBuffer, nBufferLength);
499 delete [] pBuffer;
500 }
501 }
502 else if (m_pOptions)
503 {
504 if (nDataLength < 2)
505 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1);
506 else
507 {
508 int nListenPort = (int)m_pOptions->GetOptionVal(OPTION_SERVERPORT);
509 int nAdminListenPort = (int)m_pOptions->GetOptionVal(OPTION_ADMINPORT);
510 CStdString adminIpBindings = m_pOptions->GetOption(OPTION_ADMINIPBINDINGS);
511
512 SOCKADDR_IN sockAddr;
513 memset(&sockAddr, 0, sizeof(sockAddr));
514 int nSockAddrLen = sizeof(sockAddr);
515 BOOL bLocal = pAdminSocket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen) && sockAddr.sin_addr.S_un.S_addr == 0x0100007f;
516
517 if (!m_pOptions->ParseOptionsCommand(pData, nDataLength, bLocal))
518 {
519 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data, could not import settings.", strlen("\001Protocol error: Invalid data, could not import settings.")+1);
520 char buffer = 1;
521 pAdminSocket->SendCommand(1, 5, &buffer, 1);
522 break;
523 }
524
525 char buffer = 0;
526 pAdminSocket->SendCommand(1, 5, &buffer, 1);
527
528 unsigned int threadnum = (int)m_pOptions->GetOptionVal(OPTION_THREADNUM);
529 if (threadnum > m_ThreadArray.size())
530 {
531 int newthreads=threadnum-m_ThreadArray.size();
532 for (int i = 0; i < newthreads; i++)
533 {
534 int index = GetNextThreadNotificationID();
535 CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index);
536 m_ThreadNotificationIDs[index] = pThread;
537 if (pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED))
538 {
539 pThread->ResumeThread();
540 m_ThreadArray.push_back(pThread);
541 }
542 }
543 CStdString str;
544 str.Format("Number of threads increased to %d.", threadnum);
545 ShowStatus(str, 0);
546 }
547 else if (threadnum < m_ThreadArray.size())
548 {
549 CStdString str;
550 str.Format("Decreasing number of threads to %d.", threadnum);
551 ShowStatus(str, 0);
552 unsigned int i=0;
553 std::list<CServerThread *> newList;
554 for (std::list<CServerThread *>::iterator iter=m_ThreadArray.begin(); iter!=m_ThreadArray.end(); iter++,i++)
555 if (i>=threadnum)
556 {
557 (*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 2);
558 m_ClosedThreads.push_back(*iter);
559 }
560 else
561 newList.push_back(*iter);
562 m_ThreadArray.clear();
563 m_ThreadArray = newList;
564 }
565 if (nListenPort != m_pOptions->GetOptionVal(OPTION_SERVERPORT))
566 {
567 if (!m_ListenSocketList.empty())
568 {
569 CStdString str;
570 str.Format("Closing listen socket on port %d", nListenPort);
571 ShowStatus(str, 0);
572 for (std::list<CListenSocket*>::iterator listIter = m_ListenSocketList.begin(); listIter != m_ListenSocketList.end(); listIter++)
573 {
574 (*listIter)->Close();
575 delete *listIter;
576 }
577 m_ListenSocketList.clear();
578
579 if (!CreateListenSocket())
580 {
581 str.Format("Failed to create listen socket on port %I64d. Server is not online!", m_pOptions->GetOptionVal(OPTION_SERVERPORT));
582 ShowStatus(str,1);
583 m_nServerState = 0;
584 }
585 else
586 ShowStatus("Listen socket port changed",0);
587 }
588 }
589 if (nAdminListenPort != m_pOptions->GetOptionVal(OPTION_ADMINPORT) || adminIpBindings!=m_pOptions->GetOption(OPTION_ADMINIPBINDINGS))
590 {
591 if (nAdminListenPort == m_pOptions->GetOptionVal(OPTION_ADMINPORT))
592 {
593 for (std::list<CAdminListenSocket*>::iterator iter = m_AdminListenSocketList.begin(); iter!=m_AdminListenSocketList.end(); iter++)
594 {
595 (*iter)->Close();
596 delete *iter;
597 }
598 m_AdminListenSocketList.clear();
599 }
600 CAdminListenSocket *pSocket = new CAdminListenSocket(m_pAdminInterface);
601 if (!pSocket->Create((int)m_pOptions->GetOptionVal(OPTION_ADMINPORT), SOCK_STREAM, FD_ACCEPT, (m_pOptions->GetOption(OPTION_ADMINIPBINDINGS)!="*") ? _T("127.0.0.1") : NULL))
602 {
603 delete pSocket;
604 CStdString str;
605 str.Format(_T("Failed to change admin listen port to %I64d."), m_pOptions->GetOptionVal(OPTION_ADMINPORT));
606 m_pOptions->SetOption(OPTION_ADMINPORT, nAdminListenPort);
607 ShowStatus(str, 1);
608 }
609 else
610 {
611 pSocket->Listen();
612 for (std::list<CAdminListenSocket*>::iterator iter = m_AdminListenSocketList.begin(); iter!=m_AdminListenSocketList.end(); iter++)
613 {
614 (*iter)->Close();
615 delete *iter;
616 }
617 m_AdminListenSocketList.clear();
618
619 m_AdminListenSocketList.push_back(pSocket);
620 if (nAdminListenPort != m_pOptions->GetOptionVal(OPTION_ADMINPORT))
621 {
622 CStdString str;
623 str.Format(_T("Admin listen port changed to %I64d."), m_pOptions->GetOptionVal(OPTION_ADMINPORT));
624 ShowStatus(str, 0);
625 }
626
627 if (m_pOptions->GetOption(OPTION_ADMINIPBINDINGS) != "*")
628 {
629 BOOL bError = FALSE;
630 CStdString str = _T("Failed to bind the admin interface to the following IPs:");
631 CStdString ipBindings = m_pOptions->GetOption(OPTION_ADMINIPBINDINGS);
632
633 if (ipBindings != "")
634 ipBindings += " ";
635 while (ipBindings != "")
636 {
637 int pos = ipBindings.Find(" ");
638 if (pos == -1)
639 break;
640 CStdString ip = ipBindings.Left(pos);
641 ipBindings = ipBindings.Mid(pos+1);
642 CAdminListenSocket *pAdminListenSocket = new CAdminListenSocket(m_pAdminInterface);
643 if (!pAdminListenSocket->Create((int)m_pOptions->GetOptionVal(OPTION_ADMINPORT), SOCK_STREAM, FD_ACCEPT, ip) || !pAdminListenSocket->Listen())
644 {
645 bError = TRUE;
646 str += _T(" ") + ip;
647 delete pAdminListenSocket;
648 }
649 else
650 m_AdminListenSocketList.push_back(pAdminListenSocket);
651 }
652 if (bError)
653 ShowStatus(str, 1);
654 }
655 if (adminIpBindings!=m_pOptions->GetOption(OPTION_ADMINIPBINDINGS))
656 ShowStatus(_T("Admin interface IP bindings changed"), 0);
657 }
658
659 }
660 }
661 }
662 break;
663 case 6:
664 if (!nDataLength)
665 {
666 char *pBuffer = NULL;
667 DWORD nBufferLength = 0;
668 CPermissions permissions;
669 permissions.GetAsCommand(&pBuffer, &nBufferLength);
670 pAdminSocket->SendCommand(1, 6, pBuffer, nBufferLength);
671 delete [] pBuffer;
672 }
673 else
674 {
675 if (nDataLength < 2)
676 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1);
677 else
678 {
679 CPermissions permissions;
680 if (!permissions.ParseUsersCommand(pData, nDataLength))
681 {
682 pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data, could not import account settings.", strlen("\001Protocol error: Invalid data, could not import account settings.")+1);
683 char buffer = 1;
684 pAdminSocket->SendCommand(1, 6, &buffer, 1);
685 break;
686 }
687 char buffer = 0;
688 pAdminSocket->SendCommand(1, 6, &buffer, 1);
689 }
690 }
691 break;
692 case 8:
693 pAdminSocket->SendCommand(1, 8, NULL, 0);
694 break;
695 default:
696 {
697 CStdString str;
698 str.Format("\001Protocol error: Unknown command (%d).", nID);
699 pAdminSocket->SendCommand(1, 1, str.c_str(), str.GetLength());
700 }
701 break;
702 }
703
704 return TRUE;
705}
706
707BOOL CServer::ToggleActive(int nServerState)
708{
709 if (nServerState&2)
710 {
711 for (std::list<CListenSocket*>::iterator listenIter = m_ListenSocketList.begin(); listenIter != m_ListenSocketList.end(); listenIter++)
712 {
713 (*listenIter)->Close();
714 delete *listenIter;
715 }
716 m_ListenSocketList.clear();
717 for (std::list<CServerThread *>::iterator iter = m_ThreadArray.begin(); iter != m_ThreadArray.end(); iter++)
718 {
719 (*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 0);
720 m_ClosedThreads.push_back(*iter);
721 }
722 m_ThreadArray.clear();
723 if (m_nServerState & 1)
724 m_nServerState = m_nServerState |= 2;
725 }
726 else if (nServerState&4)
727 {
728 for (std::list<CListenSocket*>::iterator listenIter = m_ListenSocketList.begin(); listenIter != m_ListenSocketList.end(); listenIter++)
729 {
730 (*listenIter)->Close();
731 delete *listenIter;
732 }
733 for (std::list<CServerThread *>::iterator iter=m_ThreadArray.begin(); iter!=m_ThreadArray.end(); iter++)
734 {
735 (*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 2);
736 m_ClosedThreads.push_back(*iter);
737 }
738 m_ThreadArray.clear();
739
740 if (m_nServerState & 1)
741 m_nServerState = m_nServerState |= 4;
742 }
743 else if (nServerState&8)
744 {
745 for (std::list<CListenSocket*>::iterator listenIter = m_ListenSocketList.begin(); listenIter != m_ListenSocketList.end(); listenIter++)
746 {
747 (*listenIter)->Close();
748 delete *listenIter;
749 }
750 for (std::list<CServerThread *>::iterator iter=m_ThreadArray.begin(); iter!=m_ThreadArray.end(); iter++)
751 {
752 (*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 1);
753 m_ClosedThreads.push_back(*iter);
754 }
755 m_ThreadArray.clear();
756
757 if (m_nServerState & 1)
758 m_nServerState = m_nServerState |= 8;
759 }
760 else if (nServerState&1)
761 {
762 if (m_ListenSocketList.empty())
763 CreateListenSocket();
764
765 if (!m_ListenSocketList.empty())
766 {
767 ShowStatus("Server online", 0);
768 int i=0;
769 int num = (m_pOptions ? (int)m_pOptions->GetOptionVal(OPTION_THREADNUM) : 2);
770 for (std::list<CServerThread *>::iterator iter=m_ThreadArray.begin(); iter!=m_ThreadArray.end(); iter++, i++)
771 if (i<num)
772 (*iter)->DontQuit();
773 else
774 break;
775 //Recreate the threads
776 for (i = m_ThreadArray.size(); i < num; i++)
777 {
778 int index = GetNextThreadNotificationID();
779 CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index);
780 m_ThreadNotificationIDs[index] = pThread;
781 if (pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED))
782 {
783 pThread->ResumeThread();
784 m_ThreadArray.push_back(pThread);
785 }
786 }
787 }
788 for (std::list<CListenSocket *>::iterator iter = m_ListenSocketList.begin(); iter != m_ListenSocketList.end(); iter++)
789 (*iter)->m_bLocked = nServerState & 0x10;
790
791 m_nServerState = (m_ListenSocketList.empty() ? 0 : 1) + (nServerState & 16);
792 }
793 unsigned char buffer[2];
794 buffer[0] = m_nServerState / 256;
795 buffer[1] = m_nServerState % 256;
796 m_pAdminInterface->SendCommand(2, 2, buffer, 2);
797 return TRUE;
798}
799
800void CServer::ShowStatus(LPCTSTR msg, int nType)
801{
802 USES_CONVERSION;
803 LPCSTR str=T2CA(msg);
804 char *pBuffer=new char[strlen(str)+1];
805 *pBuffer=nType;
806 memcpy(pBuffer+1, str, strlen(str));
807 if (m_pAdminInterface)
808 m_pAdminInterface->SendCommand(2, 1, pBuffer, strlen(str)+1);
809 delete [] pBuffer;
810
811 if (m_pFileLogger)
812 m_pFileLogger->Log(msg);
813}
814
815void CServer::ShowStatus(DWORD eventDateHigh, DWORD eventDateLow, LPCTSTR msg, int nType)
816{
817 USES_CONVERSION;
818 LPCSTR str = T2CA(msg);
819 char *pBuffer = new char[strlen(str) + 1 + 8];
820 *pBuffer = nType;
821 memcpy(pBuffer + 1, &eventDateHigh, 8);
822 memcpy(pBuffer + 5, &eventDateLow, 4);
823 memcpy(pBuffer + 1 + 8, str, strlen(str));
824 if (m_pAdminInterface)
825 m_pAdminInterface->SendCommand(2, 4, pBuffer, strlen(str) + 1 + 8);
826 delete [] pBuffer;
827
828 //Log string
829 if (m_pFileLogger)
830 {
831 FILETIME fFileTime;
832 SYSTEMTIME sFileTime;
833 fFileTime.dwHighDateTime = eventDateHigh;
834 fFileTime.dwLowDateTime = eventDateLow;
835 FileTimeToSystemTime(&fFileTime, &sFileTime);
836 char text[80];
837 if (!GetDateFormat(
838 LOCALE_USER_DEFAULT, // locale for which date is to be formatted
839 DATE_SHORTDATE, // flags specifying function options
840 &sFileTime, // date to be formatted
841 0, // date format string
842 text, // buffer for storing formatted string
843 80 // size of buffer
844 ))
845 return;
846
847 CStdString text2=" ";
848 text2+=text;
849
850 if (!GetTimeFormat(
851 LOCALE_USER_DEFAULT, // locale for which date is to be formatted
852 TIME_FORCE24HOURFORMAT, // flags specifying function options
853 &sFileTime, // date to be formatted
854 0, // date format string
855 text, // buffer for storing formatted string
856 80 // size of buffer
857 ))
858 return;
859
860 text2 += " ";
861 text2 += text;
862 CStdString str = msg;
863 int pos = str.Find("-");
864 if (pos!=-1)
865 {
866 str.Insert(pos, text2 + " ");
867 }
868 m_pFileLogger->Log(str);
869 }
870}
871
872void CServer::OnTimer(UINT nIDEvent)
873{
874 m_pAdminInterface->CheckForTimeout();
875 m_pFileLogger->CheckLogFile();
876}
877
878BOOL CServer::CreateAdminListenSocket()
879{
880 CStdString ipBindings = (m_pOptions ? m_pOptions->GetOption(OPTION_ADMINIPBINDINGS) : "");
881 int nAdminPort = (m_pOptions ? (int)m_pOptions->GetOptionVal(OPTION_ADMINPORT) : 14147);
882 CAdminListenSocket *pAdminListenSocket = new CAdminListenSocket(m_pAdminInterface);
883 BOOL bError = FALSE;
884 if (!pAdminListenSocket->Create(nAdminPort, SOCK_STREAM, FD_ACCEPT, (ipBindings!="*") ? _T("127.0.0.1") : NULL))
885 {
886 CStdString str;
887 if (!pAdminListenSocket->Create(0, SOCK_STREAM, FD_ACCEPT, _T("127.0.0.1")))
888 {
889 delete pAdminListenSocket;
890 pAdminListenSocket = NULL;
891 str.Format(_T("Failed to create listen socket for admin interface on port %d, the admin interface has been disabled."), nAdminPort);
892 }
893 else
894 {
895 SOCKADDR_IN sockAddr;
896 memset(&sockAddr, 0, sizeof(sockAddr));
897 int nSockAddrLen = sizeof(sockAddr);
898 BOOL bResult = pAdminListenSocket->GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen);
899 if (bResult)
900 {
901 int nPort = ntohs(sockAddr.sin_port);
902 str.Format(_T("Failed to create listen socket for admin interface on port %d, for this session the admin interface is available on port %d."), nAdminPort, nPort);
903 nAdminPort = nPort;
904 }
905 else
906 {
907 delete pAdminListenSocket;
908 pAdminListenSocket = NULL;
909 str.Format(_T("Failed to create listen socket for admin interface on port %d, the admin interface has been disabled."), nAdminPort);
910 }
911 }
912 MessageBox(0, str, _T("FileZilla Server Error"), MB_ICONEXCLAMATION | MB_SERVICE_NOTIFICATION);
913 }
914 if (pAdminListenSocket)
915 {
916 VERIFY(pAdminListenSocket->Listen());
917 m_AdminListenSocketList.push_back(pAdminListenSocket);
918 }
919
920 if (!bError && ipBindings != "*")
921 {
922 BOOL bError = FALSE;
923 CStdString str = _T("Failed to bind the admin interface to the following IPs:");
924 if (ipBindings != "")
925 ipBindings += " ";
926 while (ipBindings != "")
927 {
928 int pos = ipBindings.Find(" ");
929 if (pos == -1)
930 break;
931 CStdString ip = ipBindings.Left(pos);
932 ipBindings = ipBindings.Mid(pos+1);
933 CAdminListenSocket *pAdminListenSocket = new CAdminListenSocket(m_pAdminInterface);
934 if (!pAdminListenSocket->Create(nAdminPort, SOCK_STREAM, FD_ACCEPT, ip) || !pAdminListenSocket->Listen())
935 {
936 delete pAdminListenSocket;
937 bError = TRUE;
938 str += _T("\n") + ip;
939 }
940 else
941 m_AdminListenSocketList.push_back(pAdminListenSocket);
942 }
943 if (bError)
944 MessageBox(0, str, _T("FileZilla Server Error"), MB_ICONEXCLAMATION | MB_SERVICE_NOTIFICATION);
945 }
946 return !m_AdminListenSocketList.empty();
947}
948
949BOOL CServer::CreateListenSocket()
950{
951 CStdString ipBindings = (m_pOptions ? m_pOptions->GetOption(OPTION_IPBINDINGS) : "");
952 int nPort = (m_pOptions ? (int)m_pOptions->GetOptionVal(OPTION_SERVERPORT) : 21);
953 CStdString str;
954 str.Format("Creating listen socket on port %d...", nPort);
955 ShowStatus(str, 0);
956 if (ipBindings == "*")
957 {
958 CListenSocket *pListenSocket = new CListenSocket(this);
959 pListenSocket->m_pThreadList = &m_ThreadArray;
960
961 if (!pListenSocket->Create(nPort, SOCK_STREAM, FD_ACCEPT, NULL) || !pListenSocket->Listen())
962 {
963 delete pListenSocket;
964 pListenSocket = NULL;
965 str.Format(_T("Failed to create listen socket on port %d"), nPort);
966 ShowStatus(str, 1);
967 }
968 else
969 m_ListenSocketList.push_back(pListenSocket);
970 }
971
972 if (ipBindings != "*")
973 {
974 BOOL bError = FALSE;
975 CStdString str = _T("Failed to bind the listen socket to the following IPs:");
976 if (ipBindings != "")
977 ipBindings += " ";
978 while (ipBindings != "")
979 {
980 int pos = ipBindings.Find(" ");
981 if (pos == -1)
982 break;
983 CStdString ip = ipBindings.Left(pos);
984 ipBindings = ipBindings.Mid(pos + 1);
985 CListenSocket *pListenSocket = new CListenSocket(this);
986 pListenSocket->m_pThreadList = &m_ThreadArray;
987 if (!pListenSocket->Create(nPort, SOCK_STREAM, FD_ACCEPT, ip) || !pListenSocket->Listen())
988 {
989 delete pListenSocket;
990 bError = TRUE;
991 str += _T(" ") + ip;
992 }
993 else
994 m_ListenSocketList.push_back(pListenSocket);
995 }
996 if (bError)
997 ShowStatus(str, 1);
998 }
999
1000 return !m_ListenSocketList.empty();
1001}
1002
1003int CServer::GetNextThreadNotificationID()
1004{
1005 for (int i = 0; i < m_ThreadNotificationIDs.size(); i++)
1006 if (!m_ThreadNotificationIDs[i])
1007 return i;
1008
1009 m_ThreadNotificationIDs.push_back(0);
1010 return m_ThreadNotificationIDs.size() - 1;
1011}
1012
1013void CServer::FreeThreadNotificationID(CServerThread *pThread)
1014{
1015 for (int i = 0; i < m_ThreadNotificationIDs.size(); i++)
1016 if (m_ThreadNotificationIDs[i] == pThread)
1017 {
1018 m_ThreadNotificationIDs[i] = 0;
1019 break;
1020 }
1021
1022}
1023
1024