use wxSocketBase::Initialize/Shutdown() instead of GSocket_Init/Cleanup()
[wxWidgets.git] / tests / streams / socketstream.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/streams/socketstream.cpp
3 // Purpose: Test wxSocketInputStream/wxSocketOutputStream
4 // Author: Vadim Zeitlin
5 // RCS-ID: $Id$
6 // Copyright: (c) 2008 Vadim Zeitlin
7 // Licence: wxWidgets licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx/wx.h".
11 // and "wx/cppunit.h"
12 #include "testprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 // for all others, include the necessary headers
19 #ifndef WX_PRECOMP
20 #include "wx/log.h"
21 #endif
22
23 #include "wx/socket.h"
24 #include "wx/sckstrm.h"
25 #include "wx/thread.h"
26
27 #include "bstream.h"
28
29 namespace
30 {
31
32 const int TEST_PORT_READ = 0x7778; // arbitrary, chosen because == "wx"
33 const int TEST_PORT_WRITE = 0x7779; // well, "wy"
34
35 // these cond and mutex are used to minimize the risk of the main thread
36 // Connect()-ing before this thread starts Accept()-ing connections but
37 // unfortunately we can't make this truly safe, see comment in
38 // SocketServerThread::Entry()
39 wxMutex gs_mutex;
40 wxCondition gs_cond(gs_mutex);
41 } // anonymous namespace
42
43 // return address for the given port on local host
44 static inline wxIPV4address LocalAddress(int port)
45 {
46 wxIPV4address addr;
47 addr.LocalHost();
48 addr.Service(port);
49
50 return addr;
51 }
52
53 // A thread which creates a listening socket on the specified port and executes
54 // the given function with each socket which connects to it
55 class SocketServerThread : public wxThread
56 {
57 public:
58 // port is the port to listen on and function will be called on each
59 // accepted socket
60 SocketServerThread(int port, void (*accept)(wxSocketBase&))
61 : wxThread(wxTHREAD_JOINABLE),
62 m_port(port),
63 m_accept(accept)
64 {
65 Create();
66 Run();
67 }
68
69 protected:
70 virtual void *Entry()
71 {
72 wxSocketServer srv(LocalAddress(m_port), wxSOCKET_REUSEADDR);
73
74 // FIXME: this is still not atomic, of course and the main thread could
75 // call Connect() before we have time to Accept() but there is
76 // no way to fix it with current API
77 {
78 wxMutexLocker lock(gs_mutex);
79 gs_cond.Signal();
80 }
81
82 wxSocketBase *socket = srv.Accept();
83 if ( socket )
84 (*m_accept)(*socket);
85
86 return NULL;
87 }
88
89 int m_port;
90 void (*m_accept)(wxSocketBase&);
91
92 DECLARE_NO_COPY_CLASS(SocketServerThread)
93 };
94
95 // The test case for socket streams
96 class socketStream :
97 public BaseStreamTestCase<wxSocketInputStream, wxSocketOutputStream>
98 {
99 public:
100 socketStream();
101 virtual ~socketStream();
102
103 virtual void setUp();
104 virtual void tearDown();
105
106 CPPUNIT_TEST_SUITE(socketStream);
107 // Base class stream tests the socketStream supports.
108 CPPUNIT_TEST(Input_GetC);
109
110 // This one fails because wxSocketInputStream::Eof() is not implemented
111 // correctly
112 //CPPUNIT_TEST(Input_Read);
113
114 // The other ones untested yet
115 #if 0
116 CPPUNIT_TEST(Input_Eof);
117 CPPUNIT_TEST(Input_LastRead);
118 CPPUNIT_TEST(Input_CanRead);
119 CPPUNIT_TEST(Input_Peek);
120 CPPUNIT_TEST(Input_Ungetch);
121
122 CPPUNIT_TEST(Output_PutC);
123 CPPUNIT_TEST(Output_Write);
124 CPPUNIT_TEST(Output_LastWrite);
125 #endif
126 CPPUNIT_TEST_SUITE_END();
127
128 private:
129 // Implement base class functions.
130 virtual wxSocketInputStream *DoCreateInStream();
131 virtual wxSocketOutputStream *DoCreateOutStream();
132
133 // socket thread functions
134 static void WriteSocket(wxSocketBase& socket)
135 {
136 socket.Write("hello, world!", 13);
137 }
138
139 static void ReadSocket(wxSocketBase& socket)
140 {
141 char ch;
142 while ( socket.Read(&ch, 1).LastCount() == 1 )
143 ;
144 }
145
146 wxSocketClient *m_readSocket,
147 *m_writeSocket;
148 wxThread *m_writeThread,
149 *m_readThread;
150 };
151
152 socketStream::socketStream()
153 {
154 m_readSocket =
155 m_writeSocket = NULL;
156
157 m_writeThread =
158 m_readThread = NULL;
159
160 wxSocketBase::Initialize();
161 }
162
163 socketStream::~socketStream()
164 {
165 wxSocketBase::Shutdown();
166 }
167
168 void socketStream::setUp()
169 {
170 // create the socket threads and wait until they are ready to accept
171 // connections (if we called Connect() before this happens, it would fail)
172 {
173 wxMutexLocker lock(gs_mutex);
174
175 m_writeThread =
176 new SocketServerThread(TEST_PORT_READ, &socketStream::WriteSocket);
177 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, gs_cond.Wait() );
178
179 m_readThread =
180 new SocketServerThread(TEST_PORT_WRITE, &socketStream::ReadSocket);
181 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, gs_cond.Wait() );
182 }
183
184 m_readSocket = new wxSocketClient;
185 m_readSocket->SetTimeout(3);
186 CPPUNIT_ASSERT( m_readSocket->Connect(LocalAddress(TEST_PORT_READ)) );
187
188 m_writeSocket = new wxSocketClient;
189 m_writeSocket->SetTimeout(3);
190 CPPUNIT_ASSERT( m_writeSocket->Connect(LocalAddress(TEST_PORT_WRITE)) );
191 }
192
193 void socketStream::tearDown()
194 {
195 wxDELETE(m_readSocket);
196 wxDELETE(m_writeSocket);
197
198 m_writeThread->Wait();
199 wxDELETE(m_writeThread);
200
201 m_readThread->Wait();
202 wxDELETE(m_readThread);
203 }
204
205 wxSocketInputStream *socketStream::DoCreateInStream()
206 {
207 wxSocketInputStream *pStrInStream = new wxSocketInputStream(*m_readSocket);
208 CPPUNIT_ASSERT(pStrInStream->IsOk());
209 return pStrInStream;
210 }
211
212 wxSocketOutputStream *socketStream::DoCreateOutStream()
213 {
214 wxSocketOutputStream *pStrOutStream = new wxSocketOutputStream(*m_writeSocket);
215 CPPUNIT_ASSERT(pStrOutStream->IsOk());
216 return pStrOutStream;
217 }
218
219 // Register the stream sub suite, by using some stream helper macro.
220 STREAM_TEST_SUBSUITE_NAMED_REGISTRATION(socketStream)