/home/vlg/develop/libASSA/libassa/assa/IPv4Socket.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 //                          IPv4Socket.cpp
00004 //------------------------------------------------------------------------------
00005 //  Copyright (C) 1997-2002  Vladislav Grinchenko 
00006 //
00007 //  This library is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU Library General Public
00009 //  License as published by the Free Software Foundation; either
00010 //  version 2 of the License, or (at your option) any later version.
00011 //------------------------------------------------------------------------------
00012 #if defined(WIN32)
00013 #   include <errno.h>
00014 #   include <ws2tcpip.h>
00015 #else
00016 #   include <sys/errno.h>
00017 #endif
00018 
00019 #include "assa/MemDump.h"
00020 #include "assa/IPv4Socket.h"
00021 
00022 using namespace ASSA;
00023 
00024 Streambuf* 
00025 IPv4Socket::
00026 rdbuf (Streambuf* sb_) 
00027 { 
00028     trace_with_mask("IPv4Socket::rdbuf(sb_)",SOCKTRACE);
00029 
00030     if (sb_ == 0 || sb_ == m_rdbuf) {
00031         return (sb_);
00032     }
00033     Streambuf* old = m_rdbuf;
00034     m_rdbuf = sb_;
00035     return (old);
00036 }
00037 
00038 
00039 bool
00040 IPv4Socket::
00041 open (const int domain_)
00042 {
00043     trace_with_mask("IPv4Socket::open",SOCKTRACE);
00044     
00045     m_type = domain_;
00046 
00047     m_fd = ::socket(domain_, SOCK_STREAM, 0);
00048 
00049     if (!is_valid_handler (m_fd)) {
00050         EL((ASSAERR,"OS::socket() error: m_fd = %d\n", m_fd));
00051         setstate (Socket::failbit);
00052         disable_handler (m_fd);
00053         return (false);
00054     }
00055     DL ((SOCK,"domain = %d, m_fd = %d\n", domain_, m_fd));
00056 
00057     clear ();
00058     turnOptionOn (Socket::nonblocking);
00059 
00060     return (true);
00061 }
00062 
00063 bool
00064 IPv4Socket::
00065 close()
00066 {
00067     trace_with_mask("IPv4Socket::close()",SOCKTRACE);
00068 
00069     if (is_valid_handler (m_fd)) {
00070         DL((SOCK,"Closed FD: %d\n",m_fd));
00071 
00072         /*--- Flush data in output stream buffer ---*/
00073         flush ();
00074         close_handler(m_fd);
00075         setstate (Socket::failbit);
00076 
00077         /*--- 
00078           Socket can be re-opened in the future.
00079           If there is some bytes left in it since last read(2),
00080           clean them up.
00081           ---*/
00082 
00083         if (m_rdbuf && m_rdbuf->in_avail ()) {
00084             for (int c; (c=m_rdbuf->sbumpc ()) != EOF;) { }
00085         }
00086     }
00087     return (true);
00088 }
00089 
00090 bool
00091 IPv4Socket::
00092 connect (const Address& his_address_)
00093 {
00094     trace_with_mask("IPv4Socket::connect()",SOCKTRACE);
00095 
00096     if (!is_valid_handler (m_fd) && open (getDomain()) == false) {
00097         return false;
00098     }
00099 
00100     int ret = ::connect (m_fd, 
00101                          (SA*) his_address_.getAddress(),
00102                          his_address_.getLength());
00103     if (ret < 0) 
00104     {
00105         int e = get_errno ();   // is ASYNC connect in progress?
00106         if (e == EINPROGRESS || e == EWOULDBLOCK) { 
00107             DL((SOCK,"FD: %d OS::connect() error\n",m_fd));
00108         }
00109         else {
00110             EL((SOCK,"FD: %d OS::connect() error\n",m_fd));
00111         }
00112         return (false);
00113     }
00114 
00115     clear ();
00116 
00117     DL((SOCK,"Connection opened on FD: %d\n", m_fd));
00118     return (true);
00119 }
00120 
00121 bool 
00122 IPv4Socket::
00123 bind (const Address& addr_)
00124 {
00125     trace_with_mask("IPv4Socket::bind",SOCKTRACE);
00126 
00127 #if !defined(WIN32)
00128 
00131     if ( getDomain() == AF_UNIX ) {
00132         char* p = ((SA_UN *) addr_.getAddress())->sun_path;
00133         m_path = new char[strlen(p)+1];
00134         strcpy(m_path, p);
00135         struct stat sb;
00136 
00137         if (stat (m_path, &sb) == 0) {
00138             if ( S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode) ) {
00139                 unlink(m_path);
00140             }
00141         }
00142     }
00143 #endif
00144 
00145     /*---
00146       From Stevens, Ch 7.5 (p.196):
00147       "Set the SO_REUSEADDR socket option before calling bind(2)
00148       in all TCP servers."
00149       ---*/
00150     Assure_return ( turnOptionOn (reuseaddr) );
00151 
00152     int rt = ::bind(m_fd, addr_.getAddress(), addr_.getLength());
00153 
00154     if ( rt < 0) {
00155         EL((SOCK,"::bind() FD: %d failed\n",m_fd));
00156         setstate (Socket::failbit);
00157         return (false);
00158     }
00159     Assure_return ( (::listen(m_fd, 5) == 0) );
00160     return (true);
00161 }
00162 
00174 IPv4Socket*
00175 IPv4Socket::
00176 accept ()
00177 {
00178     trace_with_mask("IPv4Socket::accept",SOCKTRACE);
00179 
00180     socklen_t length = 0;
00181     SA*       remote_address = NULL;
00182     handler_t new_fd;
00183 
00184     disable_handler (new_fd);
00185 
00186     if ( getDomain() == AF_UNIX ) {
00187         length = sizeof(struct sockaddr_in);
00188         remote_address = (SA*) new SA_IN;
00189     }
00190     else   /* AF_INET */
00191     { 
00192         remote_address = (SA*) new SA_UN;
00193         length = sizeof(struct sockaddr_un);
00194     }
00195     memset(remote_address, 0, length);
00196 
00197 #if !defined (_CYGWIN32__)
00198     new_fd = ::accept(m_fd, remote_address, &length);
00199 #else
00200     new_fd = ::accept(m_fd, remote_address, (int*)&length);
00201 #endif
00202     
00203     if (!is_valid_handler (new_fd)) {
00204         EL((ASSAERR,"::accept() failed (new_fd=%d)\n", new_fd));
00205         close();
00206         return NULL;
00207     }
00208     if (length == sizeof(SA_IN)) {
00209         SA_IN* sa_in = (SA_IN*) remote_address;
00210 
00211         DL((SOCK,"Accepted new TCP connection from Addr %s, port %d\n", 
00212             inet_ntoa(sa_in->sin_addr), ntohs( sa_in->sin_port)));
00213     }
00214     else {
00215 #if !defined(WIN32)
00216         SA_UN* sa_un = (SA_UN*) remote_address;
00217         DL((SOCK,"Accepted new UNIX connection from %s\n", sa_un->sun_path));
00218 #endif
00219     }
00220     delete remote_address;
00221 
00222     IPv4Socket* s = new IPv4Socket (new_fd);
00223     s->clear ();
00224     s->turnOptionOn (Socket::nonblocking);
00225     return s;
00226 }
00227 
00228 int
00229 IPv4Socket::
00230 read (char* packet_, const unsigned int size_)
00231 {
00232     trace_with_mask("IPv4Socket::read",SOCKTRACE);
00233 
00234     register int len;
00235     register int sz = size_;
00236     char* tmp = packet_;
00237     
00238     if (!is_valid_handler (m_fd) < 0) {
00239         return -1;
00240     }
00241 
00242     len = 0;
00243     if (m_rdbuf->unbuffered ()) { 
00244         /*
00245           --- This needs to be redesigned ---
00246           I should read a character at a time in loop,
00247           until I get all characters, or EWOULDBLOCK or EOF.
00248           If ::read() returns 0 or -1, it will be converted
00249           by sbumpc() into EOF. Otherwise, sbumpc() returns
00250           character read. Is this the right thing here to do? 
00251         */
00252         if ((len = m_rdbuf->sbumpc ()) >= 0) {
00253             *tmp = len; 
00254             len = 1;
00255         }
00256     }
00257     else {
00258         len = m_rdbuf->sgetn (tmp, sz);
00259     }
00260     if (len == -1) 
00261     {
00264         if (get_errno () != EWOULDBLOCK) {
00265             EL((ASSAERR,"::read (fd=%d) failed.\n",m_fd));
00266             setstate (Socket::failbit);
00267         }
00268         return len;
00269     }
00270     tmp += len;
00271     sz  -= len;
00272 
00273     if ((size_ - sz) == 0) 
00274     {
00275         DL((SOCK,"Peer has dropped connection FD: %d\n",m_fd));
00276         setstate (Socket::failbit | Socket::eofbit);
00277         return 0;
00278     }
00279 
00280     DL((SOCKTRACE,"==> FD: %d Received %d bytes\n", m_fd, size_ - sz));
00281     MemDump::dump_to_log (SOCKTRACE, "Data received:", packet_, size_ - sz);
00282 
00283     /*
00284       Return number of bytes read. If all requested bytes have been
00285       read, then sz is 0 and size_ is returned. If sz != 0, then
00286       writer has sent us a partial packet.
00287     */
00288     return (size_ - sz);        
00289 }
00290 
00291 int
00292 IPv4Socket::
00293 write(const char* packet_, const unsigned int size_)
00294 {
00295     trace_with_mask("IPv4Socket::write()",SOCKTRACE);
00296 
00297     int ret = 0;
00298 
00299     if (!is_valid_handler (m_fd)) {
00300         return -1;
00301     }
00302 
00303     if (m_rdbuf->unbuffered ()) 
00304     {
00305         int wlen = size_;
00306         char* p = (char*) packet_;
00307 
00308         while (wlen-- > 0) {
00309             if (m_rdbuf->sputc (*p++) == EOF) {
00310                 return (EOF);
00311             }
00312         }
00313         ret = p - packet_;
00314     }
00315     else {
00316         ret = m_rdbuf->sputn ((char*) packet_, size_);
00317     }
00318 
00319     if (ret > 0) {
00320         DL((SOCK,"<= FD: %d Wrote %d bytes (requested %d bytes)\n",
00321             m_fd, ret, size_));
00322         MemDump::dump_to_log (SOCK, "Data written", (char*)packet_, ret);
00323     }
00324     return ret;
00325 }
00326 
00327 IPv4Socket*
00328 IPv4Socket::
00329 clone () const
00330 {
00331     const char self[] = "IPv4Socket::clone"; 
00332     trace_with_mask(self,SOCKTRACE);
00333 
00334     handler_t nfd = dup (m_fd);
00335     IPv4Socket* s = new IPv4Socket (nfd);
00336 
00337     DL((SOCK,"Original socket has %d bytes in its get_area\n",
00338         m_rdbuf->in_avail ()));
00339 
00340     if (!is_valid_handler (nfd) || !good ()) {
00341         s->setstate (Socket::failbit);
00342     }
00343     else {
00344         s->clear ();
00345     }
00346 
00347     return s;
00348 }
00349 
00350 

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6