aboutsummaryrefslogtreecommitdiff
path: root/src/stable/sockettcp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/sockettcp.cpp')
-rw-r--r--src/stable/sockettcp.cpp488
1 files changed, 488 insertions, 0 deletions
diff --git a/src/stable/sockettcp.cpp b/src/stable/sockettcp.cpp
new file mode 100644
index 0000000..d61f92f
--- /dev/null
+++ b/src/stable/sockettcp.cpp
@@ -0,0 +1,488 @@
1/*
2 * Copyright (C) 2007-2019 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <string.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/time.h>
15#include <errno.h>
16#include <fcntl.h>
17#include "bu/sockettcp.h"
18
19#include "bu/config.h"
20
21#ifndef WIN32
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #include <arpa/inet.h>
26#else
27 #include <Winsock2.h>
28#endif
29
30#define RBS (1024*2)
31
32namespace Bu { subExceptionDef( SocketTcpException ) }
33
34Bu::SocketTcp::SocketTcp( handle nSocketTcp ) :
35 nSocketTcp( nSocketTcp ),
36 bActive( true ),
37 bBlocking( true )
38{
39#ifdef WIN32
40 Bu::Winsock2::getInstance();
41#endif
42 setAddress();
43}
44
45Bu::SocketTcp::SocketTcp( const Bu::String &sAddr, int nPort, int nTimeout,
46 bool bBlocking ) :
47 nSocketTcp( 0 ),
48 bActive( false ),
49 bBlocking( true )
50{
51#ifdef WIN32
52 Bu::Winsock2::getInstance();
53#endif
54
55 /* Create the socket. */
56 nSocketTcp = bu_socket( PF_INET, SOCK_STREAM, 0 );
57
58#ifdef WIN32
59 if( nSocketTcp == INVALID_SOCKET )
60#else
61 if( nSocketTcp < 0 )
62#endif
63 {
64 throw ExceptionBase("Couldn't create socket.\n");
65 }
66
67 setBlocking( false );
68
69 /* Connect to the server. */
70 //printf("Resolving hostname (%s)...\n", sAddr );
71 {
72 struct addrinfo *pAddr = NULL;
73 struct addrinfo aiHints;
74 memset( &aiHints, 0, sizeof(addrinfo) );
75 aiHints.ai_flags = AI_CANONNAME;
76 aiHints.ai_family = AF_INET;
77 aiHints.ai_socktype = SOCK_STREAM;
78 char ibuf[10];
79 sprintf( ibuf, "%d", nPort );
80
81 int ret;
82 if( (ret = bu_getaddrinfo(
83 sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 )
84 {
85 close();
86 throw Bu::SocketTcpException("Couldn't resolve hostname %s (%s).\n",
87 sAddr.getStr(), bu_gai_strerror(ret));
88 }
89
90 bu_connect(
91 nSocketTcp,
92 pAddr->ai_addr,
93 pAddr->ai_addrlen
94 );
95
96 sAddress = pAddr->ai_canonname;
97
98 bu_freeaddrinfo( pAddr );
99 }
100
101 bActive = true;
102
103 if( nTimeout > 0 )
104 {
105 fd_set rfds, wfds, efds;
106 int retval;
107
108 FD_ZERO(&rfds);
109 FD_SET(nSocketTcp, &rfds);
110 FD_ZERO(&wfds);
111 FD_SET(nSocketTcp, &wfds);
112 FD_ZERO(&efds);
113 FD_SET(nSocketTcp, &efds);
114
115 struct timeval tv;
116 tv.tv_sec = nTimeout;
117 tv.tv_usec = 0;
118
119 retval = bu_select( nSocketTcp+1, &rfds, &wfds, &efds, &tv );
120
121 if( retval == 0 )
122 {
123 close();
124 throw ExceptionBase("Connection timeout.\n");
125 }
126 read( NULL, 0 ); // See if we can get any errors out of the way early.
127 }
128
129 if( bBlocking )
130 setBlocking( bBlocking );
131}
132
133Bu::SocketTcp::~SocketTcp()
134{
135 close();
136}
137
138void Bu::SocketTcp::close()
139{
140 if( bActive )
141 {
142#ifndef WIN32
143 fsync( nSocketTcp );
144#endif
145#ifdef WIN32
146 #ifndef SHUT_RDWR
147 #define SHUT_RDWR (SD_BOTH)
148 #endif
149#endif
150 bu_shutdown( nSocketTcp, SHUT_RDWR );
151 ::close( nSocketTcp );
152 }
153 bActive = false;
154}
155
156Bu::size Bu::SocketTcp::read( void *pBuf, Bu::size nBytes )
157{
158 fd_set rfds;
159 FD_ZERO(&rfds);
160 FD_SET(nSocketTcp, &rfds);
161 struct timeval tv = {0, 0};
162 if( bu_select( nSocketTcp+1, &rfds, NULL, NULL, &tv ) < 0 )
163 {
164 int iErr = errno;
165 close();
166 throw SocketTcpException( SocketTcpException::cRead, strerror(iErr) );
167 }
168 if( FD_ISSET( nSocketTcp, &rfds ) || bBlocking )
169 {
170 int nRead = TEMP_FAILURE_RETRY(
171 bu_recv( nSocketTcp, (char *) pBuf, nBytes, 0 ) );
172 if( nRead == 0 && nBytes > 0 )
173 {
174 close();
175 throw SocketTcpException( SocketTcpException::cClosed, "SocketTcp closed.");
176 }
177 if( nRead < 0 )
178 {
179#ifdef WIN32
180 int iWSAError = bu_WSAGetLastError();
181 if( iWSAError == WSAEWOULDBLOCK )
182 return 0;
183#else
184 if( errno == ENETRESET || errno == ECONNRESET )
185 {
186 close();
187 throw SocketTcpException( SocketTcpException::cClosed,
188 strerror(errno) );
189 }
190 if( errno == EAGAIN )
191 return 0;
192 int iErr = errno;
193 close();
194 throw SocketTcpException( SocketTcpException::cRead, strerror(iErr) );
195#endif
196 }
197 return nRead;
198 }
199 return 0;
200}
201
202Bu::size Bu::SocketTcp::read( void *pBuf, Bu::size nBytes,
203 uint32_t nSec, uint32_t nUSec )
204{
205 struct timeval tv;
206 Bu::size nRead = 0;
207
208 fd_set rfds;
209 FD_ZERO(&rfds);
210 FD_SET(nSocketTcp, &rfds);
211
212#ifdef WIN32
213 DWORD dwStart = GetTickCount();
214 uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000));
215 DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver;
216#else
217 struct timeval nt, ct;
218 gettimeofday( &nt, NULL );
219 nt.tv_sec += nSec;
220 nt.tv_usec += nUSec;
221#endif
222
223 for(;;)
224 {
225 tv.tv_sec = nSec;
226 tv.tv_usec = nUSec;
227 bu_select( nSocketTcp+1, &rfds, NULL, NULL, &tv );
228 nRead += read( ((char *)pBuf)+nRead, nBytes-nRead );
229 if( nRead >= nBytes )
230 break;
231#ifdef WIN32
232 DWORD dwNow = GetTickCount();
233 if( dwNow > dwEnd )
234 break;
235#else
236 gettimeofday( &ct, NULL );
237 if( (ct.tv_sec > nt.tv_sec) ||
238 (ct.tv_sec == nt.tv_sec &&
239 ct.tv_usec >= nt.tv_usec) )
240 break;
241#endif
242 }
243 return nRead;
244}
245
246Bu::size Bu::SocketTcp::write( const void *pBuf, Bu::size nBytes )
247{
248//#ifdef WIN32
249 int nWrote = TEMP_FAILURE_RETRY(
250 bu_send( nSocketTcp, (const char *) pBuf, nBytes, 0 ) );
251//#else
252// int nWrote = TEMP_FAILURE_RETRY( ::write( nSocketTcp, pBuf, nBytes ) );
253//#endif
254 if( nWrote < 0 )
255 {
256#ifdef WIN32
257 int iWSAError = bu_WSAGetLastError();
258 if( iWSAError == WSAEWOULDBLOCK )
259 return 0;
260#else
261 if( errno == EAGAIN ) return 0;
262#endif
263 throw SocketTcpException( SocketTcpException::cWrite, strerror(errno) );
264 }
265 return nWrote;
266}
267
268Bu::size Bu::SocketTcp::write( const void *pBuf, Bu::size nBytes, uint32_t nSec, uint32_t nUSec )
269{
270 struct timeval tv;
271 Bu::size nWrote = 0;
272
273 fd_set wfds;
274 FD_ZERO(&wfds);
275 FD_SET(nSocketTcp, &wfds);
276
277#ifdef WIN32
278 DWORD dwStart = GetTickCount();
279 uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000));
280 DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver;
281#else
282 struct timeval nt, ct;
283 gettimeofday( &nt, NULL );
284 nt.tv_sec += nSec;
285 nt.tv_usec += nUSec;
286#endif
287
288 for(;;)
289 {
290 tv.tv_sec = nSec;
291 tv.tv_usec = nUSec;
292 bu_select( nSocketTcp+1, NULL, &wfds, NULL, &tv );
293 nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote );
294 if( nWrote >= nBytes )
295 break;
296#ifdef WIN32
297 DWORD dwNow = GetTickCount();
298 if( dwNow > dwEnd )
299 break;
300#else
301 gettimeofday( &ct, NULL );
302 if( (ct.tv_sec > nt.tv_sec) ||
303 (ct.tv_sec == nt.tv_sec &&
304 ct.tv_usec >= nt.tv_usec) )
305 break;
306#endif
307 }
308 return nWrote;
309}
310
311Bu::size Bu::SocketTcp::tell()
312{
313 throw UnsupportedException();
314}
315
316void Bu::SocketTcp::seek( Bu::size )
317{
318 throw UnsupportedException();
319}
320
321void Bu::SocketTcp::setPos( Bu::size )
322{
323 throw UnsupportedException();
324}
325
326void Bu::SocketTcp::setPosEnd( Bu::size )
327{
328 throw UnsupportedException();
329}
330
331bool Bu::SocketTcp::isEos()
332{
333 return !bActive;
334}
335
336bool Bu::SocketTcp::canRead()
337{
338 fd_set rfds;
339 FD_ZERO(&rfds);
340 FD_SET(nSocketTcp, &rfds);
341 struct timeval tv = { 0, 0 };
342 int retval = bu_select( nSocketTcp+1, &rfds, NULL, NULL, &tv );
343 if( retval == -1 )
344 throw SocketTcpException(
345 SocketTcpException::cBadRead,
346 "Bad Read error"
347 );
348
349 if( !FD_ISSET( nSocketTcp, &rfds ) )
350 return false;
351 return true;
352}
353
354bool Bu::SocketTcp::canWrite()
355{
356 fd_set wfds;
357 FD_ZERO(&wfds);
358 FD_SET(nSocketTcp, &wfds);
359 struct timeval tv = { 0, 0 };
360 int retval = bu_select( nSocketTcp+1, NULL, &wfds, NULL, &tv );
361 if( retval == -1 )
362 throw SocketTcpException(
363 SocketTcpException::cBadRead,
364 "Bad Read error"
365 );
366 if( !FD_ISSET( nSocketTcp, &wfds ) )
367 return false;
368 return true;
369}
370
371bool Bu::SocketTcp::isReadable()
372{
373 return true;
374}
375
376bool Bu::SocketTcp::isWritable()
377{
378 return true;
379}
380
381bool Bu::SocketTcp::isSeekable()
382{
383 return false;
384}
385
386bool Bu::SocketTcp::isBlocking()
387{
388#ifndef WIN32
389 return ((fcntl( nSocketTcp, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK);
390#else
391 return false;
392#endif
393}
394
395void Bu::SocketTcp::setBlocking( bool bBlocking )
396{
397 this->bBlocking = bBlocking;
398#ifndef WIN32
399 if( bBlocking )
400 {
401 fcntl( nSocketTcp, F_SETFL, fcntl( nSocketTcp, F_GETFL, 0 ) & (~O_NONBLOCK) );
402 }
403 else
404 {
405 fcntl( nSocketTcp, F_SETFL, fcntl( nSocketTcp, F_GETFL, 0 ) | O_NONBLOCK );
406 }
407#else
408 u_long iMode;
409 if( bBlocking )
410 iMode = 0;
411 else
412 iMode = 1;
413 //-------------------------
414 // Set the socket I/O mode: In this case FIONBIO
415 // enables or disables the blocking mode for the
416 // socket based on the numerical value of iMode.
417 // If iMode = 0, blocking is enabled;
418 // If iMode != 0, non-blocking mode is enabled.
419 bu_ioctlsocket(nSocketTcp, FIONBIO, &iMode);
420#endif
421}
422
423void Bu::SocketTcp::setSize( Bu::size )
424{
425}
426
427void Bu::SocketTcp::flush()
428{
429}
430
431bool Bu::SocketTcp::isOpen()
432{
433 return bActive;
434}
435
436void Bu::SocketTcp::setAddress()
437{
438 struct sockaddr_in addr;
439 socklen_t len = sizeof(addr);
440 addr.sin_family = AF_INET;
441 bu_getpeername( nSocketTcp, (sockaddr *)(&addr), &len );
442 sAddress = bu_inet_ntoa( addr.sin_addr );
443}
444
445Bu::String Bu::SocketTcp::getAddress() const
446{
447 return sAddress;
448}
449
450Bu::SocketTcp::operator Bu::SocketTcp::handle() const
451{
452 return nSocketTcp;
453}
454
455Bu::SocketTcp::handle Bu::SocketTcp::getHandle() const
456{
457 return nSocketTcp;
458}
459
460Bu::SocketTcp::handle Bu::SocketTcp::takeHandle()
461{
462 handle nRet = nSocketTcp;
463 bActive = false;
464 nSocketTcp = 0;
465 return nRet;
466}
467
468Bu::size Bu::SocketTcp::getSize() const
469{
470 throw UnsupportedException();
471}
472
473Bu::size Bu::SocketTcp::getBlockSize() const
474{
475 return 1500; //TODO: Fix this, it's stupid.
476}
477
478Bu::String Bu::SocketTcp::getLocation() const
479{
480 return getAddress();
481}
482
483bool Bu::SocketTcp::getFd( int &rFdOut ) const
484{
485 rFdOut = nSocketTcp;
486 return true;
487}
488