socketstream.cpp 6.8 KB

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