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