|
1 // Server.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include "Misc.h" |
|
14 #include "stdafx.h" |
|
15 #include "console_host.h" |
|
16 #include "Server.h" |
|
17 #include "ConsoleWindow.h" |
|
18 #include "RemoteConsole.h" |
|
19 |
|
20 const int KMajorVersion = 1; |
|
21 const int KServerInitParam = ID_RC_CLOSE - 1; |
|
22 static CServer* sServer = NULL; |
|
23 LPCTSTR KServerWindowClassName = TEXT("ServerWindowClass"); |
|
24 LPCTSTR KServerConsoleName = TEXT("Server Console"); |
|
25 LPCTSTR KServerSocketName = TEXT("Server Socket"); |
|
26 |
|
27 |
|
28 class TCreateConsoleWindowPacket |
|
29 { |
|
30 public: |
|
31 void Validate() const; |
|
32 public: |
|
33 int iMajorVersion; |
|
34 int iMinorVersion; |
|
35 int iWidth; |
|
36 int iHeight; |
|
37 int iTitleLength; |
|
38 }; |
|
39 |
|
40 void TCreateConsoleWindowPacket::Validate() const |
|
41 { |
|
42 if (iMajorVersion > KMajorVersion) |
|
43 { |
|
44 throw KExceptionInvalidClientVersion; |
|
45 } |
|
46 } |
|
47 |
|
48 |
|
49 CServer* CServer::New(HINSTANCE aAppHandle) |
|
50 { |
|
51 std::auto_ptr<CServer> self(new(EThrow) CServer(aAppHandle)); |
|
52 self->Construct(); |
|
53 return self.release(); |
|
54 } |
|
55 |
|
56 CServer::~CServer() |
|
57 { |
|
58 delete iSocket; |
|
59 delete iConsole; |
|
60 } |
|
61 |
|
62 void CServer::HandleException(TException aException) |
|
63 { |
|
64 switch (aException) |
|
65 { |
|
66 case KExceptionNoMemory: |
|
67 iConsole->Write(TEXT("Out of memory\r\n")); |
|
68 break; |
|
69 case KExceptionWindowConstructFailed: |
|
70 iConsole->Write(TEXT("Failed to construct new window\r\n")); |
|
71 break; |
|
72 case KExceptionConsoleWindowConstructFailed: |
|
73 iConsole->Write(TEXT("Failed to construct new console window\r\n")); |
|
74 break; |
|
75 case KExceptionSocketConstructFailed: |
|
76 iConsole->Write(TEXT("Failed to construct new socket\r\n")); |
|
77 break; |
|
78 case KExceptionSocketBindFailed: |
|
79 iConsole->Write(TEXT("Failed to bind server socket. Is something else already listening on that port?\r\n")); |
|
80 break; |
|
81 case KExceptionSocketListenFailed: |
|
82 iConsole->Write(TEXT("Failed to listen on server socket\r\n")); |
|
83 break; |
|
84 case KExceptionSocketSelectFailed: |
|
85 iConsole->Write(TEXT("Failed to asynchronously wait on socket\r\n")); |
|
86 break; |
|
87 case KExceptionSocketAcceptFailed: |
|
88 iConsole->Write(TEXT("Failed to accept to client connection\r\n")); |
|
89 break; |
|
90 case KExceptionSocketReadFailed: |
|
91 iConsole->Write(TEXT("Failed to read from socket\r\n")); |
|
92 break; |
|
93 case KExceptionInvalidClientVersion: |
|
94 iConsole->Write(TEXT("Invalid client version\r\n")); |
|
95 break; |
|
96 case KExceptionFailedToWritePrefsFile: |
|
97 iConsole->Write(TEXT("Failed to write preferences file\r\n")); |
|
98 break; |
|
99 default: |
|
100 iConsole->Write(TEXT("Unknown error\r\n")); |
|
101 break; |
|
102 } |
|
103 } |
|
104 |
|
105 TPreferences& CServer::Preferences() |
|
106 { |
|
107 return iPreferences; |
|
108 } |
|
109 |
|
110 const TPreferences& CServer::Preferences() const |
|
111 { |
|
112 return iPreferences; |
|
113 } |
|
114 |
|
115 CServer::CServer(HINSTANCE aAppHandle) : iAppHandle(aAppHandle), iSocket(NULL), iConsole(NULL), iPort(0) |
|
116 { |
|
117 sServer = this; |
|
118 } |
|
119 |
|
120 void CServer::Construct() |
|
121 { |
|
122 WNDCLASSEX wcex; |
|
123 wcex.cbSize = sizeof(WNDCLASSEX); |
|
124 wcex.style = CS_HREDRAW | CS_VREDRAW; |
|
125 wcex.lpfnWndProc = (WNDPROC)CWindow::HandleMessage; |
|
126 wcex.cbClsExtra = 0; |
|
127 wcex.cbWndExtra = 0; |
|
128 wcex.hInstance = iAppHandle; |
|
129 wcex.hIcon = LoadIcon(iAppHandle, (LPCTSTR)IDI_CONSOLE_HOST); |
|
130 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); |
|
131 wcex.hbrBackground = NULL; |
|
132 wcex.lpszMenuName = (LPCTSTR)ID_SERVER_MENU; |
|
133 wcex.lpszClassName = KServerWindowClassName; |
|
134 wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); |
|
135 if (RegisterClassEx(&wcex) == 0) |
|
136 { |
|
137 throw KExceptionWindowClassRegistrationFailed; |
|
138 } |
|
139 |
|
140 iConsole = CConsoleWindow::New(iAppHandle, KServerWindowClassName, TEXT("Remote Console Server"), CW_USEDEFAULT, CW_USEDEFAULT, 40, 20, 20, this, NULL, TRUE); |
|
141 iConsole->SetName(KServerConsoleName); |
|
142 |
|
143 try |
|
144 { |
|
145 iPreferences.Read(); |
|
146 } |
|
147 catch (...) |
|
148 { |
|
149 iConsole->Write(TEXT("Unable to read preferences")); |
|
150 } |
|
151 |
|
152 iSocket = CServerSocket::New(*iConsole); |
|
153 iSocket->SetName(KServerSocketName); |
|
154 PostMessage(iConsole->Handle(), WM_COMMAND, KServerInitParam, 0); |
|
155 } |
|
156 |
|
157 void CServer::Listen() |
|
158 { |
|
159 if (iPort != iPreferences.ServerPort()) |
|
160 { |
|
161 delete iSocket; |
|
162 iSocket = CServerSocket::New(*iConsole); |
|
163 iSocket->SetName(KServerSocketName); |
|
164 iSocket->Listen(iPreferences.ServerPort(), 5, *this); |
|
165 iConsole->WriteFormat(TEXT("Listening on port %d\r\n"), iPreferences.ServerPort()); |
|
166 iPort = iPreferences.ServerPort(); |
|
167 } |
|
168 } |
|
169 |
|
170 void CServer::HandleNewClient(CClientSocket& aClientSocket) |
|
171 { |
|
172 CSocketCommandReader* commandReader = CSocketCommandReader::New(aClientSocket, *this); |
|
173 commandReader->ReadCommand(); |
|
174 } |
|
175 |
|
176 void CServer::HandleSocketClosure(CSocket& aSocket) |
|
177 { |
|
178 ASSERT(&aSocket == iSocket); |
|
179 PostQuitMessage(0); |
|
180 } |
|
181 |
|
182 void CServer::HandleSocketCommand(TPacketHeader::TPacketType aCommand, const char* aPacket, int aPacketLength, CSocketCommandReader& aReader) |
|
183 { |
|
184 switch (aCommand) |
|
185 { |
|
186 case TPacketHeader::ECommandCreateConsoleWindow: |
|
187 { |
|
188 iConsole->Write(TEXT("Creating new console window...\r\n")); |
|
189 const TCreateConsoleWindowPacket* createConsoleWindowPacket = new((char*)aPacket) TCreateConsoleWindowPacket; |
|
190 LPTSTR title = (TCHAR*)((char*)aPacket + sizeof(TCreateConsoleWindowPacket)); |
|
191 try |
|
192 { |
|
193 createConsoleWindowPacket->Validate(); |
|
194 CRemoteConsole* remoteConsole = CRemoteConsole::New(iAppHandle, aReader, title, createConsoleWindowPacket->iWidth, createConsoleWindowPacket->iHeight, iPreferences); |
|
195 int consoleId = remoteConsole->Id(); |
|
196 iConsole->WriteFormat(TEXT("Created window \"%s\" (%d)...\r\n"), title, consoleId); |
|
197 aReader.SendResponse((char*)&consoleId, sizeof(int)); |
|
198 } |
|
199 catch (TException aException) |
|
200 { |
|
201 int err = -2; // KErrGeneral. |
|
202 if (aException == KExceptionInvalidClientVersion) |
|
203 { |
|
204 err = -21; // KErrAccessDenied. |
|
205 } |
|
206 aReader.SendResponse((char*)&err, sizeof(int)); |
|
207 delete &aReader; |
|
208 throw aException; |
|
209 } |
|
210 catch (...) |
|
211 { |
|
212 delete &aReader; |
|
213 throw KExceptionUnknown; |
|
214 } |
|
215 break; |
|
216 } |
|
217 case TPacketHeader::ECommandAttachKeyEventSocket: |
|
218 { |
|
219 iConsole->Write(TEXT("Attaching key event socket...\r\n")); |
|
220 int* consoleId = new((char*)aPacket) int; |
|
221 CRemoteConsole* remoteConsole = CRemoteConsole::Instance(*consoleId); |
|
222 if (remoteConsole) |
|
223 { |
|
224 remoteConsole->AttachKeyEventSocket(aReader.ReleaseSocket()); |
|
225 iConsole->WriteFormat(TEXT("Attached key event socket to window %d...\r\n"), *consoleId); |
|
226 } |
|
227 delete &aReader; |
|
228 break; |
|
229 } |
|
230 default: |
|
231 { |
|
232 iConsole->WriteFormat(TEXT("Invalid server socket command: %d\r\n"), aCommand); |
|
233 delete &aReader; |
|
234 break; |
|
235 } |
|
236 } |
|
237 } |
|
238 |
|
239 void CServer::HandleSocketClosure(CSocketCommandReader& aReader) |
|
240 { |
|
241 delete &aReader; |
|
242 } |
|
243 |
|
244 void CServer::HandleWindowClosure(CWindow& aWindow) |
|
245 { |
|
246 ASSERT(&aWindow == iConsole); |
|
247 PostQuitMessage(0); |
|
248 } |
|
249 |
|
250 LRESULT CALLBACK PrefsCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) |
|
251 { |
|
252 switch (message) |
|
253 { |
|
254 case WM_INITDIALOG: |
|
255 TCHAR string[128]; |
|
256 swprintf(string, TEXT("%u"), sServer->Preferences().ServerPort()); |
|
257 SetDlgItemText(hDlg, ID_EDIT_PORT, string); |
|
258 swprintf(string, TEXT("%u"), sServer->Preferences().DefaultWindowWidth()); |
|
259 SetDlgItemText(hDlg, ID_EDIT_WIN_WIDTH, string); |
|
260 swprintf(string, TEXT("%u"), sServer->Preferences().DefaultWindowHeight()); |
|
261 SetDlgItemText(hDlg, ID_EDIT_WIN_HEIGHT, string); |
|
262 swprintf(string, TEXT("%u"), sServer->Preferences().DefaultWindowPosX()); |
|
263 SetDlgItemText(hDlg, ID_EDIT_WIN_POS_X, string); |
|
264 swprintf(string, TEXT("%u"), sServer->Preferences().DefaultWindowPosY()); |
|
265 SetDlgItemText(hDlg, ID_EDIT_WIN_POS_Y, string); |
|
266 EnableWindow(GetDlgItem(hDlg, ID_EDIT_WIN_POS_X), !sServer->Preferences().SystemPositionedWindows()); |
|
267 EnableWindow(GetDlgItem(hDlg, ID_EDIT_WIN_POS_Y), !sServer->Preferences().SystemPositionedWindows()); |
|
268 CheckDlgButton(hDlg, ID_CHECK_WIN_POS, sServer->Preferences().SystemPositionedWindows()); |
|
269 swprintf(string, TEXT("%u"), sServer->Preferences().NumOverflowLines()); |
|
270 SetDlgItemText(hDlg, ID_OVERFLOW_LINES, string); |
|
271 return TRUE; |
|
272 case WM_COMMAND: |
|
273 switch (LOWORD(wParam)) |
|
274 { |
|
275 case IDOK: |
|
276 { |
|
277 TCHAR string[128]; |
|
278 GetDlgItemText(hDlg, ID_EDIT_PORT, string, 128); |
|
279 unsigned int val; |
|
280 swscanf(string, TEXT("%u"), &val); |
|
281 sServer->Preferences().SetServerPort((unsigned short)val); |
|
282 GetDlgItemText(hDlg, ID_EDIT_WIN_WIDTH, string, 128); |
|
283 swscanf(string, TEXT("%u"), &val); |
|
284 sServer->Preferences().SetDefaultWindowWidth(val); |
|
285 GetDlgItemText(hDlg, ID_EDIT_WIN_HEIGHT, string, 128); |
|
286 swscanf(string, TEXT("%u"), &val); |
|
287 sServer->Preferences().SetDefaultWindowHeight(val); |
|
288 GetDlgItemText(hDlg, ID_EDIT_WIN_POS_X, string, 128); |
|
289 swscanf(string, TEXT("%u"), &val); |
|
290 sServer->Preferences().SetDefaultWindowPosX(val); |
|
291 GetDlgItemText(hDlg, ID_EDIT_WIN_POS_Y, string, 128); |
|
292 swscanf(string, TEXT("%u"), &val); |
|
293 sServer->Preferences().SetDefaultWindowPosY(val); |
|
294 GetDlgItemText(hDlg, ID_OVERFLOW_LINES, string, 128); |
|
295 swscanf(string, TEXT("%u"), &val); |
|
296 sServer->Preferences().SetNumOverflowLines(val); |
|
297 sServer->Preferences().SetSystemPositionedWindows((IsDlgButtonChecked(hDlg, ID_CHECK_WIN_POS) == BST_CHECKED) ? TRUE : FALSE); |
|
298 sServer->Preferences().Write(); |
|
299 sServer->Listen(); |
|
300 } // Deliberate fall through. |
|
301 case IDCANCEL: |
|
302 { |
|
303 EndDialog(hDlg, LOWORD(wParam)); |
|
304 return TRUE; |
|
305 } |
|
306 case ID_CHECK_WIN_POS: |
|
307 { |
|
308 int isChecked = IsDlgButtonChecked(hDlg, ID_CHECK_WIN_POS); |
|
309 EnableWindow(GetDlgItem(hDlg, ID_EDIT_WIN_POS_X), !isChecked); |
|
310 EnableWindow(GetDlgItem(hDlg, ID_EDIT_WIN_POS_Y), !isChecked); |
|
311 break; |
|
312 } |
|
313 } |
|
314 break; |
|
315 } |
|
316 return FALSE; |
|
317 } |
|
318 |
|
319 LRESULT CServer::HandleWindowCommand(UINT aMessage, WPARAM aWParam, LPARAM aLParam) |
|
320 { |
|
321 int wmId = LOWORD(aWParam); |
|
322 int wmEvent = HIWORD(aWParam); |
|
323 switch (wmId) |
|
324 { |
|
325 case KServerInitParam: |
|
326 Listen(); |
|
327 break; |
|
328 case ID_PREFS: |
|
329 DialogBox(iAppHandle, (LPCTSTR)IDD_PREFS_DIALOG, iConsole->Handle(), (DLGPROC)PrefsCallback); |
|
330 break; |
|
331 default: |
|
332 return DefWindowProc(iConsole->Handle(), aMessage, aWParam, aLParam); |
|
333 } |
|
334 return 0; |
|
335 } |