Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

TcpSocket.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : TcpSocket.cpp
00008    Version  : $Revision: 1.11 $
00009    Author   : $Author: darkeye $
00010    Location : $Source: /cvsroot/darkice/darkice/src/TcpSocket.cpp,v $
00011    
00012    Copyright notice:
00013 
00014     This program is free software; you can redistribute it and/or
00015     modify it under the terms of the GNU General Public License  
00016     as published by the Free Software Foundation; either version 2
00017     of the License, or (at your option) any later version.
00018    
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00022     GNU General Public License for more details.
00023    
00024     You should have received a copy of the GNU General Public License
00025     along with this program; if not, write to the Free Software
00026     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #else
00039 #error need string.h
00040 #endif
00041 
00042 #ifdef HAVE_SYS_TYPES_H
00043 #include <sys/types.h>
00044 #else
00045 #error need sys/types.h
00046 #endif
00047 
00048 #ifdef HAVE_ERRNO_H
00049 #include <errno.h>
00050 #else
00051 #error need errno.h
00052 #endif
00053 
00054 #ifdef HAVE_SYS_SOCKET_H
00055 #include <sys/socket.h>
00056 #else
00057 #error need sys/socket.h
00058 #endif
00059 
00060 #ifdef HAVE_NETINET_IN_H
00061 #include <netinet/in.h>
00062 #else
00063 #error need netinet/in.h
00064 #endif
00065 
00066 #ifdef HAVE_NETDB_H
00067 #include <netdb.h>
00068 #else
00069 #error need netdb.h
00070 #endif
00071 
00072 #ifdef HAVE_UNISTD_H
00073 #include <unistd.h>
00074 #else
00075 #error need unistd.h
00076 #endif
00077 
00078 #ifdef HAVE_SYS_TIME_H
00079 #include <sys/time.h>
00080 #else
00081 #error need sys/time.h
00082 #endif
00083 
00084 
00085 #include "Util.h"
00086 #include "Exception.h"
00087 #include "TcpSocket.h"
00088 
00089 
00090 /* ===================================================  local data structures */
00091 
00092 
00093 /* ================================================  local constants & macros */
00094 
00095 /*------------------------------------------------------------------------------
00096  *  File identity
00097  *----------------------------------------------------------------------------*/
00098 static const char fileid[] = "$Id: TcpSocket.cpp,v 1.11 2006/05/19 12:39:19 darkeye Exp $";
00099 
00100 
00101 /* ===============================================  local function prototypes */
00102 
00103 
00104 /* =============================================================  module code */
00105 
00106 /*------------------------------------------------------------------------------
00107  *  Initialize the object
00108  *----------------------------------------------------------------------------*/
00109 void
00110 TcpSocket :: init (   const char    * host,
00111                       unsigned short  port )          throw ( Exception )
00112 {
00113     this->host   = Util::strDup( host);
00114     this->port   = port;
00115     this->sockfd = 0;
00116 }
00117 
00118 
00119 /*------------------------------------------------------------------------------
00120  *  De-initialize the object
00121  *----------------------------------------------------------------------------*/
00122 void
00123 TcpSocket :: strip ( void)                           throw ( Exception )
00124 {
00125     if ( isOpen() ) {
00126         close();
00127     }
00128 
00129     delete[] host;
00130 }
00131 
00132 
00133 /*------------------------------------------------------------------------------
00134  *  Copy Constructor
00135  *----------------------------------------------------------------------------*/
00136 TcpSocket :: TcpSocket (  const TcpSocket &    ss )    throw ( Exception )
00137                 : Source( ss), Sink( ss )
00138 {
00139     int     fd;
00140     
00141     init( ss.host, ss.port);
00142 
00143     if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) {
00144         strip();
00145         throw Exception( __FILE__, __LINE__, "dup failure");
00146     }
00147 
00148     sockfd = fd;
00149 }
00150 
00151 
00152 /*------------------------------------------------------------------------------
00153  *  Assignment operator
00154  *----------------------------------------------------------------------------*/
00155 TcpSocket &
00156 TcpSocket :: operator= (  const TcpSocket &    ss )   throw ( Exception )
00157 {
00158     if ( this != &ss ) {
00159         int     fd;
00160 
00161         /* first strip */
00162         strip();
00163 
00164 
00165         /* then build up */
00166         Sink::operator=( ss );
00167         Source::operator=( ss );
00168 
00169         init( ss.host, ss.port);
00170         
00171         if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) {
00172             strip();
00173             throw Exception( __FILE__, __LINE__, "dup failure");
00174         }
00175 
00176         sockfd = fd;
00177     }
00178 
00179     return *this;
00180 }
00181 
00182 
00183 /*------------------------------------------------------------------------------
00184  *  Open the file
00185  *----------------------------------------------------------------------------*/
00186 bool
00187 TcpSocket :: open ( void )                       throw ( Exception )
00188 {
00189 #ifdef HAVE_ADDRINFO
00190     struct addrinfo         hints
00191     struct addrinfo       * ptr;
00192     struct sockaddr_storage addr;
00193     char                    portstr[6];
00194 #else
00195     struct sockaddr_in      addr;
00196     struct hostent        * pHostEntry;
00197 #endif
00198  
00199     if ( isOpen() ) {
00200         return false;
00201     }
00202 
00203 #ifdef HAVE_ADDRINFO
00204     memset(&hints, 0, sizeof(hints));
00205     hints.ai_socktype = SOCK_STREAM;
00206     hints.ai_family = AF_ANY;
00207     snprintf(portstr, sizeof(portstr), "%d", port);
00208 
00209     if (getaddrinfo(host , portstr, &hints, &ptr)) {
00210         throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno);
00211     }
00212     memcpy ( addr, ptr->ai_addr, ptr->ai_addrlen);
00213     freeaddrinfo(ptr);
00214 #else
00215     if ( !(pHostEntry = gethostbyname( host)) ) {
00216         throw Exception( __FILE__, __LINE__, "gethostbyname error", errno);
00217     }
00218     
00219     if ( (sockfd = socket( AF_INET, SOCK_STREAM,  IPPROTO_TCP)) == -1 ) {
00220         throw Exception( __FILE__, __LINE__, "socket error", errno);
00221     }
00222 
00223     memset( &addr, 0, sizeof(addr));
00224     addr.sin_family      = AF_INET;
00225     addr.sin_port        = htons(port);
00226     addr.sin_addr.s_addr = *((long*) pHostEntry->h_addr_list[0]);
00227 #endif
00228     if ( connect( sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ) {
00229         ::close( sockfd);
00230         sockfd = 0;
00231         throw Exception( __FILE__, __LINE__, "connect error", errno);
00232     }
00233 
00234     return true;
00235 }
00236 
00237 
00238 /*------------------------------------------------------------------------------
00239  *  Check wether read() would return anything
00240  *----------------------------------------------------------------------------*/
00241 bool
00242 TcpSocket :: canRead (      unsigned int    sec,
00243                             unsigned int    usec )      throw ( Exception )
00244 {
00245     fd_set              fdset;
00246     struct timeval      tv;
00247     int                 ret;
00248 
00249     if ( !isOpen() ) {
00250         return false;
00251     }
00252 
00253     FD_ZERO( &fdset);
00254     FD_SET( sockfd, &fdset);
00255     tv.tv_sec  = sec;
00256     tv.tv_usec = usec;
00257 
00258     ret = select( sockfd + 1, &fdset, NULL, NULL, &tv);
00259     
00260     if ( ret == -1 ) {
00261         throw Exception( __FILE__, __LINE__, "select error");
00262     }
00263 
00264     return ret > 0;
00265 }
00266 
00267 
00268 /*------------------------------------------------------------------------------
00269  *  Read from the socket
00270  *----------------------------------------------------------------------------*/
00271 unsigned int
00272 TcpSocket :: read (     void          * buf,
00273                         unsigned int    len )       throw ( Exception )
00274 {
00275     int         ret;
00276 
00277     if ( !isOpen() ) {
00278         return 0;
00279     }
00280 
00281     ret = recv( sockfd, buf, len, 0);
00282 
00283     if ( ret == -1 ) {
00284         switch (errno) {
00285             case ECONNRESET:
00286                 // re-open the socket if it has been reset by the peer
00287                 close();
00288                 open();
00289                 break;
00290 
00291             default:
00292                 throw Exception( __FILE__, __LINE__, "recv error", errno);
00293         }
00294     }
00295 
00296     return ret;
00297 }
00298 
00299 
00300 /*------------------------------------------------------------------------------
00301  *  Check wether read() would return anything
00302  *----------------------------------------------------------------------------*/
00303 bool
00304 TcpSocket :: canWrite (    unsigned int    sec,
00305                            unsigned int    usec )      throw ( Exception )
00306 {
00307     fd_set              fdset;
00308     struct timeval      tv;
00309     int                 ret;
00310 
00311     if ( !isOpen() ) {
00312         return false;
00313     }
00314 
00315     FD_ZERO( &fdset);
00316     FD_SET( sockfd, &fdset);
00317     tv.tv_sec  = sec;
00318     tv.tv_usec = usec;
00319 
00320     ret = select( sockfd + 1, NULL, &fdset, NULL, &tv);
00321     
00322     if ( ret == -1 ) {
00323         throw Exception( __FILE__, __LINE__, "select error");
00324     }
00325 
00326     return ret > 0;
00327 }
00328 
00329 
00330 /*------------------------------------------------------------------------------
00331  *  Write to the socket
00332  *----------------------------------------------------------------------------*/
00333 unsigned int
00334 TcpSocket :: write (    const void    * buf,
00335                         unsigned int    len )       throw ( Exception )
00336 {
00337     int         ret;
00338 
00339     if ( !isOpen() ) {
00340         return 0;
00341     }
00342 
00343 #ifdef HAVE_MSG_NOSIGNAL
00344     ret = send( sockfd, buf, len, MSG_NOSIGNAL);
00345 #else
00346     ret = send( sockfd, buf, len, 0);
00347 #endif
00348 
00349     if ( ret == -1 ) {
00350         if ( errno == EAGAIN ) {
00351             ret = 0;
00352         } else {
00353             throw Exception( __FILE__, __LINE__, "send error", errno);
00354         }
00355     }
00356 
00357     return ret;
00358 }
00359 
00360 
00361 /*------------------------------------------------------------------------------
00362  *  Close the socket
00363  *----------------------------------------------------------------------------*/
00364 void
00365 TcpSocket :: close ( void )                          throw ( Exception )
00366 {
00367     if ( !isOpen() ) {
00368         return;
00369     }
00370 
00371     flush();
00372     ::close( sockfd);
00373     sockfd = 0;
00374 }
00375 
00376 
00377 
00378 /*------------------------------------------------------------------------------
00379  
00380   $Source: /cvsroot/darkice/darkice/src/TcpSocket.cpp,v $
00381 
00382   $Log: TcpSocket.cpp,v $
00383   Revision 1.11  2006/05/19 12:39:19  darkeye
00384   added reconnection capability if the TCP connection is reset by the peer
00385 
00386   Revision 1.10  2005/04/11 19:34:23  darkeye
00387   added IPv6 support, thanks to <jochen2@users.sourceforge.net>
00388 
00389   Revision 1.9  2002/10/19 12:22:27  darkeye
00390   cosmetic change
00391 
00392   Revision 1.8  2002/08/28 18:24:46  darkeye
00393   ported to FreeBSD (removed reference to MSG_NOSIGNAL in TcpSocket.cpp)
00394 
00395   Revision 1.7  2002/07/20 16:37:06  darkeye
00396   added fault tolerance in case a server connection is dropped
00397 
00398   Revision 1.6  2001/09/18 16:44:10  darkeye
00399   TcpSocket did not report closed state when could not connect()
00400 
00401   Revision 1.5  2001/08/30 17:25:56  darkeye
00402   renamed configure.h to config.h
00403 
00404   Revision 1.4  2000/11/17 15:50:48  darkeye
00405   added -Wall flag to compiler and eleminated new warnings
00406 
00407   Revision 1.3  2000/11/12 14:54:50  darkeye
00408   added kdoc-style documentation comments
00409 
00410   Revision 1.2  2000/11/05 14:08:28  darkeye
00411   changed builting to an automake / autoconf environment
00412 
00413   Revision 1.1.1.1  2000/11/05 10:05:55  darkeye
00414   initial version
00415 
00416   
00417 ------------------------------------------------------------------------------*/
00418 

Generated on Fri May 19 15:36:48 2006 for DarkIce by  doxygen 1.4.4