libassa
3.5.0
|
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