選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

networking.cpp 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. // networking.cpp
  2. // Copyright (C) 2006-2009 MicroNeil Research Corporation.
  3. //
  4. // This program is part of the MicroNeil Research Open Library Project. For
  5. // more information go to http://www.microneil.com/OpenLibrary/index.html
  6. //
  7. // This program is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU General Public License as published by the
  9. // Free Software Foundation; either version 2 of the License, or (at your
  10. // option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful, but WITHOUT
  13. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. // more details.
  16. //
  17. // You should have received a copy of the GNU General Public License along with
  18. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  19. // Place, Suite 330, Boston, MA 02111-1307 USA
  20. //==============================================================================
  21. // See networking.hpp for notes.
  22. // See networking.inline.hpp for inlined methods & functions.
  23. #include "networking.hpp"
  24. Networking Network; // Finally creating the Network instance.
  25. //// Platform Specific Stuff ///////////////////////////////////////////////////
  26. #if defined(WIN32) || defined(WIN64)
  27. ////////////////////////////////////////////////////////////////////////////////
  28. //// Being Windows specific code
  29. WSADATA WSSTartData; // Socket library data structure.
  30. // Error description handling for humans.
  31. string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno.
  32. char* s = 0;
  33. switch(Errno) {
  34. case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break;
  35. case WSA_NOT_ENOUGH_MEMORY: s = "WSA_NOT_ENOUGH_MEMORY"; break;
  36. case WSA_INVALID_PARAMETER: s = "WSA_INVALID_PARAMETER"; break;
  37. case WSA_OPERATION_ABORTED: s = "WSA_OPERATION_ABORTED"; break;
  38. case WSA_IO_INCOMPLETE: s = "WSA_IO_INCOMPLETE"; break;
  39. case WSA_IO_PENDING: s = "WSA_IO_PENDING"; break;
  40. case WSAEINTR: s = "WSAEINTR"; break;
  41. case WSAEBADF: s = "WSAEBADF"; break;
  42. case WSAEACCES: s = "WSAEACCES"; break;
  43. case WSAEFAULT: s = "WSAEFAULT"; break;
  44. case WSAEINVAL: s = "WSAEINVAL"; break;
  45. case WSAEMFILE: s = "WSAEMFILE"; break;
  46. case WSAEWOULDBLOCK: s = "WSAEWOULDBLOCK"; break;
  47. case WSAEINPROGRESS: s = "WSAEINPROGRESS"; break;
  48. case WSAEALREADY: s = "WSAEALREADY"; break;
  49. case WSAENOTSOCK: s = "WSAENOTSOCK"; break;
  50. case WSAEDESTADDRREQ: s = "WSAEDESTADDRREQ"; break;
  51. case WSAEMSGSIZE: s = "WSAEMSGSIZE"; break;
  52. case WSAEPROTOTYPE: s = "WSAEPROTOTYPE"; break;
  53. case WSAENOPROTOOPT: s = "WSAENOPROTOOPT"; break;
  54. case WSAEPROTONOSUPPORT: s = "WSAEPROTONOSUPPORT"; break;
  55. case WSAESOCKTNOSUPPORT: s = "WSAESOCKTNOSUPPORT"; break;
  56. case WSAEOPNOTSUPP: s = "WSAEOPNOTSUPP"; break;
  57. case WSAEPFNOSUPPORT: s = "WSAEPFNOSUPPORT"; break;
  58. case WSAEAFNOSUPPORT: s = "WSAEAFNOSUPPORT"; break;
  59. case WSAEADDRINUSE: s = "WSAEADDRINUSE"; break;
  60. case WSAEADDRNOTAVAIL: s = "WSAEADDRNOTAVAIL"; break;
  61. case WSAENETDOWN: s = "WSAENETDOWN"; break;
  62. case WSAENETUNREACH: s = "WSAENETUNREACH"; break;
  63. case WSAENETRESET: s = "WSAENETRESET"; break;
  64. case WSAECONNABORTED: s = "WSAECONNABORTED"; break;
  65. case WSAECONNRESET: s = "WSAECONNRESET"; break;
  66. case WSAENOBUFS: s = "WSAENOBUFS"; break;
  67. case WSAEISCONN: s = "WSAEISCONN"; break;
  68. case WSAENOTCONN: s = "WSAENOTCONN"; break;
  69. case WSAESHUTDOWN: s = "WSAESHUTDOWN"; break;
  70. case WSAETOOMANYREFS: s = "WSAETOOMANYREFS"; break;
  71. case WSAETIMEDOUT: s = "WSAETIMEDOUT"; break;
  72. case WSAECONNREFUSED: s = "WSAECONNREFUSED"; break;
  73. case WSAELOOP: s = "WSAELOOP"; break;
  74. case WSAENAMETOOLONG: s = "WSAENAMETOOLONG"; break;
  75. case WSAEHOSTDOWN: s = "WSAEHOSTDOWN"; break;
  76. case WSAEHOSTUNREACH: s = "WSAEHOSTUNREACH"; break;
  77. case WSAENOTEMPTY: s = "WSAENOTEMPTY"; break;
  78. case WSAEPROCLIM: s = "WSAEPROCLIM"; break;
  79. case WSAEUSERS: s = "WSAEUSERS"; break;
  80. case WSAEDQUOT: s = "WSAEDQUOT"; break;
  81. case WSAESTALE: s = "WSAESTALE"; break;
  82. case WSAEREMOTE: s = "WSAEREMOTE"; break;
  83. case WSASYSNOTREADY: s = "WSASYSNOTREADY"; break;
  84. case WSAVERNOTSUPPORTED: s = "WSAVERNOTSUPPORTED"; break;
  85. case WSANOTINITIALISED: s = "WSANOTINITIALISED"; break;
  86. case WSAEDISCON: s = "WSAEDISCON"; break;
  87. case WSAENOMORE: s = "WSAENOMORE"; break;
  88. case WSAECANCELLED: s = "WSAECANCELLED"; break;
  89. case WSAEINVALIDPROCTABLE: s = "WSAEINVALIDPROCTABLE"; break;
  90. case WSAEINVALIDPROVIDER: s = "WSAEINVALIDPROVIDER"; break;
  91. case WSAEPROVIDERFAILEDINIT: s = "WSAEPROVIDERFAILEDINIT"; break;
  92. case WSASYSCALLFAILURE: s = "WSASYSCALLFAILURE"; break;
  93. case WSASERVICE_NOT_FOUND: s = "WSASERVICE_NOT_FOUND"; break;
  94. case WSATYPE_NOT_FOUND: s = "WSATYPE_NOT_FOUND"; break;
  95. case WSA_E_NO_MORE: s = "WSA_E_NO_MORE"; break;
  96. case WSA_E_CANCELLED: s = "WSA_E_CANCELLED"; break;
  97. case WSAEREFUSED: s = "WSAEREFUSED"; break;
  98. case WSAHOST_NOT_FOUND: s = "WSAHOST_NOT_FOUND"; break;
  99. case WSATRY_AGAIN: s = "WSATRY_AGAIN"; break;
  100. case WSANO_RECOVERY: s = "WSANO_RECOVERY"; break;
  101. case WSANO_DATA: s = "WSANO_DATA"; break;
  102. case WSA_QOS_RECEIVERS: s = "WSA_QOS_RECEIVERS"; break;
  103. case WSA_QOS_SENDERS: s = "WSA_QOS_SENDERS"; break;
  104. case WSA_QOS_NO_SENDERS: s = "WSA_QOS_NO_SENDERS"; break;
  105. case WSA_QOS_NO_RECEIVERS: s = "WSA_QOS_NO_RECEIVERS"; break;
  106. case WSA_QOS_REQUEST_CONFIRMED: s = "WSA_QOS_REQUEST_CONFIRMED"; break;
  107. case WSA_QOS_ADMISSION_FAILURE: s = "WSA_QOS_ADMISSION_FAILURE"; break;
  108. case WSA_QOS_POLICY_FAILURE: s = "WSA_QOS_POLICY_FAILURE"; break;
  109. case WSA_QOS_BAD_STYLE: s = "WSA_QOS_BAD_STYLE"; break;
  110. case WSA_QOS_BAD_OBJECT: s = "WSA_QOS_BAD_OBJECT"; break;
  111. case WSA_QOS_TRAFFIC_CTRL_ERROR: s = "WSA_QOS_TRAFFIC_CTRL_ERROR"; break;
  112. case WSA_QOS_GENERIC_ERROR: s = "WSA_QOS_GENERIC_ERROR"; break;
  113. case WSA_QOS_ESERVICETYPE: s = "WSA_QOS_ESERVICETYPE"; break;
  114. case WSA_QOS_EFLOWSPEC: s = "WSA_QOS_EFLOWSPEC"; break;
  115. case WSA_QOS_EPROVSPECBUF: s = "WSA_QOS_EPROVSPECBUF"; break;
  116. case WSA_QOS_EFILTERSTYLE: s = "WSA_QOS_EFILTERSTYLE"; break;
  117. case WSA_QOS_EFILTERTYPE: s = "WSA_QOS_EFILTERTYPE"; break;
  118. case WSA_QOS_EFILTERCOUNT: s = "WSA_QOS_EFILTERCOUNT"; break;
  119. case WSA_QOS_EOBJLENGTH: s = "WSA_QOS_EOBJLENGTH"; break;
  120. case WSA_QOS_EFLOWCOUNT: s = "WSA_QOS_EFLOWCOUNT"; break;
  121. case WSA_QOS_EPOLICYOBJ: s = "WSA_QOS_EPOLICYOBJ"; break;
  122. case WSA_QOS_EFLOWDESC: s = "WSA_QOS_EFLOWDESC"; break;
  123. case WSA_QOS_EPSFLOWSPEC: s = "WSA_QOS_EPSFLOWSPEC"; break;
  124. case WSA_QOS_EPSFILTERSPEC: s = "WSA_QOS_EPSFILTERSPEC"; break;
  125. case WSA_QOS_ESDMODEOBJ: s = "WSA_QOS_ESDMODEOBJ"; break;
  126. case WSA_QOS_ESHAPERATEOBJ: s = "WSA_QOS_ESHAPERATEOBJ"; break;
  127. case WSA_QOS_RESERVED_PETYPE: s = "WSA_QOS_RESERVED_PETYPE"; break;
  128. #ifdef WSA_QOS_EUNKOWNPSOBJ
  129. case WSA_QOS_EUNKOWNPSOBJ: s = "WSA_QOS_EUNKOWNPSOBJ"; break;
  130. #endif
  131. }
  132. Msg.append(" ");
  133. if(s) {
  134. Msg.append(s);
  135. }
  136. else {
  137. ostringstream ErrNoMsg;
  138. ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno;
  139. Msg.append(ErrNoMsg.str());
  140. }
  141. return Msg;
  142. };
  143. // Networking Constructor //////////////////////////////////////////////////////
  144. // Handles any necessary setup of Network Module resources.
  145. Networking::Networking() { // Upon initialization,
  146. if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData)) { // startup the Winsock2.0 DLL.
  147. throw InitializationError( // If that fails then throw!
  148. "Networking::Networking() if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData))"
  149. );
  150. }
  151. }
  152. // Networking Destructor ///////////////////////////////////////////////////////
  153. // Handles any necessary cleanup of Network Module resources.
  154. Networking::~Networking() { // Upon shutdown,
  155. WSACleanup(); // shutdown the Winsock DLL.
  156. }
  157. //// Emd Windows specific code
  158. ////////////////////////////////////////////////////////////////////////////////
  159. #else
  160. ////////////////////////////////////////////////////////////////////////////////
  161. //// Begin GNU specific code
  162. // Error description handling for humans.
  163. string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno.
  164. Msg.append(" "); Msg.append(strerror(Errno));
  165. return Msg;
  166. };
  167. // Networking Constructor //////////////////////////////////////////////////////
  168. // Handles any necessary setup of Network Module resources.
  169. Networking::Networking() { // Upon initialization,
  170. // Nothing So Far... // nothing special required.
  171. }
  172. // Networking Destructor ///////////////////////////////////////////////////////
  173. // Handles any necessary cleanup of Network Module resources.
  174. Networking::~Networking() { // GNU sockets cleanup,
  175. // Nothing So Far... // nothing specail to required.
  176. }
  177. //// End GNU specific code
  178. ////////////////////////////////////////////////////////////////////////////////
  179. #endif
  180. ////////////////////////////////////////////////////////////////////////////////
  181. //// Platform Agnostic Stuff
  182. //// Useful Internal Bits & Pieces /////////////////////////////////////////////
  183. const int LowestOctetMask = 0x000000FF; // The bits to look at.
  184. const int OneOctetInBits = 8; // The bits to shift.
  185. void splitIP( // Split an IP into octets.
  186. unsigned long A, // The address in host format.
  187. int& a0, // Reference to the first octet.
  188. int& a1, // Reference to the second octet.
  189. int& a2, // Reference to the third octet.
  190. int& a3 // Reference to the forth octet.
  191. ){
  192. a3 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the lowest order octet & move.
  193. a2 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move.
  194. a1 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move.
  195. a0 = A & LowestOctetMask; // Get the highest octet. That's IT!
  196. }
  197. //// IP4Address methods ////////////////////////////////////////////////////////
  198. IP4Address::operator unsigned long int() const { // Assign to unsigned long int.
  199. return IP; // Return it.
  200. }
  201. IP4Address::operator string() const { // Assign to a string.
  202. char stringbfr[IPStringBufferSize]; // Grab a temporary buffer.
  203. memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space.
  204. int a0, a1, a2, a3; // Grab some integers.
  205. splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address.
  206. sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets.
  207. return string(stringbfr); // Return a string.
  208. }
  209. //// SocketAddress methods /////////////////////////////////////////////////////
  210. // getAddress(str, len)
  211. const char* SocketAddress::getAddress(char* str) { // Get the IP address into a cstring.
  212. if(NULL == str) { // If the caller did not provide a
  213. str = IPStringBuffer; // buffer to use then we will use ours.
  214. }
  215. int a0, a1, a2, a3, i=0; // Grab a bunch of handy integers.
  216. getAddress(a0, a1, a2, a3); // Get the address as octets.
  217. sprintf(str, "%d.%d.%d.%d", a0, a1, a2, a3); // Format as dotted decimal notation.
  218. return str; // Return the output buffer.
  219. }
  220. // getAddress(int& a0, int& a1, int& a2, int& a3)
  221. void SocketAddress::getAddress(int& a0, int& a1, int& a2, int& a3) { // Get the IP address into 4 ints
  222. unsigned long A = getAddress(); // Get the address.
  223. splitIP(A, a0, a1, a2, a3); // Split it into octets.
  224. }
  225. //// TCPListener methods ///////////////////////////////////////////////////////
  226. TCPListener::TCPListener(unsigned short Port) { // Set up localhost on this Port.
  227. LocalAddress.setPort(Port); // Establish the port.
  228. LocalAddress.setAddress(LOCALHOST); // Set the address to LOCALHOST.
  229. MaxPending = DefaultMaxPending; // Use the default inbound queue size.
  230. ReuseAddress = true; // ReuseAddress on by default.
  231. OpenStage1Complete = false; // This stage of open() not yet done.
  232. OpenStage2Complete = false; // This stage of open() not yet done.
  233. // Create a socket...
  234. LastError = 0;
  235. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  236. if(INVALID_SOCKET == Handle) { // If that operation failed then
  237. LastError = Network.getLastError(); // grab the error code and
  238. throw Networking::SocketCreationError( // throw.
  239. Network.DescriptiveError(
  240. "TCPListener::open().socket()", LastError));
  241. }
  242. }
  243. TCPListener::TCPListener(SocketAddress& WhereToBind) { // Set up specific "name" for listening.
  244. LocalAddress = WhereToBind; // Make my Local address as provided.
  245. MaxPending = DefaultMaxPending; // Use the default inbound queue size.
  246. ReuseAddress = true; // ReuseAddress on by default.
  247. OpenStage1Complete = false; // This stage of open() not yet done.
  248. OpenStage2Complete = false; // This stage of open() not yet done.
  249. // Create a socket...
  250. LastError = 0;
  251. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  252. if(INVALID_SOCKET == Handle) { // If that operation failed then
  253. LastError = Network.getLastError(); // grab the error code and
  254. throw Networking::SocketCreationError( // throw.
  255. Network.DescriptiveError(
  256. "TCPListener::open().socket()", LastError));
  257. }
  258. }
  259. // open()
  260. void TCPListener::open() { // Open when ready.
  261. if(OpenSucceeded) return; // If open already, we're done.
  262. LastError = 0; // Clear the last error.
  263. bool SuccessFlag = true; // Start optimistically.
  264. // Set SO_REUSEADDR if turned on
  265. if(!OpenStage1Complete) { // Do this stage only once.
  266. int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag.
  267. int result = // Set SO_REUSEADDR before bind().
  268. setsockopt(
  269. Handle,
  270. SOL_SOCKET,
  271. SO_REUSEADDR,
  272. (char*) &ReuseAddress_Flag,
  273. sizeof(ReuseAddress_Flag));
  274. if(0 > result) { // If there was an error then
  275. SuccessFlag = false; // we did not succeed.
  276. LastError = Network.getLastError(); // Capture the error information and
  277. throw Networking::SocketSetSockOptError( // throw.
  278. Network.DescriptiveError(
  279. "TCPListener::open().setsockopt()", LastError));
  280. }
  281. OpenStage1Complete = true; // Stage 1 complete now.
  282. } // End of open() stage 1
  283. // Next we bind it...
  284. if(!OpenStage2Complete) { // Do this stage only once.
  285. int result = // Bind our socket to the LocalAddress.
  286. bind(
  287. Handle,
  288. LocalAddress.getPtr_sockaddr(),
  289. LocalAddress.getAddressSize());
  290. if(0 > result) { // If there was an error then
  291. SuccessFlag = false; // we did not succeed.
  292. LastError = Network.getLastError(); // Capture the error information and
  293. throw Networking::SocketBindError( // throw.
  294. Network.DescriptiveError(
  295. "TCPListener::open().bind()", LastError));
  296. }
  297. OpenStage2Complete = true; // Stage 2 complete now.
  298. } // End of open() stage 2
  299. // Then we put it in a listening state...
  300. int result = listen(Handle, MaxPending); // Listen for up to MaxPending at once.
  301. if(0 > result) { // If an error occurred then
  302. SuccessFlag = false; // we did not succeed.
  303. LastError = Network.getLastError(); // Capture the error information and
  304. throw Networking::SocketListenError( // throw.
  305. Network.DescriptiveError(
  306. "TCPListener::open().listen()", LastError));
  307. }
  308. OpenSucceeded = SuccessFlag; // So, did we succeed?
  309. }
  310. // acceptClient()
  311. TCPClient* TCPListener::acceptClient() { // Accept a client connection.
  312. LastError = 0; // Clear the last error.
  313. socklen_t rsize = RemoteAddress.getAddressSize(); // Size as an int for accept().
  314. hSocket NewHandle = // Accept a new connection if available.
  315. accept(
  316. Handle, // use our handle, of course,...
  317. RemoteAddress.getPtr_sockaddr(), // and store the remote hosts
  318. &rsize); // address for us.
  319. if(INVALID_SOCKET == NewHandle) { // If there was an error then
  320. LastError = Network.getLastError(); // capture the error value.
  321. if(!Network.WouldBlock(LastError)) { // If it's not a EWOULDBLOCK error
  322. throw Networking::SocketAcceptError( // then we need to throw.
  323. Network.DescriptiveError(
  324. "TCPListener::acceptClient()", LastError));
  325. } else { // EWOULDBLOCK errors are normal in
  326. return NULL; // non blocking mode so we return
  327. } // NULL when we see them.
  328. }
  329. // If things have gone well we can do what we came for.
  330. return new TCPClient(*this, NewHandle, RemoteAddress); // Create the new TCPClient object.
  331. }
  332. //// TCPClient methods /////////////////////////////////////////////////////////
  333. int TCPClient::transmit(const char* bfr, int size) { // How to send a buffer of data.
  334. LastError = 0; // No errors yet.
  335. if(0 == size) return 0; // Nothing to send, send nothing.
  336. if(0 == bfr) // Watch out for null buffers.
  337. throw Networking::SocketWriteError("TCPClient::transmit() NULL Bfr!");
  338. if(0 > size) // Watch out for bad sizes.
  339. throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!");
  340. int ByteCount = send(Handle, bfr, size, NOFLAGS); // Try to send and capture the count.
  341. if(0 > ByteCount) ByteCount = 0; // Mask error results as 0 bytes sent.
  342. if(size > ByteCount) { // If we didn't send it all check it out.
  343. LastError = Network.getLastError(); // Grab the error code.
  344. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  345. return ByteCount; // it was a partial send - return.
  346. } else { // If this was a different kind of error
  347. throw Networking::SocketWriteError( // then throw!
  348. Network.DescriptiveError(
  349. "TCPClient::transmit()", LastError));
  350. }
  351. }
  352. return ByteCount; // Ultimately return the byte count.
  353. }
  354. int TCPClient::receive(char* bfr, int size) { // How to receive a buffer of data.
  355. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  356. fillReadBuffer(); // fill it first.
  357. } // Optimize our transfer to the smaller
  358. if(DataLength < size) { // of what we have or the size of the
  359. size = DataLength; // provided buffer. This way we ony check
  360. } // one value in our copy loop ;-)
  361. int RemainingDataLength = size; // Capture the length of data to xfer.
  362. while(0 < RemainingDataLength) { // While we have work to do
  363. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  364. bfr++; ReadPointer++; // move the pointers to the next byte,
  365. DataLength--; // update our ReadBuffers's DataLength,
  366. RemainingDataLength--; // and count down the bytes left to xfer.
  367. }
  368. return size; // When done, say how much we moved.
  369. }
  370. int TCPClient::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data.
  371. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  372. fillReadBuffer(); // fill it first.
  373. } // Optimize our transfer to the smaller
  374. if(DataLength < size) { // of what we have or the size of the
  375. size = DataLength; // provided buffer. This way we ony check
  376. } // one value in our copy loop ;-)
  377. int Count = 0; // Keep our byte count in scope.
  378. bool DelimiterNotReached = true; // Watching for our deliimiter.
  379. while((Count < size) && DelimiterNotReached) { // While there is work to do...
  380. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  381. DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character,
  382. bfr++; ReadPointer++; // move the pointers to the next byte,
  383. DataLength--; // update our ReadBuffers's DataLength,
  384. Count++; // and count up the bytes we have moved.
  385. }
  386. return Count; // When done, say how much we moved.
  387. }
  388. //// TCPHost methods ///////////////////////////////////////////////////////////
  389. // Constructors...
  390. TCPHost::TCPHost(unsigned short Port) { // Will connect to localhost on Port.
  391. RemoteAddress.setPort(Port); // Connect to Port on
  392. RemoteAddress.setAddress(LOCALHOST); // Localhost.
  393. ReadPointer = ReadBuffer; // Set the read position to zero.
  394. DataLength = 0; // There is no data yet.
  395. ReuseAddress = false; // ReuseAddress off by default.
  396. OpenStage1Complete = false; // Stage 1 of open() not done yet.
  397. // Create a socket to use.
  398. LastError = 0; // Clear our last error value.
  399. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  400. if(0 > Handle) { // If that operation failed then
  401. LastError = Network.getLastError(); // grab the error code and
  402. throw Networking::SocketCreationError( // throw.
  403. Network.DescriptiveError(
  404. "TCPHost::open().socket()", LastError));
  405. }
  406. }
  407. TCPHost::TCPHost(SocketAddress& Remote) { // Will connect to Remote address/port.
  408. RemoteAddress = Remote; // Capture the provided address.
  409. ReadPointer = ReadBuffer; // Set the read position to zero.
  410. DataLength = 0; // There is no data yet.
  411. ReuseAddress = false; // ReuseAddress off by default.
  412. OpenStage1Complete = false; // Stage 1 of open() not done yet.
  413. // Create a socket to use.
  414. LastError = 0; // Clear our last error value.
  415. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  416. if(0 > Handle) { // If that operation failed then
  417. LastError = Network.getLastError(); // grab the error code and
  418. throw Networking::SocketCreationError( // throw.
  419. Network.DescriptiveError(
  420. "TCPHost::open().socket()", LastError));
  421. }
  422. }
  423. // Methods...
  424. void TCPHost::open() { // We provide open().
  425. if(OpenSucceeded) return; // If open already, we're done.
  426. LastError = 0; // Clear our LastError value.
  427. bool SuccessFlag = true; // Begin optimistically.
  428. // Set SO_REUSEADDR if turned on
  429. if(!OpenStage1Complete) { // If we haven't done this yet:
  430. int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag.
  431. int result = // Set SO_REUSEADDR before bind().
  432. setsockopt(
  433. Handle,
  434. SOL_SOCKET,
  435. SO_REUSEADDR,
  436. (char *)&ReuseAddress_Flag,
  437. sizeof(ReuseAddress_Flag));
  438. if(0 > result) { // If there was an error then
  439. SuccessFlag = false; // we did not succeed.
  440. LastError = Network.getLastError(); // Capture the error information and
  441. throw Networking::SocketSetSockOptError( // throw.
  442. Network.DescriptiveError(
  443. "TCPListener::open().setsockopt()", LastError));
  444. }
  445. OpenStage1Complete = true; // Skip this section from now on.
  446. } // Done with stage 1.
  447. // Connect the socekt to the Host.
  448. int result = // Connect to the remote host
  449. connect( // using the socket we just
  450. Handle, // stored in Handle and
  451. RemoteAddress.getPtr_sockaddr(), // the Remote address.
  452. RemoteAddress.getAddressSize());
  453. if(0 > result) { // If there was an error then
  454. SuccessFlag = false; // we did not succeed.
  455. LastError = Network.getLastError(); // Record the error data.
  456. if(Network.IsConnected(LastError)) { // If we actually did succeed then
  457. SuccessFlag = true; // say so. (Silly Winsock!)
  458. } else // But if that's not the case check
  459. if( // to see if something bad happened -
  460. !Network.WouldBlock(LastError) && // not just would-block, or
  461. !Network.InProgress(LastError) // in progress...
  462. ) { // If it was something other than
  463. throw Networking::SocketConnectError( // WouldBlock or InProgress then
  464. Network.DescriptiveError( // throw!
  465. "TCPHost::open().connect()", LastError));
  466. } // If it was WouldBlock then it's
  467. } // considered to be ok.
  468. OpenSucceeded = SuccessFlag; // So, are we open now?
  469. }
  470. int TCPHost::transmit(const char* bfr, int size) { // How to send a buffer of data.
  471. LastError = 0; // No errors yet.
  472. if(0 == size) return 0; // Nothing to send, send nothing.
  473. if(0 == bfr) // Watch out for null buffers.
  474. throw Networking::SocketWriteError("TCPHost::transmit() NULL Bfr!");
  475. if(0 > size) // Watch out for bad sizes.
  476. throw Networking::SocketWriteError("TCPHost::transmit() 0 > size!");
  477. int ByteCount = send(Handle, bfr, size, NOFLAGS); // Try to send and capture the count.
  478. if(0 > ByteCount) ByteCount = 0; // Mask error results as 0 bytes sent.
  479. if(size > ByteCount) { // If we didn't send it all check it out.
  480. LastError = Network.getLastError(); // Grab the error code.
  481. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  482. return ByteCount; // it was a partial snd - return.
  483. } else { // If this was a different kind of error
  484. throw Networking::SocketWriteError( // then throw!
  485. Network.DescriptiveError(
  486. "TCPHost::transmit().send()", LastError));
  487. }
  488. }
  489. return ByteCount; // Ultimately return the byte count.
  490. }
  491. int TCPHost::receive(char* bfr, int size) { // How to receive a buffer of data.
  492. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  493. fillReadBuffer(); // fill it first.
  494. } // Optimize our transfer to the smaller
  495. if(DataLength < size) { // of what we have or the size of the
  496. size = DataLength; // provided buffer. This way we ony check
  497. } // one value in our copy loop ;-)
  498. int RemainingDataLength = size; // Capture the length of data to xfer.
  499. while(0 < RemainingDataLength) { // While we have work to do
  500. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  501. bfr++; ReadPointer++; // move the pointers to the next byte,
  502. DataLength--; // update our ReadBuffers's DataLength,
  503. RemainingDataLength--; // and count down the bytes left to xfer.
  504. }
  505. return size; // When done, say how much we moved.
  506. }
  507. int TCPHost::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data.
  508. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  509. fillReadBuffer(); // fill it first.
  510. } // Optimize our transfer to the smaller
  511. if(DataLength < size) { // of what we have or the size of the
  512. size = DataLength; // provided buffer. This way we ony check
  513. } // one value in our copy loop ;-)
  514. int Count = 0; // Keep our byte count in scope.
  515. bool DelimiterNotReached = true; // Watching for our deliimiter.
  516. while((Count < size) && DelimiterNotReached) { // While there is work to do...
  517. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  518. DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character,
  519. bfr++; ReadPointer++; // move the pointers to the next byte,
  520. DataLength--; // update our ReadBuffers's DataLength,
  521. Count++; // and count up the bytes we have moved.
  522. }
  523. return Count; // When done, say how much we moved.
  524. }
  525. // End Platform Agnostic Stuff
  526. ////////////////////////////////////////////////////////////////////////////////