You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

networking.cpp 62KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  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. #include "networking.hpp"
  23. namespace codedweller {
  24. Networking Network; // Creating _THE_ Network instance.
  25. #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
  26. int Networking::getLastError() { // In windows you get the last error
  27. return WSAGetLastError(); // from WSAGetLastError();
  28. }
  29. int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking
  30. unsigned long nonblocking = 1; // Create a flag...
  31. int result = 0;
  32. if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket.
  33. result = -1; // If that fails then return -1.
  34. }
  35. return result; // Show 'em my motto!
  36. }
  37. int Networking::closeSocket(hSocket socket) { // Close a socket in winsock
  38. return closesocket(socket); // wraps closesocket().
  39. }
  40. bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
  41. return (WSAEWOULDBLOCK == ErrorCode);
  42. }
  43. bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
  44. return( // [WSA]EALREADY also returns true.
  45. WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could
  46. WSAEALREADY == ErrorCode || // get any of these when retesting
  47. WSAEWOULDBLOCK == ErrorCode || // open() for a connection.
  48. WSAEINVAL == ErrorCode
  49. );
  50. }
  51. bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
  52. return(WSAEISCONN == ErrorCode);
  53. }
  54. #else
  55. //// GNU platform
  56. int Networking::getLastError() { // In GNU you get the last error
  57. return errno; // from errno;
  58. }
  59. int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking
  60. int flags, result; // Grab a place to hold the flags.
  61. flags = fcntl(socket, F_GETFL, 0); // Get the current flags.
  62. result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return.
  63. return result; // Return the result.
  64. }
  65. int Networking::closeSocket(hSocket socket) { // Close a socket in GNU
  66. return close(socket); // wraps close().
  67. }
  68. bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
  69. return (EWOULDBLOCK == ErrorCode);
  70. }
  71. bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
  72. return( // [WSA]EALREADY also returns true.
  73. EINPROGRESS == ErrorCode ||
  74. EALREADY == ErrorCode
  75. );
  76. }
  77. bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
  78. return(EISCONN == ErrorCode);
  79. }
  80. #endif
  81. // End Platform Specific
  82. ////////////////////////////////////////////////////////////////////////////////
  83. // Begin Platform Agnostic
  84. //// class IP4Address //////////////////////////////////////////////////////////
  85. IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0
  86. IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long
  87. IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address
  88. IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring.
  89. IP4Address::IP4Address(const std::string& newIP) { (*this) = newIP; } // Constructing with a cppstring.
  90. IP4Address& IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int.
  91. IP = Right;
  92. return *this;
  93. }
  94. IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string.
  95. IP = ntohl(inet_addr(Right));
  96. return *this;
  97. }
  98. IP4Address& IP4Address::operator=(const std::string& Right) { // Convert from cpp string.
  99. IP = ntohl(inet_addr(Right.c_str()));
  100. return *this;
  101. }
  102. bool IP4Address::operator<(const IP4Address Right) const { // < Comparison.
  103. return (IP < Right.IP);
  104. }
  105. bool IP4Address::operator>(const IP4Address Right) const { // > Comparison.
  106. return (IP > Right.IP);
  107. }
  108. bool IP4Address::operator==(const IP4Address Right) const { // == Comparison.
  109. return (IP == Right.IP);
  110. }
  111. bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison.
  112. return (IP != Right.IP);
  113. }
  114. bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison.
  115. return (IP <= Right.IP);
  116. }
  117. bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison.
  118. return (IP >= Right.IP);
  119. }
  120. //// class SocketAddress ///////////////////////////////////////////////////////
  121. void SocketAddress::clear() {
  122. memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture
  123. Address.sin_family = AF_INET; // Internet Address Family ip4
  124. Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address
  125. Address.sin_port = 0; // Zero means any port.
  126. }
  127. SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards
  128. clear(); // Conveniently, we can use clear() :-)
  129. }
  130. struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in.
  131. return &Address; // Simply return it's address.
  132. }
  133. struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr.
  134. return (struct sockaddr*) &Address;
  135. }
  136. socklen_t SocketAddress::getAddressSize() {
  137. return sizeof(Address); // Return the size of the structure.
  138. }
  139. void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int
  140. Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign.
  141. }
  142. void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring
  143. Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign.
  144. }
  145. unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int
  146. return ntohl(Address.sin_addr.s_addr); // Convert to host order and return.
  147. }
  148. void SocketAddress::setPort(unsigned short port) { // Set the port address from an int
  149. Address.sin_port = htons(port); // Convert to network order and set.
  150. }
  151. void SocketAddress::setPort(char* port) { // Set the port address from a cstring
  152. setPort(atoi(port)); // Convert to int and set.
  153. }
  154. unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int
  155. return ntohs(Address.sin_port); // Convert to host order and return.
  156. }
  157. const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring.
  158. if(NULL == str) { // If the caller did not provide a
  159. str = PortStringBuffer; // buffer to use then we will use ours.
  160. }
  161. sprintf(str,"%d",getPort()); // Get the port and convert to cstring.
  162. return str; // Return the string we got.
  163. }
  164. //// class Socket //////////////////////////////////////////////////////////////
  165. Socket::Socket() : // When starting up we are
  166. Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid.
  167. }
  168. Socket::~Socket() { // When shutting down, be sure
  169. if(INVALID_SOCKET != Handle) { // any open socket is closed without
  170. Network.closeSocket(Handle); // throwing any exceptions.
  171. }
  172. }
  173. void Socket::close() { // When we close,
  174. if(INVALID_SOCKET != Handle) { // If the handle is open then
  175. if(Network.closeSocket(Handle)) { // close the handle and check for error.
  176. LastError = Network.getLastError(); // If there was an error record it.
  177. if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
  178. throw Networking::ControlError( // then throw a ControlError exception.
  179. Network.DescriptiveError(
  180. "Socket::close()", LastError));
  181. }
  182. } else { // If there was no error then
  183. LastError = 0; // reset the LastError value.
  184. }
  185. Handle = INVALID_SOCKET; // and reset the handle to INVALID.
  186. NonBlocking = false; // The default is Blocking.
  187. OpenSucceeded = false; // After close, forget we opened.
  188. }
  189. }
  190. hSocket Socket::getHandle() { // Returns the current Socket handle.
  191. return Handle;
  192. }
  193. bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
  194. return NonBlocking;
  195. }
  196. void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
  197. if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
  198. LastError = Network.getLastError(); // If it didn't work, go get the error.
  199. NonBlocking = false; // We are NOT NonBlocking.
  200. throw Networking::ControlError( // Throw a control error.
  201. Network.DescriptiveError(
  202. "Socket::makeNonBlocking()", LastError));
  203. } else {
  204. NonBlocking = true; // If we didn't throw, we're ON.
  205. }
  206. }
  207. bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
  208. bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.
  209. bool Socket::isOpen() { // True if the socket is open.
  210. return(
  211. INVALID_SOCKET != Handle && // A valid handle and
  212. true == OpenSucceeded // a successful open operation
  213. ); // means we're open.
  214. }
  215. int Socket::getLastError() { // Returns the last error for this socket.
  216. return LastError;
  217. }
  218. //// class TCPClient ///////////////////////////////////////////////////////////
  219. TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
  220. MyListener(L) { // Capture our listener.
  221. Handle = H; // Capture the new socket handle.
  222. RemoteAddress = A; // Capture the client address.
  223. ReadPointer = ReadBuffer; // Set the read position to zero.
  224. DataLength = 0; // There is no data yet.
  225. OpenSucceeded = true; // We're getting an open socket.
  226. }
  227. TCPClient::~TCPClient() { // When destroying a TCPClient
  228. try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections.
  229. }
  230. void TCPClient::open() { // We provide open() as unsupported.
  231. throw Networking::NotSupportedError( // Throw an exception if this is called.
  232. Network.DescriptiveError(
  233. "TCPClient::open()", LastError));
  234. }
  235. bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  236. return (0 >= DataLength); // We can check that with DataLength.
  237. }
  238. void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
  239. LastError = 0; // Clear the LastError value.
  240. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  241. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
  242. if(0 >= DataLength) { // If there was an error then
  243. LastError = Network.getLastError(); // Grab the last error code.
  244. DataLength = 0; // Correct the DataLength.
  245. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  246. return; // simply return - it's ok.
  247. } else { // If it was a different error
  248. throw Networking::SocketReadError( // then throw a ReadError.
  249. Network.DescriptiveError(
  250. "TCPClient::fillReadBuffer()", LastError));
  251. }
  252. } // If we succeeded then our ReadBuffer
  253. } // assembly is in good shape.
  254. bool TCPClient::isNonBlocking() { // Provided for MessagePort.
  255. return Socket::isNonBlocking();
  256. }
  257. unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
  258. return RemoteAddress.getAddress();
  259. }
  260. const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
  261. return RemoteAddress.getAddress(str);
  262. }
  263. unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
  264. return RemoteAddress.getPort();
  265. }
  266. const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
  267. return RemoteAddress.getPort(str);
  268. }
  269. //// class TCPHost /////////////////////////////////////////////////////////////
  270. TCPHost::~TCPHost() { // When destroying a TCPHost
  271. try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection.
  272. }
  273. bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
  274. return (0 >= DataLength); // We can check that with DataLength.
  275. }
  276. void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
  277. LastError = 0; // Clear the LastError value.
  278. ReadPointer = ReadBuffer; // Reset the ReadPointer.
  279. DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.
  280. if(0 >= DataLength) { // If there was an error then
  281. LastError = Network.getLastError(); // Grab the last error code.
  282. DataLength = 0; // Correct the DataLength.
  283. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  284. return; // simply return - it's ok.
  285. } else { // If it was a different error
  286. throw Networking::SocketReadError( // then throw a ReadError.
  287. Network.DescriptiveError(
  288. "TCPHost::fillReadBuffer()", LastError));
  289. }
  290. } // If we succeeded then our ReadBuffer
  291. } // assembly is in good shape.
  292. bool TCPHost::isNonBlocking() { // Provided for MessagePort.
  293. return Socket::isNonBlocking();
  294. }
  295. //// class TCPListener /////////////////////////////////////////////////////////
  296. TCPListener::~TCPListener() { // When destroying a TCPListener
  297. try{ close(); } catch(...) {} // silently close if not already done.
  298. }
  299. //// Platform Specific Stuff ///////////////////////////////////////////////////
  300. #if defined(WIN32) || defined(WIN64)
  301. ////////////////////////////////////////////////////////////////////////////////
  302. //// Being Windows specific code
  303. WSADATA WSSTartData; // Socket library data structure.
  304. // Error description handling for humans.
  305. string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno.
  306. string s = ""; // Message string.
  307. switch(Errno) { // Assign the appropriate message.
  308. case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break;
  309. case WSA_NOT_ENOUGH_MEMORY: s = "WSA_NOT_ENOUGH_MEMORY"; break;
  310. case WSA_INVALID_PARAMETER: s = "WSA_INVALID_PARAMETER"; break;
  311. case WSA_OPERATION_ABORTED: s = "WSA_OPERATION_ABORTED"; break;
  312. case WSA_IO_INCOMPLETE: s = "WSA_IO_INCOMPLETE"; break;
  313. case WSA_IO_PENDING: s = "WSA_IO_PENDING"; break;
  314. case WSAEINTR: s = "WSAEINTR"; break;
  315. case WSAEBADF: s = "WSAEBADF"; break;
  316. case WSAEACCES: s = "WSAEACCES"; break;
  317. case WSAEFAULT: s = "WSAEFAULT"; break;
  318. case WSAEINVAL: s = "WSAEINVAL"; break;
  319. case WSAEMFILE: s = "WSAEMFILE"; break;
  320. case WSAEWOULDBLOCK: s = "WSAEWOULDBLOCK"; break;
  321. case WSAEINPROGRESS: s = "WSAEINPROGRESS"; break;
  322. case WSAEALREADY: s = "WSAEALREADY"; break;
  323. case WSAENOTSOCK: s = "WSAENOTSOCK"; break;
  324. case WSAEDESTADDRREQ: s = "WSAEDESTADDRREQ"; break;
  325. case WSAEMSGSIZE: s = "WSAEMSGSIZE"; break;
  326. case WSAEPROTOTYPE: s = "WSAEPROTOTYPE"; break;
  327. case WSAENOPROTOOPT: s = "WSAENOPROTOOPT"; break;
  328. case WSAEPROTONOSUPPORT: s = "WSAEPROTONOSUPPORT"; break;
  329. case WSAESOCKTNOSUPPORT: s = "WSAESOCKTNOSUPPORT"; break;
  330. case WSAEOPNOTSUPP: s = "WSAEOPNOTSUPP"; break;
  331. case WSAEPFNOSUPPORT: s = "WSAEPFNOSUPPORT"; break;
  332. case WSAEAFNOSUPPORT: s = "WSAEAFNOSUPPORT"; break;
  333. case WSAEADDRINUSE: s = "WSAEADDRINUSE"; break;
  334. case WSAEADDRNOTAVAIL: s = "WSAEADDRNOTAVAIL"; break;
  335. case WSAENETDOWN: s = "WSAENETDOWN"; break;
  336. case WSAENETUNREACH: s = "WSAENETUNREACH"; break;
  337. case WSAENETRESET: s = "WSAENETRESET"; break;
  338. case WSAECONNABORTED: s = "WSAECONNABORTED"; break;
  339. case WSAECONNRESET: s = "WSAECONNRESET"; break;
  340. case WSAENOBUFS: s = "WSAENOBUFS"; break;
  341. case WSAEISCONN: s = "WSAEISCONN"; break;
  342. case WSAENOTCONN: s = "WSAENOTCONN"; break;
  343. case WSAESHUTDOWN: s = "WSAESHUTDOWN"; break;
  344. case WSAETOOMANYREFS: s = "WSAETOOMANYREFS"; break;
  345. case WSAETIMEDOUT: s = "WSAETIMEDOUT"; break;
  346. case WSAECONNREFUSED: s = "WSAECONNREFUSED"; break;
  347. case WSAELOOP: s = "WSAELOOP"; break;
  348. case WSAENAMETOOLONG: s = "WSAENAMETOOLONG"; break;
  349. case WSAEHOSTDOWN: s = "WSAEHOSTDOWN"; break;
  350. case WSAEHOSTUNREACH: s = "WSAEHOSTUNREACH"; break;
  351. case WSAENOTEMPTY: s = "WSAENOTEMPTY"; break;
  352. case WSAEPROCLIM: s = "WSAEPROCLIM"; break;
  353. case WSAEUSERS: s = "WSAEUSERS"; break;
  354. case WSAEDQUOT: s = "WSAEDQUOT"; break;
  355. case WSAESTALE: s = "WSAESTALE"; break;
  356. case WSAEREMOTE: s = "WSAEREMOTE"; break;
  357. case WSASYSNOTREADY: s = "WSASYSNOTREADY"; break;
  358. case WSAVERNOTSUPPORTED: s = "WSAVERNOTSUPPORTED"; break;
  359. case WSANOTINITIALISED: s = "WSANOTINITIALISED"; break;
  360. case WSAEDISCON: s = "WSAEDISCON"; break;
  361. case WSAENOMORE: s = "WSAENOMORE"; break;
  362. case WSAECANCELLED: s = "WSAECANCELLED"; break;
  363. case WSAEINVALIDPROCTABLE: s = "WSAEINVALIDPROCTABLE"; break;
  364. case WSAEINVALIDPROVIDER: s = "WSAEINVALIDPROVIDER"; break;
  365. case WSAEPROVIDERFAILEDINIT: s = "WSAEPROVIDERFAILEDINIT"; break;
  366. case WSASYSCALLFAILURE: s = "WSASYSCALLFAILURE"; break;
  367. case WSASERVICE_NOT_FOUND: s = "WSASERVICE_NOT_FOUND"; break;
  368. case WSATYPE_NOT_FOUND: s = "WSATYPE_NOT_FOUND"; break;
  369. case WSA_E_NO_MORE: s = "WSA_E_NO_MORE"; break;
  370. case WSA_E_CANCELLED: s = "WSA_E_CANCELLED"; break;
  371. case WSAEREFUSED: s = "WSAEREFUSED"; break;
  372. case WSAHOST_NOT_FOUND: s = "WSAHOST_NOT_FOUND"; break;
  373. case WSATRY_AGAIN: s = "WSATRY_AGAIN"; break;
  374. case WSANO_RECOVERY: s = "WSANO_RECOVERY"; break;
  375. case WSANO_DATA: s = "WSANO_DATA"; break;
  376. case WSA_QOS_RECEIVERS: s = "WSA_QOS_RECEIVERS"; break;
  377. case WSA_QOS_SENDERS: s = "WSA_QOS_SENDERS"; break;
  378. case WSA_QOS_NO_SENDERS: s = "WSA_QOS_NO_SENDERS"; break;
  379. case WSA_QOS_NO_RECEIVERS: s = "WSA_QOS_NO_RECEIVERS"; break;
  380. case WSA_QOS_REQUEST_CONFIRMED: s = "WSA_QOS_REQUEST_CONFIRMED"; break;
  381. case WSA_QOS_ADMISSION_FAILURE: s = "WSA_QOS_ADMISSION_FAILURE"; break;
  382. case WSA_QOS_POLICY_FAILURE: s = "WSA_QOS_POLICY_FAILURE"; break;
  383. case WSA_QOS_BAD_STYLE: s = "WSA_QOS_BAD_STYLE"; break;
  384. case WSA_QOS_BAD_OBJECT: s = "WSA_QOS_BAD_OBJECT"; break;
  385. case WSA_QOS_TRAFFIC_CTRL_ERROR: s = "WSA_QOS_TRAFFIC_CTRL_ERROR"; break;
  386. case WSA_QOS_GENERIC_ERROR: s = "WSA_QOS_GENERIC_ERROR"; break;
  387. case WSA_QOS_ESERVICETYPE: s = "WSA_QOS_ESERVICETYPE"; break;
  388. case WSA_QOS_EFLOWSPEC: s = "WSA_QOS_EFLOWSPEC"; break;
  389. case WSA_QOS_EPROVSPECBUF: s = "WSA_QOS_EPROVSPECBUF"; break;
  390. case WSA_QOS_EFILTERSTYLE: s = "WSA_QOS_EFILTERSTYLE"; break;
  391. case WSA_QOS_EFILTERTYPE: s = "WSA_QOS_EFILTERTYPE"; break;
  392. case WSA_QOS_EFILTERCOUNT: s = "WSA_QOS_EFILTERCOUNT"; break;
  393. case WSA_QOS_EOBJLENGTH: s = "WSA_QOS_EOBJLENGTH"; break;
  394. case WSA_QOS_EFLOWCOUNT: s = "WSA_QOS_EFLOWCOUNT"; break;
  395. case WSA_QOS_EPOLICYOBJ: s = "WSA_QOS_EPOLICYOBJ"; break;
  396. case WSA_QOS_EFLOWDESC: s = "WSA_QOS_EFLOWDESC"; break;
  397. case WSA_QOS_EPSFLOWSPEC: s = "WSA_QOS_EPSFLOWSPEC"; break;
  398. case WSA_QOS_EPSFILTERSPEC: s = "WSA_QOS_EPSFILTERSPEC"; break;
  399. case WSA_QOS_ESDMODEOBJ: s = "WSA_QOS_ESDMODEOBJ"; break;
  400. case WSA_QOS_ESHAPERATEOBJ: s = "WSA_QOS_ESHAPERATEOBJ"; break;
  401. case WSA_QOS_RESERVED_PETYPE: s = "WSA_QOS_RESERVED_PETYPE"; break;
  402. #ifdef WSA_QOS_EUNKOWNPSOBJ
  403. case WSA_QOS_EUNKOWNPSOBJ: s = "WSA_QOS_EUNKOWNPSOBJ"; break;
  404. #endif
  405. }
  406. Msg.append(" "); // Add a space to the existing message.
  407. if(0 < s.length()) { // If we know the message for Errno
  408. Msg.append(s); // then append it.
  409. }
  410. else { // If we don't know what Errno means
  411. std::ostringstream ErrNoMsg; // then say so and pass on Errno as
  412. ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out.
  413. Msg.append(ErrNoMsg.str());
  414. }
  415. return Msg;
  416. };
  417. // Networking Constructor //////////////////////////////////////////////////////
  418. // Handles any necessary setup of Network Module resources.
  419. Networking::Networking() { // Upon initialization,
  420. if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData)) { // startup the Winsock2.0 DLL.
  421. throw InitializationError( // If that fails then throw!
  422. "Networking::Networking() if(0 != WSAStartup(MAKEWORD (2,0), &WSSTartData))"
  423. );
  424. }
  425. }
  426. // Networking Destructor ///////////////////////////////////////////////////////
  427. // Handles any necessary cleanup of Network Module resources.
  428. Networking::~Networking() { // Upon shutdown,
  429. WSACleanup(); // shutdown the Winsock DLL.
  430. }
  431. //// Emd Windows specific code
  432. ////////////////////////////////////////////////////////////////////////////////
  433. #else
  434. ////////////////////////////////////////////////////////////////////////////////
  435. //// Begin GNU specific code
  436. // Error description handling for humans.
  437. std::string Networking::DescriptiveError(std::string Msg, int Errno) { // Form a descriptive error w/ errno.
  438. Msg.append(" "); Msg.append(strerror(Errno));
  439. return Msg;
  440. };
  441. // Networking Constructor //////////////////////////////////////////////////////
  442. // Handles any necessary setup of Network Module resources.
  443. Networking::Networking() { // Upon initialization,
  444. // Nothing So Far... // nothing special required.
  445. }
  446. // Networking Destructor ///////////////////////////////////////////////////////
  447. // Handles any necessary cleanup of Network Module resources.
  448. Networking::~Networking() { // GNU sockets cleanup,
  449. // Nothing So Far... // nothing specail to required.
  450. }
  451. //// End GNU specific code
  452. ////////////////////////////////////////////////////////////////////////////////
  453. #endif
  454. ////////////////////////////////////////////////////////////////////////////////
  455. //// Platform Agnostic Stuff
  456. //// Useful Internal Bits & Pieces /////////////////////////////////////////////
  457. const int LowestOctetMask = 0x000000FF; // The bits to look at.
  458. const int OneOctetInBits = 8; // The bits to shift.
  459. void splitIP( // Split an IP into octets.
  460. unsigned long A, // The address in host format.
  461. int& a0, // Reference to the first octet.
  462. int& a1, // Reference to the second octet.
  463. int& a2, // Reference to the third octet.
  464. int& a3 // Reference to the forth octet.
  465. ){
  466. a3 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the lowest order octet & move.
  467. a2 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move.
  468. a1 = A & LowestOctetMask; A >>= OneOctetInBits; // Get the next lowest octet & move.
  469. a0 = A & LowestOctetMask; // Get the highest octet. That's IT!
  470. }
  471. //// IP4Address methods ////////////////////////////////////////////////////////
  472. IP4Address::operator unsigned long int() const { // Assign to unsigned long int.
  473. return IP; // Return it.
  474. }
  475. IP4Address::operator std::string() const { // Assign to a string.
  476. char stringbfr[IPStringBufferSize]; // Grab a temporary buffer.
  477. memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space.
  478. int a0, a1, a2, a3; // Grab some integers.
  479. splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address.
  480. sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets.
  481. return std::string(stringbfr); // Return a string.
  482. }
  483. //// SocketAddress methods /////////////////////////////////////////////////////
  484. // getAddress(str, len)
  485. const char* SocketAddress::getAddress(char* str) { // Get the IP address into a cstring.
  486. if(NULL == str) { // If the caller did not provide a
  487. str = IPStringBuffer; // buffer to use then we will use ours.
  488. }
  489. int a0, a1, a2, a3; // Grab a bunch of handy integers.
  490. getAddress(a0, a1, a2, a3); // Get the address as octets.
  491. sprintf(str, "%d.%d.%d.%d", a0, a1, a2, a3); // Format as dotted decimal notation.
  492. return str; // Return the output buffer.
  493. }
  494. // getAddress(int& a0, int& a1, int& a2, int& a3)
  495. void SocketAddress::getAddress(int& a0, int& a1, int& a2, int& a3) { // Get the IP address into 4 ints
  496. unsigned long A = getAddress(); // Get the address.
  497. splitIP(A, a0, a1, a2, a3); // Split it into octets.
  498. }
  499. //// TCPListener methods ///////////////////////////////////////////////////////
  500. TCPListener::TCPListener(unsigned short Port) { // Set up localhost on this Port.
  501. LocalAddress.setPort(Port); // Establish the port.
  502. LocalAddress.setAddress(LOCALHOST); // Set the address to LOCALHOST.
  503. MaxPending = DefaultMaxPending; // Use the default inbound queue size.
  504. ReuseAddress = true; // ReuseAddress on by default.
  505. OpenStage1Complete = false; // This stage of open() not yet done.
  506. OpenStage2Complete = false; // This stage of open() not yet done.
  507. // Create a socket...
  508. LastError = 0;
  509. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  510. if(INVALID_SOCKET == Handle) { // If that operation failed then
  511. LastError = Network.getLastError(); // grab the error code and
  512. throw Networking::SocketCreationError( // throw.
  513. Network.DescriptiveError(
  514. "TCPListener::TCPListener().socket()", LastError));
  515. }
  516. }
  517. TCPListener::TCPListener(SocketAddress& WhereToBind) { // Set up specific "name" for listening.
  518. LocalAddress = WhereToBind; // Make my Local address as provided.
  519. MaxPending = DefaultMaxPending; // Use the default inbound queue size.
  520. ReuseAddress = true; // ReuseAddress on by default.
  521. OpenStage1Complete = false; // This stage of open() not yet done.
  522. OpenStage2Complete = false; // This stage of open() not yet done.
  523. // Create a socket...
  524. LastError = 0;
  525. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  526. if(INVALID_SOCKET == Handle) { // If that operation failed then
  527. LastError = Network.getLastError(); // grab the error code and
  528. throw Networking::SocketCreationError( // throw.
  529. Network.DescriptiveError(
  530. "TCPListener::TCPListener().socket()", LastError));
  531. }
  532. }
  533. // open()
  534. void TCPListener::open() { // Open when ready.
  535. if(OpenSucceeded) return; // If open already, we're done.
  536. LastError = 0; // Clear the last error.
  537. bool SuccessFlag = true; // Start optimistically.
  538. // Set SO_REUSEADDR if turned on
  539. if(!OpenStage1Complete) { // Do this stage only once.
  540. int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag.
  541. int result = // Set SO_REUSEADDR before bind().
  542. setsockopt(
  543. Handle,
  544. SOL_SOCKET,
  545. SO_REUSEADDR,
  546. (char*) &ReuseAddress_Flag,
  547. sizeof(ReuseAddress_Flag));
  548. if(0 > result) { // If there was an error then
  549. SuccessFlag = false; // we did not succeed.
  550. LastError = Network.getLastError(); // Capture the error information and
  551. throw Networking::SocketSetSockOptError( // throw.
  552. Network.DescriptiveError(
  553. "TCPListener::open().setsockopt(SO_REUSEADDR)", LastError));
  554. }
  555. OpenStage1Complete = true; // Stage 1 complete now.
  556. } // End of open() stage 1
  557. // Next we bind it...
  558. if(!OpenStage2Complete) { // Do this stage only once.
  559. int result = // Bind our socket to the LocalAddress.
  560. bind(
  561. Handle,
  562. LocalAddress.getPtr_sockaddr(),
  563. LocalAddress.getAddressSize());
  564. if(0 > result) { // If there was an error then
  565. SuccessFlag = false; // we did not succeed.
  566. LastError = Network.getLastError(); // Capture the error information and
  567. throw Networking::SocketBindError( // throw.
  568. Network.DescriptiveError(
  569. "TCPListener::open().bind()", LastError));
  570. }
  571. OpenStage2Complete = true; // Stage 2 complete now.
  572. } // End of open() stage 2
  573. // Then we put it in a listening state...
  574. int result = listen(Handle, MaxPending); // Listen for up to MaxPending at once.
  575. if(0 > result) { // If an error occurred then
  576. SuccessFlag = false; // we did not succeed.
  577. LastError = Network.getLastError(); // Capture the error information and
  578. throw Networking::SocketListenError( // throw.
  579. Network.DescriptiveError(
  580. "TCPListener::open().listen()", LastError));
  581. }
  582. OpenSucceeded = SuccessFlag; // So, did we succeed?
  583. }
  584. // acceptClient()
  585. TCPClient* TCPListener::acceptClient() { // Accept a client connection.
  586. LastError = 0; // Clear the last error.
  587. socklen_t rsize = RemoteAddress.getAddressSize(); // Size as an int for accept().
  588. hSocket NewHandle = // Accept a new connection if available.
  589. accept(
  590. Handle, // use our handle, of course,...
  591. RemoteAddress.getPtr_sockaddr(), // and store the remote hosts
  592. &rsize); // address for us.
  593. if(INVALID_SOCKET == NewHandle) { // If there was an error then
  594. LastError = Network.getLastError(); // capture the error value.
  595. if(!Network.WouldBlock(LastError)) { // If it's not a EWOULDBLOCK error
  596. throw Networking::SocketAcceptError( // then we need to throw.
  597. Network.DescriptiveError(
  598. "TCPListener::acceptClient().accept()", LastError));
  599. } else { // EWOULDBLOCK errors are normal in
  600. return NULL; // non blocking mode so we return
  601. } // NULL when we see them.
  602. }
  603. // Set SO_NOSIGPIPE if needed
  604. if( // On some systems we may have to
  605. 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
  606. 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
  607. ) {
  608. int TurnedOn = 1; // Prepare to turn this option on.
  609. int result = // Set SO_NOSIGPIPE.
  610. setsockopt(
  611. NewHandle,
  612. SOL_SOCKET,
  613. SO_NOSIGPIPE,
  614. (char*) &TurnedOn,
  615. sizeof(TurnedOn));
  616. if(0 > result) { // If there was an error then
  617. LastError = Network.getLastError(); // Capture the error information
  618. Network.closeSocket(NewHandle); // close the handle (avoid leaks)
  619. throw Networking::SocketSetSockOptError( // and throw a descriptive exception.
  620. Network.DescriptiveError(
  621. "TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError));
  622. }
  623. }
  624. // If things have gone well we can do what we came for.
  625. return new TCPClient(*this, NewHandle, RemoteAddress); // Create the new TCPClient object.
  626. }
  627. //// TCPClient methods /////////////////////////////////////////////////////////
  628. int TCPClient::transmit(const char* bfr, int size) { // How to send a buffer of data.
  629. if(0 == size) return 0; // Nothing to send, send nothing.
  630. if(0 == bfr) // Watch out for null buffers.
  631. throw Networking::SocketWriteError("TCPClient::transmit() NULL Bfr!");
  632. if(0 > size) // Watch out for bad sizes.
  633. throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!");
  634. LastError = 0; // No errors yet.
  635. int ByteCount = 0; // No bytes sent yet this pass.
  636. ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count.
  637. LastError = Network.getLastError(); // Grab any error code.
  638. bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred.
  639. const int NoBytesSent = 0; // This is our "Would Block" result.
  640. if(AnErrorOccurred) { // If there was an error check it out.
  641. if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then
  642. return NoBytesSent; // return no bytes sent (try again).
  643. } else { // If this was a different kind of error
  644. throw Networking::SocketWriteError( // then throw!
  645. Network.DescriptiveError(
  646. "TCPClient::transmit().send()", LastError));
  647. }
  648. }
  649. return ByteCount; // Usually: return the sent byte count.
  650. }
  651. int TCPClient::receive(char* bfr, int size) { // How to receive a buffer of data.
  652. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  653. fillReadBuffer(); // fill it first.
  654. } // Optimize our transfer to the smaller
  655. if(DataLength < size) { // of what we have or the size of the
  656. size = DataLength; // provided buffer. This way we ony check
  657. } // one value in our copy loop ;-)
  658. int RemainingDataLength = size; // Capture the length of data to xfer.
  659. while(0 < RemainingDataLength) { // While we have work to do
  660. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  661. bfr++; ReadPointer++; // move the pointers to the next byte,
  662. DataLength--; // update our ReadBuffers's DataLength,
  663. RemainingDataLength--; // and count down the bytes left to xfer.
  664. }
  665. return size; // When done, say how much we moved.
  666. }
  667. int TCPClient::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data.
  668. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  669. fillReadBuffer(); // fill it first.
  670. } // Optimize our transfer to the smaller
  671. if(DataLength < size) { // of what we have or the size of the
  672. size = DataLength; // provided buffer. This way we ony check
  673. } // one value in our copy loop ;-)
  674. int Count = 0; // Keep our byte count in scope.
  675. bool DelimiterNotReached = true; // Watching for our deliimiter.
  676. while((Count < size) && DelimiterNotReached) { // While there is work to do...
  677. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  678. DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character,
  679. bfr++; ReadPointer++; // move the pointers to the next byte,
  680. DataLength--; // update our ReadBuffers's DataLength,
  681. Count++; // and count up the bytes we have moved.
  682. }
  683. return Count; // When done, say how much we moved.
  684. }
  685. //// TCPHost methods ///////////////////////////////////////////////////////////
  686. // Constructors...
  687. TCPHost::TCPHost(unsigned short Port) { // Will connect to localhost on Port.
  688. RemoteAddress.setPort(Port); // Connect to Port on
  689. RemoteAddress.setAddress(LOCALHOST); // Localhost.
  690. ReadPointer = ReadBuffer; // Set the read position to zero.
  691. DataLength = 0; // There is no data yet.
  692. ReuseAddress = false; // ReuseAddress off by default.
  693. OpenStage1Complete = false; // Stage 1 of open() not done yet.
  694. // Create a socket to use.
  695. LastError = 0; // Clear our last error value.
  696. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  697. if(0 > Handle) { // If that operation failed then
  698. LastError = Network.getLastError(); // grab the error code and
  699. throw Networking::SocketCreationError( // throw.
  700. Network.DescriptiveError(
  701. "TCPHost::TCPHost().socket()", LastError));
  702. }
  703. }
  704. TCPHost::TCPHost(SocketAddress& Remote) { // Will connect to Remote address/port.
  705. RemoteAddress = Remote; // Capture the provided address.
  706. ReadPointer = ReadBuffer; // Set the read position to zero.
  707. DataLength = 0; // There is no data yet.
  708. ReuseAddress = false; // ReuseAddress off by default.
  709. OpenStage1Complete = false; // Stage 1 of open() not done yet.
  710. // Create a socket to use.
  711. LastError = 0; // Clear our last error value.
  712. Handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // Create the socket.
  713. if(0 > Handle) { // If that operation failed then
  714. LastError = Network.getLastError(); // grab the error code and
  715. throw Networking::SocketCreationError( // throw.
  716. Network.DescriptiveError(
  717. "TCPHost::TCPHost().socket()", LastError));
  718. }
  719. }
  720. // Methods...
  721. void TCPHost::open() { // We provide open().
  722. if(OpenSucceeded) return; // If open already, we're done.
  723. LastError = 0; // Clear our LastError value.
  724. bool SuccessFlag = true; // Begin optimistically.
  725. // Set Socket Options
  726. if(!OpenStage1Complete) { // If we haven't done this yet:
  727. // Set SO_REUSEADDR if turned on
  728. int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag.
  729. int result = // Set SO_REUSEADDR before bind().
  730. setsockopt(
  731. Handle,
  732. SOL_SOCKET,
  733. SO_REUSEADDR,
  734. (char*) &ReuseAddress_Flag,
  735. sizeof(ReuseAddress_Flag));
  736. if(0 > result) { // If there was an error then
  737. SuccessFlag = false; // we did not succeed.
  738. LastError = Network.getLastError(); // Capture the error information and
  739. throw Networking::SocketSetSockOptError( // throw.
  740. Network.DescriptiveError(
  741. "TCPHost::open().setsockopt(SO_REUSEADDR)", LastError));
  742. }
  743. // Set SO_NOSIGPIPE if needed
  744. if( // On some systems we may have to
  745. 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
  746. 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
  747. ) {
  748. int TurnedOn = 1; // Prepare to turn this option on.
  749. int result = // Set SO_NOSIGPIPE.
  750. setsockopt(
  751. Handle,
  752. SOL_SOCKET,
  753. SO_NOSIGPIPE,
  754. (char*) &TurnedOn,
  755. sizeof(TurnedOn));
  756. if(0 > result) { // If there was an error then
  757. SuccessFlag = false; // we did not succeed.
  758. LastError = Network.getLastError(); // Capture the error information and
  759. throw Networking::SocketSetSockOptError( // throw.
  760. Network.DescriptiveError(
  761. "TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError));
  762. }
  763. }
  764. OpenStage1Complete = true; // Skip this section from now on.
  765. } // Done with stage 1.
  766. // Connect the socekt to the Host.
  767. int result = // Connect to the remote host
  768. connect( // using the socket we just
  769. Handle, // stored in Handle and
  770. RemoteAddress.getPtr_sockaddr(), // the Remote address.
  771. RemoteAddress.getAddressSize());
  772. if(0 > result) { // If there was an error then
  773. SuccessFlag = false; // we did not succeed.
  774. LastError = Network.getLastError(); // Record the error data.
  775. if(Network.IsConnected(LastError)) { // If we actually did succeed then
  776. SuccessFlag = true; // say so. (Silly Winsock!)
  777. } else // But if that's not the case check
  778. if( // to see if something bad happened -
  779. !Network.WouldBlock(LastError) && // not just would-block, or
  780. !Network.InProgress(LastError) // in progress...
  781. ) { // If it was something other than
  782. throw Networking::SocketConnectError( // WouldBlock or InProgress then
  783. Network.DescriptiveError( // throw!
  784. "TCPHost::open().connect()", LastError));
  785. } // If it was WouldBlock then it's
  786. } // considered to be ok.
  787. OpenSucceeded = SuccessFlag; // So, are we open now?
  788. }
  789. int TCPHost::transmit(const char* bfr, int size) { // How to send a buffer of data.
  790. LastError = 0; // No errors yet.
  791. if(0 == size) return 0; // Nothing to send, send nothing.
  792. if(0 == bfr) // Watch out for null buffers.
  793. throw Networking::SocketWriteError("TCPHost::transmit() NULL Bfr!");
  794. if(0 > size) // Watch out for bad sizes.
  795. throw Networking::SocketWriteError("TCPHost::transmit() 0 > size!");
  796. int ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count.
  797. if(0 > ByteCount) ByteCount = 0; // Mask error results as 0 bytes sent.
  798. if(size > ByteCount) { // If we didn't send it all check it out.
  799. LastError = Network.getLastError(); // Grab the error code.
  800. if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
  801. return ByteCount; // it was a partial snd - return.
  802. } else { // If this was a different kind of error
  803. throw Networking::SocketWriteError( // then throw!
  804. Network.DescriptiveError(
  805. "TCPHost::transmit().send()", LastError));
  806. }
  807. }
  808. return ByteCount; // Ultimately return the byte count.
  809. }
  810. int TCPHost::receive(char* bfr, int size) { // How to receive a buffer of data.
  811. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  812. fillReadBuffer(); // fill it first.
  813. } // Optimize our transfer to the smaller
  814. if(DataLength < size) { // of what we have or the size of the
  815. size = DataLength; // provided buffer. This way we ony check
  816. } // one value in our copy loop ;-)
  817. int RemainingDataLength = size; // Capture the length of data to xfer.
  818. while(0 < RemainingDataLength) { // While we have work to do
  819. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  820. bfr++; ReadPointer++; // move the pointers to the next byte,
  821. DataLength--; // update our ReadBuffers's DataLength,
  822. RemainingDataLength--; // and count down the bytes left to xfer.
  823. }
  824. return size; // When done, say how much we moved.
  825. }
  826. int TCPHost::delimited_receive(char* bfr, int size, char delimiter) { // How to receive delimited data.
  827. if(ReadBufferIsEmpty()) { // If the read buffer is empty then
  828. fillReadBuffer(); // fill it first.
  829. } // Optimize our transfer to the smaller
  830. if(DataLength < size) { // of what we have or the size of the
  831. size = DataLength; // provided buffer. This way we ony check
  832. } // one value in our copy loop ;-)
  833. int Count = 0; // Keep our byte count in scope.
  834. bool DelimiterNotReached = true; // Watching for our deliimiter.
  835. while((Count < size) && DelimiterNotReached) { // While there is work to do...
  836. *bfr = *ReadPointer; // copy each byte from our ReadBuffer,
  837. DelimiterNotReached = (delimiter != (*bfr)); // check for the delimiter character,
  838. bfr++; ReadPointer++; // move the pointers to the next byte,
  839. DataLength--; // update our ReadBuffers's DataLength,
  840. Count++; // and count up the bytes we have moved.
  841. }
  842. return Count; // When done, say how much we moved.
  843. }
  844. // End Platform Agnostic Stuff
  845. ////////////////////////////////////////////////////////////////////////////////
  846. } // End namespace codedweller