]>
Commit | Line | Data |
---|---|---|
f85d901f GRG |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: server.cpp | |
3 | // Purpose: Server for wxSocket demo | |
4 | // Author: Guillermo Rodriguez Garcia <guille@iies.es> | |
5 | // Modified by: | |
6 | // Created: 1999/09/19 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 1999 Guillermo Rodriguez Garcia | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | // ========================================================================== | |
13 | // declarations | |
14 | // ========================================================================== | |
15 | ||
16 | // -------------------------------------------------------------------------- | |
17 | // headers | |
18 | // -------------------------------------------------------------------------- | |
e2a6f233 | 19 | |
f85d901f | 20 | // For compilers that support precompilation, includes "wx/wx.h". |
f4ada568 GL |
21 | #include "wx/wxprec.h" |
22 | ||
23 | #ifdef __BORLANDC__ | |
f85d901f | 24 | # pragma hdrstop |
f4ada568 GL |
25 | #endif |
26 | ||
677a9f0c | 27 | // for all others, include the necessary headers |
f4ada568 | 28 | #ifndef WX_PRECOMP |
f85d901f | 29 | # include "wx/wx.h" |
f4ada568 | 30 | #endif |
e2a6f233 | 31 | |
09fb22cf JS |
32 | #include "wx/socket.h" |
33 | ||
f85d901f GRG |
34 | // -------------------------------------------------------------------------- |
35 | // resources | |
36 | // -------------------------------------------------------------------------- | |
f4ada568 | 37 | |
f85d901f | 38 | // the application icon |
2804f77d | 39 | #include "mondrian.xpm" |
e2a6f233 | 40 | |
f85d901f GRG |
41 | // -------------------------------------------------------------------------- |
42 | // classes | |
43 | // -------------------------------------------------------------------------- | |
44 | ||
f4ada568 | 45 | // Define a new application type |
f85d901f GRG |
46 | class MyApp : public wxApp |
47 | { | |
48 | public: | |
49 | virtual bool OnInit(); | |
f4ada568 GL |
50 | }; |
51 | ||
f85d901f GRG |
52 | // Define a new frame type: this is going to be our main frame |
53 | class MyFrame : public wxFrame | |
54 | { | |
f4ada568 | 55 | public: |
f85d901f GRG |
56 | MyFrame(); |
57 | ~MyFrame(); | |
58 | ||
59 | // event handlers (these functions should _not_ be virtual) | |
60 | void OnQuit(wxCommandEvent& event); | |
61 | void OnAbout(wxCommandEvent& event); | |
62 | void OnServerEvent(wxSocketEvent& event); | |
63 | void OnSocketEvent(wxSocketEvent& event); | |
64 | ||
65 | void Test1(wxSocketBase *sock); | |
66 | void Test2(wxSocketBase *sock); | |
67 | void Test3(wxSocketBase *sock); | |
68 | ||
69 | // convenience functions | |
70 | void UpdateStatusBar(); | |
71 | ||
72 | private: | |
73 | wxSocketServer *m_server; | |
f85d901f GRG |
74 | wxTextCtrl *m_text; |
75 | wxMenu *m_menuFile; | |
76 | wxMenuBar *m_menuBar; | |
77 | bool m_busy; | |
78 | int m_numClients; | |
79 | ||
be5a51fb | 80 | // any class wishing to process wxWidgets events must use this macro |
f85d901f GRG |
81 | DECLARE_EVENT_TABLE() |
82 | }; | |
83 | ||
38418fde VZ |
84 | // simple helper class to log start and end of each test |
85 | class TestLogger | |
86 | { | |
87 | public: | |
88 | TestLogger(const wxString& name) : m_name(name) | |
89 | { | |
90 | wxLogMessage("=== %s begins ===", m_name); | |
91 | } | |
92 | ||
93 | ~TestLogger() | |
94 | { | |
95 | wxLogMessage("=== %s ends ===", m_name); | |
96 | } | |
97 | ||
98 | private: | |
99 | const wxString m_name; | |
100 | }; | |
101 | ||
f85d901f GRG |
102 | // -------------------------------------------------------------------------- |
103 | // constants | |
104 | // -------------------------------------------------------------------------- | |
105 | ||
106 | // IDs for the controls and the menu commands | |
107 | enum | |
108 | { | |
109 | // menu items | |
91b07357 JS |
110 | SERVER_QUIT = wxID_EXIT, |
111 | SERVER_ABOUT = wxID_ABOUT, | |
f85d901f GRG |
112 | |
113 | // id for sockets | |
91b07357 | 114 | SERVER_ID = 100, |
f85d901f | 115 | SOCKET_ID |
f4ada568 GL |
116 | }; |
117 | ||
f85d901f | 118 | // -------------------------------------------------------------------------- |
be5a51fb | 119 | // event tables and other macros for wxWidgets |
f85d901f | 120 | // -------------------------------------------------------------------------- |
f4ada568 GL |
121 | |
122 | BEGIN_EVENT_TABLE(MyFrame, wxFrame) | |
f85d901f GRG |
123 | EVT_MENU(SERVER_QUIT, MyFrame::OnQuit) |
124 | EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout) | |
125 | EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent) | |
126 | EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent) | |
f4ada568 GL |
127 | END_EVENT_TABLE() |
128 | ||
f4ada568 GL |
129 | IMPLEMENT_APP(MyApp) |
130 | ||
f4ada568 | 131 | |
f85d901f GRG |
132 | // ========================================================================== |
133 | // implementation | |
134 | // ========================================================================== | |
f4ada568 | 135 | |
f85d901f GRG |
136 | // -------------------------------------------------------------------------- |
137 | // the application class | |
138 | // -------------------------------------------------------------------------- | |
f4ada568 | 139 | |
f85d901f GRG |
140 | bool MyApp::OnInit() |
141 | { | |
45e6e6f8 VZ |
142 | if ( !wxApp::OnInit() ) |
143 | return false; | |
144 | ||
f85d901f GRG |
145 | // Create the main application window |
146 | MyFrame *frame = new MyFrame(); | |
f4ada568 | 147 | |
f85d901f | 148 | // Show it and tell the application that it's our main window |
b62ca03d | 149 | frame->Show(true); |
f85d901f | 150 | SetTopWindow(frame); |
2b98cb1f | 151 | |
bd4d918f | 152 | // Success |
b62ca03d | 153 | return true; |
f4ada568 GL |
154 | } |
155 | ||
f85d901f GRG |
156 | // -------------------------------------------------------------------------- |
157 | // main frame | |
158 | // -------------------------------------------------------------------------- | |
a737331d | 159 | |
f85d901f | 160 | // frame constructor |
bd4d918f | 161 | |
b62ca03d | 162 | MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY, |
bd4d918f | 163 | _("wxSocket demo: Server"), |
f85d901f | 164 | wxDefaultPosition, wxSize(300, 200)) |
f4ada568 | 165 | { |
f85d901f GRG |
166 | // Give the frame an icon |
167 | SetIcon(wxICON(mondrian)); | |
168 | ||
169 | // Make menus | |
170 | m_menuFile = new wxMenu(); | |
bd4d918f | 171 | m_menuFile->Append(SERVER_ABOUT, _("&About...\tCtrl-A"), _("Show about dialog")); |
f85d901f | 172 | m_menuFile->AppendSeparator(); |
bd4d918f | 173 | m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server")); |
f85d901f GRG |
174 | |
175 | // Append menus to the menubar | |
176 | m_menuBar = new wxMenuBar(); | |
bd4d918f | 177 | m_menuBar->Append(m_menuFile, _("&File")); |
f85d901f GRG |
178 | SetMenuBar(m_menuBar); |
179 | ||
8520f137 | 180 | #if wxUSE_STATUSBAR |
f85d901f GRG |
181 | // Status bar |
182 | CreateStatusBar(2); | |
8520f137 | 183 | #endif // wxUSE_STATUSBAR |
f85d901f | 184 | |
bd4d918f | 185 | // Make a textctrl for logging |
b62ca03d | 186 | m_text = new wxTextCtrl(this, wxID_ANY, |
bd4d918f GRG |
187 | _("Welcome to wxSocket demo: Server\n"), |
188 | wxDefaultPosition, wxDefaultSize, | |
f85d901f | 189 | wxTE_MULTILINE | wxTE_READONLY); |
38418fde | 190 | delete wxLog::SetActiveTarget(new wxLogTextCtrl(m_text)); |
f85d901f | 191 | |
bd4d918f | 192 | // Create the address - defaults to localhost:0 initially |
8575ff50 VZ |
193 | #if wxUSE_IPV6 |
194 | wxIPV6address addr; | |
195 | #else | |
f85d901f | 196 | wxIPV4address addr; |
8575ff50 | 197 | #endif |
f85d901f GRG |
198 | addr.Service(3000); |
199 | ||
bd4d918f | 200 | // Create the socket |
f85d901f | 201 | m_server = new wxSocketServer(addr); |
f85d901f GRG |
202 | |
203 | // We use Ok() here to see if the server is really listening | |
bd4d918f GRG |
204 | if (! m_server->Ok()) |
205 | { | |
38418fde | 206 | wxLogMessage("Could not listen at the specified port !"); |
bd4d918f GRG |
207 | return; |
208 | } | |
f85d901f | 209 | else |
bd4d918f | 210 | { |
38418fde | 211 | wxLogMessage("Server listening."); |
bd4d918f GRG |
212 | } |
213 | ||
214 | // Setup the event handler and subscribe to connection events | |
215 | m_server->SetEventHandler(*this, SERVER_ID); | |
216 | m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); | |
b62ca03d | 217 | m_server->Notify(true); |
f85d901f | 218 | |
b62ca03d | 219 | m_busy = false; |
f85d901f GRG |
220 | m_numClients = 0; |
221 | UpdateStatusBar(); | |
f4ada568 GL |
222 | } |
223 | ||
f85d901f | 224 | MyFrame::~MyFrame() |
f4ada568 | 225 | { |
bd4d918f | 226 | // No delayed deletion here, as the frame is dying anyway |
f85d901f GRG |
227 | delete m_server; |
228 | } | |
f4ada568 | 229 | |
f85d901f | 230 | // event handlers |
f4ada568 | 231 | |
f85d901f GRG |
232 | void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) |
233 | { | |
b62ca03d WS |
234 | // true is to force the frame to close |
235 | Close(true); | |
f85d901f | 236 | } |
f4ada568 | 237 | |
f85d901f GRG |
238 | void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) |
239 | { | |
4693b20c | 240 | wxMessageBox(_("wxSocket demo: Server\n(c) 1999 Guillermo Rodriguez Garcia\n"), |
bd4d918f | 241 | _("About Server"), |
f85d901f | 242 | wxOK | wxICON_INFORMATION, this); |
f4ada568 GL |
243 | } |
244 | ||
f85d901f | 245 | void MyFrame::Test1(wxSocketBase *sock) |
f4ada568 | 246 | { |
38418fde | 247 | TestLogger logtest("Test 1"); |
f4ada568 | 248 | |
f85d901f GRG |
249 | // Receive data from socket and send it back. We will first |
250 | // get a byte with the buffer size, so we can specify the | |
6097c3a2 GRG |
251 | // exact size and use the wxSOCKET_WAITALL flag. Also, we |
252 | // disabled input events so we won't have unwanted reentrance. | |
253 | // This way we can avoid the infamous wxSOCKET_BLOCK flag. | |
e51b0130 | 254 | |
f85d901f GRG |
255 | sock->SetFlags(wxSOCKET_WAITALL); |
256 | ||
bc7e88ae | 257 | // Read the size |
38418fde | 258 | unsigned char len; |
f187448d | 259 | sock->Read(&len, 1); |
38418fde | 260 | wxCharBuffer buf(len); |
bc7e88ae GRG |
261 | |
262 | // Read the data | |
38418fde VZ |
263 | sock->Read(buf.data(), len); |
264 | wxLogMessage("Got the data, sending it back"); | |
bc7e88ae GRG |
265 | |
266 | // Write it back | |
f85d901f | 267 | sock->Write(buf, len); |
f4ada568 GL |
268 | } |
269 | ||
f85d901f | 270 | void MyFrame::Test2(wxSocketBase *sock) |
f4ada568 | 271 | { |
38418fde | 272 | char buf[4096]; |
f85d901f | 273 | |
38418fde | 274 | TestLogger logtest("Test 2"); |
f85d901f GRG |
275 | |
276 | // We don't need to set flags because ReadMsg and WriteMsg | |
277 | // are not affected by them anyway. | |
e51b0130 | 278 | |
bc7e88ae | 279 | // Read the message |
38418fde VZ |
280 | wxUint32 len = sock->ReadMsg(buf, sizeof(buf)).LastCount(); |
281 | if ( !len ) | |
282 | { | |
283 | wxLogError("Failed to read message."); | |
284 | return; | |
285 | } | |
286 | ||
287 | wxLogMessage("Got \"%s\" from client.", wxString::FromUTF8(buf, len)); | |
288 | wxLogMessage("Sending the data back"); | |
f85d901f | 289 | |
bc7e88ae | 290 | // Write it back |
f85d901f | 291 | sock->WriteMsg(buf, len); |
f4ada568 GL |
292 | } |
293 | ||
f85d901f | 294 | void MyFrame::Test3(wxSocketBase *sock) |
f4ada568 | 295 | { |
38418fde | 296 | TestLogger logtest("Test 3"); |
6097c3a2 | 297 | |
677a9f0c | 298 | // This test is similar to the first one, but the len is |
6097c3a2 | 299 | // expressed in kbytes - this tests large data transfers. |
e51b0130 | 300 | |
6097c3a2 GRG |
301 | sock->SetFlags(wxSOCKET_WAITALL); |
302 | ||
bc7e88ae | 303 | // Read the size |
38418fde | 304 | unsigned char len; |
f187448d | 305 | sock->Read(&len, 1); |
38418fde | 306 | wxCharBuffer buf(len*1024); |
bc7e88ae GRG |
307 | |
308 | // Read the data | |
38418fde VZ |
309 | sock->Read(buf.data(), len * 1024); |
310 | wxLogMessage("Got the data, sending it back"); | |
bc7e88ae GRG |
311 | |
312 | // Write it back | |
6097c3a2 | 313 | sock->Write(buf, len * 1024); |
f4ada568 GL |
314 | } |
315 | ||
f85d901f | 316 | void MyFrame::OnServerEvent(wxSocketEvent& event) |
f4ada568 | 317 | { |
bd4d918f | 318 | wxString s = _("OnServerEvent: "); |
f85d901f GRG |
319 | wxSocketBase *sock; |
320 | ||
bc7e88ae | 321 | switch(event.GetSocketEvent()) |
f85d901f | 322 | { |
bd4d918f GRG |
323 | case wxSOCKET_CONNECTION : s.Append(_("wxSOCKET_CONNECTION\n")); break; |
324 | default : s.Append(_("Unexpected event !\n")); break; | |
f85d901f | 325 | } |
f4ada568 | 326 | |
f85d901f | 327 | m_text->AppendText(s); |
765e386b | 328 | |
f85d901f | 329 | // Accept new connection if there is one in the pending |
b62ca03d | 330 | // connections queue, else exit. We use Accept(false) for |
f85d901f GRG |
331 | // non-blocking accept (although if we got here, there |
332 | // should ALWAYS be a pending connection). | |
e51b0130 | 333 | |
b62ca03d | 334 | sock = m_server->Accept(false); |
f85d901f GRG |
335 | |
336 | if (sock) | |
337 | { | |
38418fde | 338 | wxLogMessage("New client connection accepted"); |
f85d901f GRG |
339 | } |
340 | else | |
341 | { | |
38418fde | 342 | wxLogMessage("Error: couldn't accept a new connection"); |
f85d901f GRG |
343 | return; |
344 | } | |
345 | ||
346 | sock->SetEventHandler(*this, SOCKET_ID); | |
347 | sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); | |
b62ca03d | 348 | sock->Notify(true); |
f85d901f GRG |
349 | |
350 | m_numClients++; | |
351 | UpdateStatusBar(); | |
f4ada568 GL |
352 | } |
353 | ||
f85d901f GRG |
354 | void MyFrame::OnSocketEvent(wxSocketEvent& event) |
355 | { | |
bd4d918f | 356 | wxString s = _("OnSocketEvent: "); |
f4d5e009 | 357 | wxSocketBase *sock = event.GetSocket(); |
f85d901f | 358 | |
f4d5e009 | 359 | // First, print a message |
bc7e88ae | 360 | switch(event.GetSocketEvent()) |
f85d901f | 361 | { |
f4d5e009 GRG |
362 | case wxSOCKET_INPUT : s.Append(_("wxSOCKET_INPUT\n")); break; |
363 | case wxSOCKET_LOST : s.Append(_("wxSOCKET_LOST\n")); break; | |
364 | default : s.Append(_("Unexpected event !\n")); break; | |
f85d901f GRG |
365 | } |
366 | ||
367 | m_text->AppendText(s); | |
368 | ||
369 | // Now we process the event | |
bc7e88ae | 370 | switch(event.GetSocketEvent()) |
f85d901f GRG |
371 | { |
372 | case wxSOCKET_INPUT: | |
373 | { | |
374 | // We disable input events, so that the test doesn't trigger | |
375 | // wxSocketEvent again. | |
376 | sock->SetNotify(wxSOCKET_LOST_FLAG); | |
377 | ||
378 | // Which test are we going to run? | |
379 | unsigned char c; | |
f4d5e009 | 380 | sock->Read(&c, 1); |
f85d901f GRG |
381 | |
382 | switch (c) | |
383 | { | |
384 | case 0xBE: Test1(sock); break; | |
385 | case 0xCE: Test2(sock); break; | |
386 | case 0xDE: Test3(sock); break; | |
f4d5e009 | 387 | default: |
38418fde | 388 | wxLogMessage("Unknown test id received from client"); |
f85d901f GRG |
389 | } |
390 | ||
391 | // Enable input events again. | |
392 | sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); | |
393 | break; | |
394 | } | |
395 | case wxSOCKET_LOST: | |
396 | { | |
397 | m_numClients--; | |
398 | ||
bd4d918f GRG |
399 | // Destroy() should be used instead of delete wherever possible, |
400 | // due to the fact that wxSocket uses 'delayed events' (see the | |
401 | // documentation for wxPostEvent) and we don't want an event to | |
402 | // arrive to the event handler (the frame, here) after the socket | |
403 | // has been deleted. Also, we might be doing some other thing with | |
404 | // the socket at the same time; for example, we might be in the | |
405 | // middle of a test or something. Destroy() takes care of all | |
bc7e88ae | 406 | // this for us. |
bd4d918f | 407 | |
38418fde | 408 | wxLogMessage("Deleting socket."); |
bd4d918f | 409 | sock->Destroy(); |
f85d901f GRG |
410 | break; |
411 | } | |
412 | default: ; | |
413 | } | |
414 | ||
415 | UpdateStatusBar(); | |
416 | } | |
417 | ||
418 | // convenience functions | |
419 | ||
420 | void MyFrame::UpdateStatusBar() | |
f4ada568 | 421 | { |
8520f137 | 422 | #if wxUSE_STATUSBAR |
f85d901f | 423 | wxString s; |
bd4d918f | 424 | s.Printf(_("%d clients connected"), m_numClients); |
f85d901f | 425 | SetStatusText(s, 1); |
8520f137 | 426 | #endif // wxUSE_STATUSBAR |
f4ada568 | 427 | } |