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