]> git.saurik.com Git - wxWidgets.git/blame - samples/sockets/client.cpp
Some more bug reports
[wxWidgets.git] / samples / sockets / client.cpp
CommitLineData
f85d901f
GRG
1/////////////////////////////////////////////////////////////////////////////
2// Name: client.cpp
3// Purpose: Client 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
f4ada568 20#ifdef __GNUG__
f85d901f
GRG
21# pragma implementation "client.cpp"
22# pragma interface "client.cpp"
f4ada568
GL
23#endif
24
f85d901f 25// For compilers that support precompilation, includes "wx/wx.h".
f4ada568
GL
26#include "wx/wxprec.h"
27
28#ifdef __BORLANDC__
f85d901f 29# pragma hdrstop
f4ada568
GL
30#endif
31
f85d901f 32// for all others, include the necessary headers
f4ada568 33#ifndef WX_PRECOMP
f85d901f 34# include "wx/wx.h"
09fb22cf
JS
35#endif
36
f85d901f
GRG
37# include "wx/socket.h"
38# include "wx/url.h"
39# include "wx/protocol/http.h"
40# include "wx/progdlg.h"
e2a6f233 41
f85d901f
GRG
42// --------------------------------------------------------------------------
43// resources
44// --------------------------------------------------------------------------
f4ada568 45
f85d901f
GRG
46// the application icon
47#if defined(__WXGTK__) || defined(__WXMOTIF__)
48# include "mondrian.xpm"
e2a6f233
JS
49#endif
50
f85d901f
GRG
51// --------------------------------------------------------------------------
52// classes
53// --------------------------------------------------------------------------
f4ada568 54
f85d901f
GRG
55// Define a new application type
56class MyApp : public wxApp
57{
f4ada568 58public:
f85d901f 59 virtual bool OnInit();
f4ada568
GL
60};
61
f85d901f
GRG
62// Define a new frame type: this is going to be our main frame
63class MyFrame : public wxFrame
f4ada568
GL
64{
65public:
f85d901f
GRG
66 MyFrame();
67 ~MyFrame();
68
69 // event handlers (these functions should _not_ be virtual)
70 void OnQuit(wxCommandEvent& event);
71 void OnAbout(wxCommandEvent& event);
72 void OnOpenConnection(wxCommandEvent& event);
73 void OnTest1(wxCommandEvent& event);
74 void OnTest2(wxCommandEvent& event);
75 void OnTest3(wxCommandEvent& event);
76 void OnCloseConnection(wxCommandEvent& event);
77 void OnSocketEvent(wxSocketEvent& event);
78
79 // convenience functions
80 void UpdateStatusBar();
81
82private:
83 wxSocketClient *m_sock;
84 wxPanel *m_panel;
85 wxTextCtrl *m_text;
86 wxMenu *m_menuFile;
87 wxMenu *m_menuSocket;
88 wxMenuBar *m_menuBar;
89 bool m_busy;
90
91 // any class wishing to process wxWindows events must use this macro
92 DECLARE_EVENT_TABLE()
f4ada568
GL
93};
94
f85d901f
GRG
95// --------------------------------------------------------------------------
96// constants
97// --------------------------------------------------------------------------
f4ada568 98
f85d901f
GRG
99// IDs for the controls and the menu commands
100enum
f4ada568 101{
f85d901f
GRG
102 // menu items
103 CLIENT_QUIT = 1000,
104 CLIENT_ABOUT,
105 CLIENT_OPEN,
106 CLIENT_TEST1,
107 CLIENT_TEST2,
108 CLIENT_TEST3,
109 CLIENT_CLOSE,
110
111 // id for socket
112 SOCKET_ID
113};
f4ada568 114
f85d901f
GRG
115// --------------------------------------------------------------------------
116// event tables and other macros for wxWindows
117// --------------------------------------------------------------------------
f4ada568 118
f85d901f
GRG
119BEGIN_EVENT_TABLE(MyFrame, wxFrame)
120 EVT_MENU(CLIENT_QUIT, MyFrame::OnQuit)
121 EVT_MENU(CLIENT_ABOUT, MyFrame::OnAbout)
122 EVT_MENU(CLIENT_OPEN, MyFrame::OnOpenConnection)
123 EVT_MENU(CLIENT_TEST1, MyFrame::OnTest1)
124 EVT_MENU(CLIENT_TEST2, MyFrame::OnTest2)
125 EVT_MENU(CLIENT_TEST3, MyFrame::OnTest3)
126 EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection)
127 EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
128END_EVENT_TABLE()
f4ada568 129
f85d901f 130IMPLEMENT_APP(MyApp)
f4ada568 131
f85d901f
GRG
132// ==========================================================================
133// implementation
134// ==========================================================================
f4ada568 135
f85d901f
GRG
136// --------------------------------------------------------------------------
137// the application class
138// --------------------------------------------------------------------------
f4ada568 139
f85d901f
GRG
140bool MyApp::OnInit()
141{
142 // Create the main application window
143 MyFrame *frame = new MyFrame();
f4ada568 144
f85d901f 145 // Show it and tell the application that it's our main window
f4ada568 146 frame->Show(TRUE);
f85d901f
GRG
147 SetTopWindow(frame);
148
149 // success
27529614 150 return TRUE;
f4ada568
GL
151}
152
f85d901f
GRG
153// --------------------------------------------------------------------------
154// main frame
155// --------------------------------------------------------------------------
156
157// frame constructor
158MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1,
159 _T("wxSocket demo: Client"),
160 wxDefaultPosition, wxSize(300, 200))
f4ada568 161{
f85d901f
GRG
162 // Give the frame an icon
163 SetIcon(wxICON(mondrian));
164
165 // Make menus
166 m_menuFile = new wxMenu();
167 m_menuFile->Append(CLIENT_ABOUT, _T("&About...\tCtrl-A"), _T("Show about dialog"));
168 m_menuFile->AppendSeparator();
169 m_menuFile->Append(CLIENT_QUIT, _T("E&xit\tAlt-X"), _T("Quit client"));
170
171 m_menuSocket = new wxMenu();
172 m_menuSocket->Append(CLIENT_OPEN, _T("&Open session"), _T("Connect to server"));
173 m_menuSocket->AppendSeparator();
174 m_menuSocket->Append(CLIENT_TEST1, _T("Test &1"), _T("Test basic functionality"));
175 m_menuSocket->Append(CLIENT_TEST2, _T("Test &2"), _T("Test ReadMsg and WriteMsg"));
176 m_menuSocket->Append(CLIENT_TEST3, _T("Test &3"), _T("Test large data transfer"));
177 m_menuSocket->AppendSeparator();
178 m_menuSocket->Append(CLIENT_CLOSE, _T("&Close session"), _T("Close connection"));
179
180 // Append menus to the menubar
181 m_menuBar = new wxMenuBar();
182 m_menuBar->Append(m_menuFile, _T("&File"));
183 m_menuBar->Append(m_menuSocket, _T("&Socket"));
184 SetMenuBar(m_menuBar);
185
186 // Status bar
f4ada568 187 CreateStatusBar(2);
f85d901f
GRG
188
189 // Make a panel with a textctrl in it
190 m_panel = new wxPanel(this, -1, wxPoint(0, 0), GetClientSize());
191 m_text = new wxTextCtrl(m_panel, -1,
192 _T("Welcome to wxSocket demo: Client\n")
193 _T("Client ready\n\n"),
194 wxPoint(0, 0), m_panel->GetClientSize(),
195 wxTE_MULTILINE | wxTE_READONLY);
196
197 // Create the socket
198 m_sock = new wxSocketClient();
199 m_sock->SetEventHandler(*this, SOCKET_ID);
200 m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG |
201 wxSOCKET_INPUT_FLAG |
202 wxSOCKET_LOST_FLAG);
203 m_sock->Notify(TRUE);
204
205 m_busy = FALSE;
206 UpdateStatusBar();
f4ada568
GL
207}
208
209MyFrame::~MyFrame()
210{
f85d901f 211 delete m_sock;
f4ada568
GL
212}
213
f85d901f
GRG
214// event handlers
215
216void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
f4ada568 217{
f85d901f 218 // TRUE is to force the frame to close
f4ada568
GL
219 Close(TRUE);
220}
221
f85d901f
GRG
222void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
223{
224 wxMessageBox(_T("wxSocket demo: Client\n")
225 _T("(c) 1999 Guillermo Rodriguez Garcia\n"),
226 _T("About Client"),
227 wxOK | wxICON_INFORMATION, this);
228}
229
230void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
f4ada568
GL
231{
232 wxIPV4address addr;
f4ada568 233
f85d901f
GRG
234 m_menuSocket->Enable(CLIENT_OPEN, FALSE);
235 m_menuSocket->Enable(CLIENT_CLOSE, FALSE);
236
237 // Ask server address
238 wxString hostname = wxGetTextFromUser(
239 _T("Enter the address of the wxSocket demo server:"),
240 _T("Connect ..."),
241 _T("localhost"));
242
243 addr.Hostname(hostname);
f4ada568 244 addr.Service(3000);
f4ada568 245
f85d901f
GRG
246 // Non-blocking connect
247 m_text->AppendText(_T("Trying to connect (timeout = 10 sec) ...\n"));
248 m_sock->Connect(addr, FALSE);
249 m_sock->WaitOnConnect(10);
250
251 if (m_sock->IsConnected())
252 m_text->AppendText(_T("Succeeded ! Connection established\n"));
253 else
254 {
255 m_sock->Close();
256 m_text->AppendText(_T("Failed ! Unable to connect\n"));
257 wxMessageBox(_T("Can't connect to the specified host"), _T("Alert !"));
258 }
259
260 UpdateStatusBar();
f4ada568
GL
261}
262
f85d901f 263void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
f4ada568 264{
f85d901f
GRG
265 char *buf1, *buf2;
266 char len;
267
268 // Disable socket menu entries (exception: Close Session)
269 m_busy = TRUE;
270 UpdateStatusBar();
271
272 m_text->AppendText(_T("\n=== Test 1 begins ===\n"));
273
274 // Tell the server which test we are running
275 char c = 0xBE;
276 m_sock->Write(&c, 1);
277
278 // Send some data and read it back. We know the size of the
279 // buffer, so we can specify the exact number of bytes to be
280 // sent or received and use the WAITALL flag. Also, we have
281 // disabled menu entries which could interfere with the test,
282 // so we can safely avoid the BLOCK (formerly SPEED) flag.
283 //
284 // First we send a byte with the length of the string, then
285 // we send the string itself (do NOT try to send any integral
286 // value larger than a byte "as is" acrosss the network, or
287 // you might be in trouble! Ever heard about big and little
288 // endian computers?)
289 //
290 m_sock->SetFlags(wxSOCKET_WAITALL);
291
292 buf1 = _T("Test string (less than 127 chars!)");
293 len = wxStrlen(buf1) + 1;
294 buf2 = new char[len];
295
296 m_text->AppendText(_T("Sending a test buffer to the server ..."));
297 m_sock->Write(&len, 1);
298 m_sock->Write(buf1, len);
299 m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
300
301 m_text->AppendText(_T("Receiving the buffer back from server ..."));
302 m_sock->Read(buf2, len);
303 m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
304
305 m_text->AppendText(_T("Comparing the two buffers ..."));
306 if (memcmp(buf1, buf2, len) != 0)
307 {
308 m_text->AppendText(_T("failed!\n"));
309 m_text->AppendText(_T("Test 1 failed !\n"));
310 }
311 else
312 {
313 m_text->AppendText(_T("done\n"));
314 m_text->AppendText(_T("Test 1 passed !\n"));
315 }
316 m_text->AppendText(_T("=== Test 1 ends ===\n"));
f4ada568 317
f85d901f
GRG
318 delete[] buf2;
319 m_busy = FALSE;
320 UpdateStatusBar();
321}
f4ada568 322
f85d901f
GRG
323void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
324{
325 char *msg1;
326 char *msg2;
327 size_t len;
328
329 // Disable socket menu entries (exception: Close Session)
330 m_busy = TRUE;
331 UpdateStatusBar();
332
333 m_text->AppendText(_T("\n=== Test 2 begins ===\n"));
334
335 // Tell the server which test we are running
336 char c = 0xCE;
337 m_sock->Write(&c, 1);
338
339 // Here we use ReadMsg and WriteMsg to send messages with
340 // a header with size information. Also, the reception is
341 // event triggered, so we test input events as well.
342 //
343 // We need to set no flags here (ReadMsg and WriteMsg are
344 // not affected by flags)
345 //
346 m_sock->SetFlags(wxSOCKET_WAITALL);
347
348 wxString s = wxGetTextFromUser(
349 _T("Enter an arbitrary string to send to the server:"),
350 _T("Test 2 ..."),
351 _T("Yes I like wxWindows!"));
352
353 msg1 = (char *)s.c_str();
354 len = wxStrlen(msg1) + 1;
355 msg2 = (char *)malloc(len);
356
357 m_text->AppendText(_T("Sending the string with WriteMsg ..."));
358 m_sock->WriteMsg(msg1, len);
359 m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
360 m_text->AppendText(_T("Waiting for an event (timeout = 2 sec)\n"));
361
362 // Wait until data available (will also return if the connection is lost)
363 m_sock->WaitForRead(2);
364
365 if (m_sock->IsData())
366 {
367 m_text->AppendText(_T("Reading the string back with ReadMsg ..."));
368 m_sock->ReadMsg(msg2, len);
369 m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
370 m_text->AppendText(_T("Comparing the two buffers ..."));
371 if (memcmp(msg1, msg2, len) != 0)
372 {
373 m_text->AppendText(_T("failed!\n"));
374 m_text->AppendText(_T("Test 2 failed !\n"));
375 }
376 else
377 {
378 m_text->AppendText(_T("done\n"));
379 m_text->AppendText(_T("Test 2 passed !\n"));
380 }
765e386b 381 }
f85d901f
GRG
382 else
383 m_text->AppendText(_T("Timeout ! Test 2 failed.\n"));
765e386b 384
f85d901f 385 m_text->AppendText(_T("=== Test 2 ends ===\n"));
765e386b 386
f85d901f
GRG
387 free(msg2);
388 m_busy = FALSE;
389 UpdateStatusBar();
765e386b
GL
390}
391
f85d901f 392void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
f4ada568 393{
f85d901f
GRG
394 m_text->AppendText(_T("\n=== Test 3 begins ===\n"));
395 m_text->AppendText(_T("Test 3 not implemented\n"));
396 m_text->AppendText(_T("=== Test 3 ends ===\n"));
f4ada568
GL
397}
398
f85d901f 399void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
f4ada568 400{
f85d901f
GRG
401 m_sock->Close();
402 UpdateStatusBar();
f4ada568
GL
403}
404
f85d901f 405void MyFrame::OnSocketEvent(wxSocketEvent& event)
f4ada568 406{
f85d901f
GRG
407 wxString s = _T("OnSocketEvent: ");
408
409 switch(event.SocketEvent())
410 {
411 case wxSOCKET_INPUT : s.Append(_T("wxSOCKET_INPUT\n")); break;
412 case wxSOCKET_LOST : s.Append(_T("wxSOCKET_LOST\n")); break;
413 case wxSOCKET_CONNECTION : s.Append(_T("wxSOCKET_CONNECTION\n")); break;
414 default : s.Append(_T("Unexpected event !\n")); break;
415 }
f4ada568 416
f85d901f
GRG
417 m_text->AppendText(s);
418 UpdateStatusBar();
f4ada568
GL
419}
420
f85d901f 421// convenience functions
a324a7bc 422
f85d901f 423void MyFrame::UpdateStatusBar()
a324a7bc 424{
f85d901f 425 wxString s;
a324a7bc 426
f85d901f
GRG
427 if (!m_sock->IsConnected())
428 {
429 s.Printf(_T("Not connected"));
a324a7bc 430 }
f85d901f
GRG
431 else
432 {
433 wxIPV4address addr;
a324a7bc 434
f85d901f
GRG
435 m_sock->GetPeer(addr);
436 s.Printf(_T("%s : %d"), (addr.Hostname()).c_str(), addr.Service());
437 }
f4ada568 438
f85d901f 439 SetStatusText(s, 1);
a737331d 440
f85d901f
GRG
441 m_menuSocket->Enable(CLIENT_OPEN, !m_sock->IsConnected() && !m_busy);
442 m_menuSocket->Enable(CLIENT_TEST1, m_sock->IsConnected() && !m_busy);
443 m_menuSocket->Enable(CLIENT_TEST2, m_sock->IsConnected() && !m_busy);
444 m_menuSocket->Enable(CLIENT_TEST3, m_sock->IsConnected() && !m_busy);
445 m_menuSocket->Enable(CLIENT_CLOSE, m_sock->IsConnected());
f4ada568 446}