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