Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

wvtcp.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvStream-based TCP connection class.
00006  */
00007 #include "wvstreamlist.h"
00008 #include "wvtcp.h"
00009 #include <fcntl.h>
00010 #include <sys/socket.h>
00011 #include <netinet/in.h>
00012 #include <netinet/ip.h>
00013 #include <netinet/tcp.h>
00014 #include <errno.h>
00015 
00016 
00017 WvTCPConn::WvTCPConn(const WvIPPortAddr &_remaddr)
00018 {
00019     remaddr = _remaddr;
00020     resolved = true;
00021     connected = false;
00022     
00023     do_connect();
00024 }
00025 
00026 
00027 WvTCPConn::WvTCPConn(int _fd, const WvIPPortAddr &_remaddr)
00028         : WvStream(_fd)
00029 {
00030     remaddr = _remaddr;
00031     resolved = true;
00032     connected = true;
00033     
00034     nice_tcpopts();
00035 
00036     if (getfd() < 0)
00037         seterr(errno);
00038 }
00039 
00040 
00041 WvTCPConn::WvTCPConn(const WvString &_hostname, __u16 _port)
00042         : hostname(_hostname)
00043 {
00044     char *hnstr = hostname.edit(), *cptr;
00045     
00046     cptr = strchr(hnstr, ':');
00047     if (!cptr)
00048         cptr = strchr(hnstr, '\t');
00049     if (!cptr)
00050         cptr = strchr(hnstr, ' ');
00051     if (cptr)
00052     {
00053         *cptr++ = 0;
00054         remaddr.port = atoi(cptr);
00055     }
00056     
00057     if (_port)
00058         remaddr.port = _port;
00059     
00060     resolved = connected = false;
00061     
00062     WvIPAddr x(hostname);
00063     if (x != WvIPAddr())
00064     {
00065         remaddr = WvIPPortAddr(x, remaddr.port);
00066         resolved = true;
00067         do_connect();
00068     }
00069     else
00070         dns.findaddr(0, hostname, NULL);
00071 }
00072 
00073 
00074 WvTCPConn::~WvTCPConn()
00075 {
00076     // nothing to do
00077 }
00078 
00079 
00080 // Set a few "nice" options on our socket... (read/write, non-blocking, 
00081 // keepalive)
00082 void WvTCPConn::nice_tcpopts()
00083 {
00084     fcntl(getfd(), F_SETFD, FD_CLOEXEC);
00085     fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
00086 
00087     int value = 1;
00088     setsockopt(getfd(), SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));
00089 }
00090 
00091 
00092 void WvTCPConn::low_delay()
00093 {
00094     int value;
00095     
00096     value = 1;
00097     setsockopt(getfd(), SOL_TCP, TCP_NODELAY, &value, sizeof(value));
00098     
00099     value = IPTOS_LOWDELAY;
00100     setsockopt(getfd(), SOL_IP, IP_TOS, &value, sizeof(value));
00101 }
00102 
00103 
00104 void WvTCPConn::do_connect()
00105 {
00106     sockaddr *sa;
00107 
00108     rwfd = socket(PF_INET, SOCK_STREAM, 0);
00109     if (rwfd < 0)
00110     {
00111         seterr(errno);
00112         return;
00113     }
00114     
00115     nice_tcpopts();
00116     
00117     sa = remaddr.sockaddr();
00118     if (connect(getfd(), sa, remaddr.sockaddr_len()) < 0
00119         && errno != EINPROGRESS)
00120     {
00121         seterr(errno);
00122         delete sa;
00123         return;
00124     }
00125     
00126     delete sa;
00127 }
00128 
00129 
00130 void WvTCPConn::check_resolver()
00131 {
00132     const WvIPAddr *ipr;
00133     int dnsres = dns.findaddr(0, hostname, &ipr);
00134     
00135     if (dnsres == 0)
00136     {
00137         // error resolving!
00138         resolved = true;
00139         seterr(WvString("Unknown host \"%s\"", hostname));
00140     }
00141     else if (dnsres > 0)
00142     {
00143         remaddr = WvIPPortAddr(*ipr, remaddr.port);
00144         resolved = true;
00145         do_connect();
00146     }
00147 }
00148 
00149 #ifndef SO_ORIGINAL_DST
00150 # define SO_ORIGINAL_DST 80
00151 #endif
00152 
00153 WvIPPortAddr WvTCPConn::localaddr()
00154 {
00155     sockaddr_in sin;
00156     socklen_t sl = sizeof(sin);
00157     
00158     if (!isok())
00159         return WvIPPortAddr();
00160     
00161     if (getsockopt(getfd(), SOL_IP, SO_ORIGINAL_DST, (char*)&sin, &sl) < 0
00162         && getsockname(getfd(), (sockaddr *)&sin, &sl))
00163     {
00164         return WvIPPortAddr();
00165     }
00166     
00167     return WvIPPortAddr(&sin);
00168 }
00169 
00170 
00171 const WvIPPortAddr *WvTCPConn::src() const
00172 {
00173     return &remaddr;
00174 }
00175 
00176 
00177 bool WvTCPConn::pre_select(SelectInfo &si)
00178 {
00179     if (!resolved)
00180     {
00181         if (dns.pre_select(hostname, si))
00182             check_resolver();
00183     }
00184 
00185     if (resolved && isok()) // name might be resolved now.
00186     {
00187         bool oldw = si.wants.writable, retval;
00188         if (!isconnected()) si.wants.writable = true;
00189         retval = WvStream::pre_select(si);
00190         si.wants.writable = oldw;
00191         return retval;
00192     }
00193     else
00194         return false;
00195 }
00196                           
00197 bool WvTCPConn::post_select(SelectInfo &si)
00198 {
00199     bool result = false;
00200 
00201     if (!resolved)
00202         check_resolver();
00203     else
00204     {
00205         result = WvStream::post_select(si);
00206 
00207         if (result && !connected)
00208         {
00209             sockaddr *sa = remaddr.sockaddr();
00210             int retval = connect(getfd(), sa, remaddr.sockaddr_len());
00211             
00212             if (!retval || (retval < 0 && errno == EISCONN))
00213                 connected = result = true;
00214             else if (retval < 0 && errno != EINPROGRESS)
00215             {
00216                 seterr(errno);
00217                 result = true;
00218             }
00219             else
00220                 result = false;
00221             
00222             delete sa;
00223         }
00224     }
00225     
00226     return result;
00227 }
00228 
00229 
00230 bool WvTCPConn::isok() const
00231 {
00232     return !resolved || WvStream::isok();
00233 }
00234 
00235 
00236 WvTCPListener::WvTCPListener(const WvIPPortAddr &_listenport)
00237         : listenport(_listenport), auto_callback(NULL)
00238 {
00239     listenport = _listenport;
00240     auto_list = NULL;
00241     auto_userdata = NULL;
00242     
00243     sockaddr *sa = listenport.sockaddr();
00244     
00245     int x = 1;
00246 
00247     rwfd = socket(PF_INET, SOCK_STREAM, 0);
00248     if (rwfd < 0
00249         || setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x))
00250         || fcntl(getfd(), F_SETFD, 1)
00251         || bind(getfd(), sa, listenport.sockaddr_len())
00252         || listen(getfd(), 5))
00253     {
00254         seterr(errno);
00255     }
00256     
00257     if (listenport.port == 0) // auto-select a port number
00258     {
00259         socklen_t namelen = listenport.sockaddr_len();
00260         
00261         if (getsockname(getfd(), sa, &namelen) != 0)
00262             seterr(errno);
00263         else
00264             listenport = WvIPPortAddr((sockaddr_in *)sa);
00265     }
00266     
00267     delete sa;
00268 }
00269 
00270 
00271 WvTCPListener::~WvTCPListener()
00272 {
00273     close();
00274 }
00275 
00276 
00277 //#include <wvlog.h>
00278 void WvTCPListener::close()
00279 {
00280     WvStream::close();
00281 /*    WvLog log("ZAP!");
00282     
00283     log("Closing TCP LISTENER at %s!!\n", listenport);
00284     abort();*/
00285 }
00286 
00287 
00288 WvTCPConn *WvTCPListener::accept()
00289 {
00290     struct sockaddr_in sin;
00291     socklen_t len = sizeof(sin);
00292     int newfd;
00293     WvTCPConn *ret;
00294 
00295     newfd = ::accept(getfd(), (struct sockaddr *)&sin, &len);
00296     ret = new WvTCPConn(newfd, WvIPPortAddr(&sin));
00297     return ret;
00298 }
00299 
00300 
00301 void WvTCPListener::auto_accept(WvStreamList *list,
00302                                 WvStreamCallback callfunc, void *userdata)
00303 {
00304     auto_list = list;
00305     auto_callback = callfunc;
00306     auto_userdata = userdata;
00307     setcallback(accept_callback, this);
00308 }
00309 
00310 
00311 void WvTCPListener::accept_callback(WvStream &, void *userdata)
00312 {
00313     WvTCPListener &l = *(WvTCPListener *)userdata;
00314 
00315     WvTCPConn *connection = l.accept();
00316     connection->setcallback(l.auto_callback, l.auto_userdata);
00317     l.auto_list->append(connection, true);
00318 }
00319 
00320 
00321 size_t WvTCPListener::uread(void *, size_t)
00322 {
00323     return 0;
00324 }
00325 
00326 
00327 size_t WvTCPListener::uwrite(const void *, size_t)
00328 {
00329     return 0;
00330 }
00331 
00332 
00333 const WvIPPortAddr *WvTCPListener::src() const
00334 {
00335     return &listenport;
00336 }
00337 

Generated on Sun Aug 25 02:29:34 2002 for WvStreams by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002