ulxr_tcpip_connection.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                ulxr_tcpip_connection.cpp  -  tcpip connection
00003                              -------------------
00004     begin                : Mon Apr 29 2002
00005     copyright            : (C) 2002-2007 by Ewald Arnold
00006     email                : ulxmlrpcpp@ewald-arnold.de
00007 
00008     $Id: ulxr_tcpip_connection.cpp 1063 2007-08-19 11:46:20Z ewald-arnold $
00009 
00010  ***************************************************************************/
00011 
00012 /**************************************************************************
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as
00016  * published by the Free Software Foundation; either version 2 of the License,
00017  * 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 Lesser General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  ***************************************************************************/
00029 
00030 // #define ULXR_SHOW_TRACE
00031 // #define ULXR_DEBUG_OUTPUT
00032 // #define ULXR_SHOW_READ
00033 // #define ULXR_SHOW_WRITE
00034 
00035 #define ULXR_REUSE_SOCKET
00036 
00037 #ifndef ULXR_OMIT_TCP_STUFF
00038 
00039 #define ULXR_NEED_EXPORTS
00040 #include <ulxmlrpcpp/ulxmlrpcpp.h>  // always first header
00041 
00042 #include <cerrno>
00043 
00044 #ifdef __SUN__
00045 #include <sys/systeminfo.h>
00046 #endif
00047 
00048 #ifdef __unix__
00049 #include <sys/socket.h>
00050 #include <netinet/tcp.h>
00051 
00052 #if defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H)
00053 #include <sys/epoll.h>
00054 #endif
00055 
00056 #endif
00057 
00058 //#include <iostream>
00059 
00060 #include <ulxmlrpcpp/ulxr_tcpip_connection.h>
00061 #include <ulxmlrpcpp/ulxr_htmlform_handler.h>
00062 #include <ulxmlrpcpp/ulxr_except.h>
00063 
00064 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00065 #include <ulxmlrpcpp/ulxr_mutex.h>
00066 #endif
00067 
00068 
00069 namespace ulxr {
00070 
00071 
00072 ULXR_API_IMPL0 TcpIpConnection::ServerSocketData::ServerSocketData(int s_no)
00073   : count(1)
00074   , socket_no(s_no)
00075 {
00076 }
00077 
00078 
00079 ULXR_API_IMPL0 TcpIpConnection::ServerSocketData::~ServerSocketData()
00080 {
00081   close();
00082 }
00083 
00084 
00085 ULXR_API_IMPL(int) TcpIpConnection::ServerSocketData::getSocket() const
00086 {
00087   return socket_no;
00088 }
00089 
00090 
00091 ULXR_API_IMPL(void) TcpIpConnection::ServerSocketData::incRef()
00092 {
00093     ++count;
00094 }
00095 
00096 
00097 ULXR_API_IMPL(int) TcpIpConnection::ServerSocketData::decRef()
00098 {
00099   if (count > 0)
00100     --count;
00101   return count;
00102 }
00103 
00104 
00105 ULXR_API_IMPL(bool) TcpIpConnection::ServerSocketData::isOpen()
00106 {
00107   return socket_no != -1;
00108 }
00109 
00110 
00111 ULXR_API_IMPL(void) TcpIpConnection::ServerSocketData::close()
00112 {
00113   ULXR_TRACE(ULXR_PCHAR("close"));
00114 #ifndef __unix__
00115   ::closesocket(socket_no);
00116 #else
00117   int ret;
00118   do
00119     ret = ::close(socket_no);
00120   while(ret < 0 && (errno == EINTR || errno == EAGAIN));
00121 
00122   if(ret < 0)
00123     throw ConnectionException(TransportError,
00124                               ULXR_PCHAR("close() failed for TcpIpConnection::ServerSocketData"), 500);
00125 #endif
00126   socket_no = -1;
00127 }
00128 
00129 
00130 ULXR_API_IMPL(void) TcpIpConnection::ServerSocketData::shutdown(int in_mode)
00131 {
00132   ULXR_TRACE(ULXR_PCHAR("shutdown") << in_mode);
00133   int ret;
00134   do
00135     ret = ::shutdown(socket_no, in_mode);
00136   while(ret < 0 && (errno == EINTR || errno == EAGAIN));
00137 
00138   if(ret < 0)
00139     throw ConnectionException(TransportError,
00140                               ULXR_PCHAR("shutdown() failed for TcpIpConnection::ServerSocketData"), 500);
00141 }
00142 
00143 
00145 
00146 
00147 struct TcpIpConnection::PImpl
00148 {
00149    CppString           serverdomain;
00150    unsigned            port;
00151    ServerSocketData   *server_data;
00152 
00153    CppString           host_name;
00154    struct sockaddr_in  hostdata;
00155    socklen_t           hostdata_len;
00156 
00157    CppString           remote_name;
00158    struct sockaddr_in  remotedata;
00159    socklen_t           remotedata_len;
00160 };
00161 
00162 
00163 ULXR_API_IMPL0 TcpIpConnection::TcpIpConnection(const TcpIpConnection &conn)
00164   : Connection(conn)
00165   , pimpl(new PImpl)
00166 {
00167   *pimpl = *conn.pimpl;
00168 }
00169 
00170 
00171 ULXR_API_IMPL0 TcpIpConnection::TcpIpConnection(bool I_am_server, long adr, unsigned prt)
00172   : Connection()
00173   , pimpl(new PImpl)
00174 {
00175   ULXR_TRACE(ULXR_PCHAR("TcpIpConnection(bool, long, uint)") << adr << ULXR_PCHAR(" ") << pimpl->port);
00176   init(prt);
00177 
00178   pimpl->hostdata.sin_addr.s_addr = htonl(adr);
00179 
00180   if (I_am_server)
00181   {
00182     pimpl->server_data = new ServerSocketData(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
00183     if (getServerHandle() < 0)
00184       throw ConnectionException(SystemError,
00185                                 ulxr_i18n(ULXR_PCHAR("Could not create socket: "))
00186                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00187 
00188 #ifdef ULXR_REUSE_SOCKET
00189     int sockOpt = 1;
00190     if (::setsockopt(getServerHandle(), SOL_SOCKET, SO_REUSEADDR,
00191                      (const char*)&sockOpt, sizeof(sockOpt)) < 0)
00192       throw ConnectionException(SystemError,
00193                                       ulxr_i18n(ULXR_PCHAR("Could not set reuse flag for socket: "))
00194                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00195 #endif
00196 
00197     int iOptVal = getTimeout() * 1000;
00198     int iOptLen = sizeof(int);
00199     ::setsockopt(getServerHandle(), SOL_SOCKET, SO_RCVTIMEO, (char*)&iOptVal, iOptLen);
00200     ::setsockopt(getServerHandle(), SOL_SOCKET, SO_SNDTIMEO, (char*)&iOptVal, iOptLen);
00201 
00202     if((::bind(getServerHandle(), (sockaddr*) &pimpl->hostdata, sizeof(pimpl->hostdata))) < 0)
00203       throw ConnectionException(SystemError,
00204                                 ulxr_i18n(ULXR_PCHAR("Could not bind adress: "))
00205                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00206 
00207     ::listen(getServerHandle(), 5);
00208   }
00209 }
00210 
00211 
00212 ULXR_API_IMPL0
00213   TcpIpConnection::TcpIpConnection(bool I_am_server, const CppString &dom, unsigned prt)
00214   : Connection()
00215   , pimpl(new PImpl)
00216 {
00217   ULXR_TRACE(ULXR_PCHAR("TcpIpConnection(bool, string, uint)") << dom << ULXR_PCHAR(" ") << pimpl->port);
00218   init(prt);
00219 
00220   pimpl->remote_name = dom;
00221 
00222   struct hostent *hp = getHostAdress(dom);
00223   if (hp == 0)
00224     throw ConnectionException(SystemError,
00225                               ulxr_i18n(ULXR_PCHAR("Host adress not found: ")) + pimpl->serverdomain, 500);
00226   memcpy(&(pimpl->hostdata.sin_addr), hp->h_addr_list[0], hp->h_length);
00227 
00228   if (I_am_server)
00229   {
00230     pimpl->server_data = new ServerSocketData(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
00231     if (getServerHandle() < 0)
00232       throw ConnectionException(SystemError,
00233                                 ulxr_i18n(ULXR_PCHAR("Could not create socket: "))
00234                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00235 #ifdef ULXR_REUSE_SOCKET
00236     int sockOpt = 1;
00237     if (::setsockopt(getServerHandle(), SOL_SOCKET, SO_REUSEADDR,
00238                      (const char*)&sockOpt, sizeof(sockOpt)) < 0)
00239       throw ConnectionException(SystemError,
00240                                 ulxr_i18n(ULXR_PCHAR("Could not set reuse flag for socket: "))
00241                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00242 #endif
00243 
00244     int iOptVal = getTimeout() * 1000;
00245     int iOptLen = sizeof(int);
00246     ::setsockopt(getServerHandle(), SOL_SOCKET, SO_RCVTIMEO, (char*)&iOptVal, iOptLen);
00247     ::setsockopt(getServerHandle(), SOL_SOCKET, SO_SNDTIMEO, (char*)&iOptVal, iOptLen);
00248 
00249     if((::bind(getServerHandle(), (sockaddr*) &pimpl->hostdata, sizeof(pimpl->hostdata))) < 0)
00250       throw ConnectionException(SystemError,
00251                                 ulxr_i18n(ULXR_PCHAR("Could not bind adress: "))
00252                                      + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00253 
00254     listen(getServerHandle(), 5);
00255   }
00256 }
00257 
00258 
00259 ULXR_API_IMPL(TcpIpConnection *) TcpIpConnection::makeClone()
00260 {
00261   return new TcpIpConnection(*this); // shallow copy !!
00262 }
00263 
00264 
00265 ULXR_API_IMPL(Connection *) TcpIpConnection::detach()
00266 {
00267   ULXR_TRACE(ULXR_PCHAR("detach"));
00268   TcpIpConnection *clone = makeClone();;
00269   clone->pimpl->server_data = 0;
00270 
00271   clone->setServerData(getServerData());
00272   if (getServerData() != 0)
00273     getServerData()->incRef();
00274 
00275   ULXR_TRACE(ULXR_PCHAR("detach getHandle() ") << getHandle());
00276   ULXR_TRACE(ULXR_PCHAR("detach clone->getHandle() ") << clone->getHandle());
00277   cut();
00278   ULXR_TRACE(ULXR_PCHAR("detach getHandle() ") << getHandle());
00279   ULXR_TRACE(ULXR_PCHAR("detach clone->getHandle() ") << clone->getHandle());
00280 
00281   ULXR_TRACE(ULXR_PCHAR("/detach"));
00282   return clone;
00283 }
00284 
00285 
00286 ULXR_API_IMPL(void) TcpIpConnection::setProxy(long adr, unsigned port)
00287 {
00288   ULXR_TRACE(ULXR_PCHAR("setProxy ") << adr << ULXR_PCHAR(" ") << port);
00289   pimpl->hostdata.sin_addr.s_addr = htonl(adr);
00290   pimpl->hostdata.sin_port = htons(port);
00291 }
00292 
00293 
00294 ULXR_API_IMPL(void) TcpIpConnection::setProxy(const CppString &dom, unsigned port)
00295 {
00296   ULXR_TRACE(ULXR_PCHAR("setProxy ") << dom << ULXR_PCHAR(" ") << port);
00297   struct hostent *hp = getHostAdress(dom);
00298   if (hp == 0)
00299     throw ConnectionException(SystemError,
00300                               ulxr_i18n(ULXR_PCHAR("Host adress for proxy not found: ")) + dom, 500);
00301   memcpy(&(pimpl->hostdata.sin_addr), hp->h_addr_list[0], hp->h_length);
00302   pimpl->hostdata.sin_port = htons(port);
00303 }
00304 
00305 
00306 ULXR_API_IMPL(void) TcpIpConnection::init(unsigned prt)
00307 {
00308   ULXR_TRACE(ULXR_PCHAR("init"));
00309 #if defined(__WIN32__)  && !defined (ULXR_NO_WSA_STARTUP)
00310   WORD wVersionRequested;
00311   WSADATA wsaData;
00312   wVersionRequested = MAKEWORD( 2, 0 );
00313 
00314   if (WSAStartup( wVersionRequested, &wsaData) != 0)
00315     throw ConnectionException(SystemError,
00316                               ulxr_i18n(ULXR_PCHAR("Could not initialize Windows sockets: "))
00317                                 + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00318 #endif
00319 
00320   pimpl->server_data = 0;
00321   setTcpNoDelay(false);
00322   pimpl->serverdomain = ULXR_PCHAR("");
00323   pimpl->remote_name = ULXR_PCHAR("");
00324   setTimeout(10);
00325   pimpl->port = prt;
00326   pimpl->hostdata_len = sizeof(pimpl->hostdata);
00327   pimpl->remotedata_len = sizeof(pimpl->remotedata);
00328   memset(&pimpl->hostdata, 0, sizeof(pimpl->hostdata));
00329   memset(&pimpl->remotedata, 0, sizeof(pimpl->remotedata));
00330   pimpl->hostdata.sin_port = htons(pimpl->port);
00331   pimpl->hostdata.sin_family = AF_INET;
00332 
00333   char buffer [1000];
00334   int ret = gethostname(buffer, sizeof(buffer)-1);
00335   if (ret != 0)
00336     throw ConnectionException(SystemError,
00337                               ulxr_i18n(ULXR_PCHAR("Could not get host name: "))
00338                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00339 
00340   pimpl->host_name = ULXR_GET_STRING(buffer);
00341 
00342 #if defined(__SUN__)
00343 
00344   long status = sysinfo(SI_SRPC_DOMAIN ,buffer, sizeof(buffer)-1);
00345   if (status == -1)
00346     throw ConnectionException(SystemError,
00347                               ulxr_i18n(ULXR_PCHAR("Could not get domain name: "))
00348                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00349 
00350   if (buffer[0] != 0)
00351   {
00352     pimpl->host_name += ULXR_PCHAR(".");
00353     pimpl->host_name += ULXR_GET_STRING(buffer);
00354   }
00355 
00356 #elif defined(__unix__) || defined(__CYGWIN__)
00357 
00358   ret = getdomainname(buffer, sizeof(buffer)-1);
00359   if (ret != 0)
00360     throw ConnectionException(SystemError,
00361                               ulxr_i18n(ULXR_PCHAR("Could not get domain name: "))
00362                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00363 
00364   if (buffer[0] != 0)
00365   {
00366     pimpl->host_name += ULXR_PCHAR(".");
00367     pimpl->host_name += ULXR_GET_STRING(buffer);
00368   }
00369 
00370 #elif _WIN32
00371 
00372 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00373   Mutex::Locker lock(gethostbynameMutex);
00374 #endif
00375 
00376   struct hostent *hostEntPtr = gethostbyname(getLatin1(pimpl->host_name).c_str());
00377   if (!hostEntPtr)
00378     throw ConnectionException(SystemError,
00379                               ulxr_i18n(ULXR_PCHAR("Could not get host+domain name: "))
00380                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00381   pimpl->host_name = ULXR_GET_STRING(hostEntPtr->h_name);
00382 
00383 #else
00384 # pragma message ("don't know how to determine the domain name")
00385 #endif
00386 }
00387 
00388 
00389 ULXR_API_IMPL(void) TcpIpConnection::asciiToInAddr(const char *address, struct in_addr &saddr)
00390 {
00391   memset (&saddr, 0, sizeof(in_addr));
00392   struct hostent *host;
00393 
00394   /* First try it as aaa.bbb.ccc.ddd. */
00395   saddr.s_addr = inet_addr(address);
00396   if ((int)saddr.s_addr == -1)
00397     throw ConnectionException(SystemError,
00398                               ulxr_i18n(ULXR_PCHAR("Could not perform inet_addr(): "))
00399                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00400 
00401 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00402   Mutex::Locker lock(gethostbynameMutex);
00403 #endif
00404 
00405   host = gethostbyname(address);
00406   if (host == 0)
00407     throw ConnectionException(SystemError,
00408                               ulxr_i18n(ULXR_PCHAR("Could not perform gethostname(): "))
00409                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00410 
00411   memmove((void*)&saddr, host->h_addr_list, sizeof(in_addr));
00412 }
00413 
00414 
00415 ULXR_API_IMPL(struct hostent *)
00416   TcpIpConnection::getHostAdress(const CppString &dom)
00417 {
00418   unsigned start = 0;
00419   if (dom.substr(start, 5) == ULXR_PCHAR("http:"))
00420     start += 5;
00421 
00422   if (dom.substr(start, 2) == ULXR_PCHAR("//"))
00423     start += 2;
00424 
00425   std::size_t slash = dom.find (ULXR_PCHAR("/"), start);
00426   if (slash != CppString::npos)
00427     pimpl->serverdomain = dom.substr(start, slash-1);
00428   else
00429     pimpl->serverdomain = dom;
00430 
00431 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00432   Mutex::Locker lock(gethostbynameMutex);
00433 #endif
00434 
00435   return gethostbyname(getLatin1(pimpl->serverdomain).c_str() );
00436 }
00437 
00438 
00439 ULXR_API_IMPL0 TcpIpConnection::~TcpIpConnection()
00440 {
00441   ULXR_TRACE(ULXR_PCHAR("~TcpIpConnection"));
00442   try
00443   {
00444     decrementServerRef();
00445   }
00446   catch(...)
00447   {
00448     // forget exception?
00449   }
00450   delete pimpl;
00451   pimpl = 0;
00452 }
00453 
00454 
00455 void TcpIpConnection::decrementServerRef(bool in_shutdown)
00456 {
00457   ULXR_TRACE(ULXR_PCHAR("decrementServerRef"));
00458 
00459   if (pimpl->server_data != 0 && pimpl->server_data->decRef() <= 0)
00460   {
00461     ULXR_TRACE(ULXR_PCHAR("delete serverdata ") << std::hex << (void*)pimpl->server_data << std::dec);
00462 
00463     if(in_shutdown)
00464     {
00465       ULXR_TRACE(ULXR_PCHAR("shutdown server_data"));
00466       if (pimpl->server_data->isOpen())
00467 #ifdef __WIN32__
00468         pimpl->server_data->shutdown(SD_BOTH);
00469 #else
00470         pimpl->server_data->shutdown(SHUT_RD);
00471 #endif
00472     }
00473 
00474     delete pimpl->server_data;
00475     pimpl->server_data = 0;
00476   }
00477 }
00478 
00479 
00480 ULXR_API_IMPL(bool) TcpIpConnection::isServerMode() const
00481 {
00482   return pimpl->server_data != 0;
00483 }
00484 
00485 
00486 ULXR_API_IMPL(void) TcpIpConnection::open()
00487 {
00488   ULXR_TRACE(ULXR_PCHAR("open"));
00489   if (isOpen() )
00490     throw RuntimeException(ApplicationError,
00491                            ulxr_i18n(ULXR_PCHAR("Attempt to open an already open connection")));
00492 
00493   if (pimpl->server_data != 0)
00494     throw ConnectionException(SystemError,
00495                               ulxr_i18n(ULXR_PCHAR("Connection is NOT prepared for client mode")), 500);
00496 //  resetConnection();
00497 
00498   setHandle(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
00499   if (getHandle() < 0)
00500     throw ConnectionException(SystemError,
00501                               ulxr_i18n(ULXR_PCHAR("Could not create socket: "))
00502                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00503 
00504   int iOptVal = getTimeout() * 1000;
00505   int iOptLen = sizeof(int);
00506   ::setsockopt(getHandle(), SOL_SOCKET, SO_RCVTIMEO, (char*)&iOptVal, iOptLen);
00507   ::setsockopt(getHandle(), SOL_SOCKET, SO_SNDTIMEO, (char*)&iOptVal, iOptLen);
00508   doTcpNoDelay();
00509 
00510   if(connect(getHandle(), (struct sockaddr *)&pimpl->hostdata, sizeof(pimpl->hostdata)) < 0)
00511     throw ConnectionException(SystemError,
00512                               ulxr_i18n(ULXR_PCHAR("Could not connect: "))
00513                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00514 
00515   ULXR_TRACE(ULXR_PCHAR("/open.peername"));
00516 #ifdef ULXR_ENABLE_GET_PEERNAME
00517   pimpl->remotedata_len = sizeof(pimpl->remotedata);
00518   if(getpeername(getHandle(),
00519                  (struct sockaddr *)&pimpl->remotedata,
00520                  &pimpl->remotedata_len)<0)
00521     throw ConnectionException(SystemError,
00522                               ulxr_i18n(ULXR_PCHAR("Could not get peer data: "))
00523                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00524 #ifdef __BORLANDC__
00525   pimpl->remote_name = ULXR_PCHAR("<remote-host>");  // FIXME, not working
00526   host = 0;
00527   host;
00528 #else
00529   else
00530   {
00531     ULXR_TRACE(ULXR_PCHAR("/open.hostby ") << ULXR_GET_STRING(inet_ntoa(pimpl->remotedata.sin_addr))
00532                << ULXR_PCHAR(":") << HtmlFormHandler::makeNumber(ntohs(pimpl->remotedata.sin_port)));
00533 
00534 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00535   Mutex::Locker lock(gethostbyaddrMutex);
00536 #endif
00537 
00538     struct hostent *host = 0;
00539 #ifdef ULXR_ENABLE_DNS_LOOKUP
00540     host = gethostbyaddr((char*)&pimpl->remotedata.sin_addr,
00541                          sizeof(pimpl->remotedata.sin_addr),
00542                          AF_INET);
00543 #endif
00544 
00545     if (0 == host)
00546     {
00547       pimpl->remote_name = ULXR_GET_STRING(inet_ntoa(pimpl->remotedata.sin_addr))
00548                            + ULXR_GET_STRING(":") + HtmlFormHandler::makeNumber(ntohs(pimpl->remotedata.sin_port));
00549       ULXR_TRACE(ULXR_PCHAR("/open.hostby.if") << pimpl->remote_name);
00550     }
00551     else
00552     {
00553       pimpl->remote_name = ULXR_GET_STRING(host->h_name);
00554       ULXR_TRACE(ULXR_PCHAR("/open.hostby.else ") << pimpl->remote_name);
00555     }
00556   }
00557 #endif
00558 
00559 #else // ULXR_ENABLE_GET_PEERNAME
00560   pimpl->remote_name = ULXR_GET_STRING("");
00561 #endif
00562 
00563   ULXR_TRACE(ULXR_PCHAR("/open"));
00564 }
00565 
00566 
00567 ULXR_API_IMPL(bool) TcpIpConnection::accept(int in_timeout)
00568 {
00569   ULXR_TRACE(ULXR_PCHAR("accept"));
00570   if (isOpen() )
00571     throw RuntimeException(ApplicationError,
00572                            ulxr_i18n(ULXR_PCHAR("Attempt to accept an already open connection")));
00573 
00574 //  resetConnection();
00575 
00576   if (pimpl->server_data == 0)
00577     throw ConnectionException(SystemError,
00578                               ulxr_i18n(ULXR_PCHAR("Connection is NOT prepared for server mode")), 500);
00579 
00580   pimpl->remotedata_len = sizeof(pimpl->remotedata);
00581 
00582   if (in_timeout != 0)
00583   {
00584 
00585 #if defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H)
00586 
00587 #ifdef __GNUC__
00588 // #warning ("message using epoll_*()")
00589 #endif
00590 
00591     ULXR_TRACE(ULXR_PCHAR("waiting for epoll_*()"));
00592     /* Epoll file descriptor */
00593     int epollfd;
00594     /* epoll register event structure */
00595     struct epoll_event ev_accept;
00596     memset(&ev_accept,0,sizeof(struct epoll_event));
00597 
00598     /* Create a epoll structure */
00599     if((epollfd = ::epoll_create(1/* Just a tip to the kernel */)) != -1)
00600     {
00601       /* Prepare the event structure to a dummy use of epoll */
00602       ev_accept.events = /*EPOLLET |*/ EPOLLIN;
00603       ev_accept.data.ptr = NULL;
00604       /* Check-return var  */
00605       int ctlresult;
00606       if((ctlresult = ::epoll_ctl(epollfd, EPOLL_CTL_ADD, getServerData()->getSocket(), &ev_accept)) == 0)
00607       {
00608         /* epoll receive event structure */
00609         struct epoll_event ev[1];
00610         memset(&ev[0],0,sizeof(struct epoll_event));
00611 
00612         int toval;
00613         if (in_timeout != 0)
00614           toval = in_timeout*1000;
00615         else
00616           toval = -1;
00617 
00618         int waitresult;
00619         if((waitresult = epoll_wait(epollfd,ev,1, toval)) == -1)
00620         {
00621           ::close(epollfd);
00622           throw ConnectionException(SystemError, ulxr_i18n(ULXR_PCHAR("Could not wait for the connection (epoll_wait() error):")), 500);
00623         }
00624 
00625         else
00626         {
00627           ::close(epollfd);
00628           if(waitresult == 0)
00629           { /* Timeout */
00630             return false;
00631           }
00632 
00633           else
00634           {
00635             if(waitresult == 1)
00636             {
00637               /* It is possible accept */
00638               /* Just keep running the following code outside the epoll test block... Do nothing here... */
00639             }
00640 
00641             else
00642             {
00643               /* Should not reach here */
00644               throw ConnectionException(SystemError,ulxr_i18n(ULXR_PCHAR("Problem while attempting to accept by epoll.")), 500);
00645             }
00646           }
00647         }
00648 
00649       }
00650 
00651       else
00652       {
00653         ::close(epollfd);
00654         throw ConnectionException(SystemError,ulxr_i18n(ULXR_PCHAR("Could not perform epoll_ctl() call: ")), 500);
00655       }
00656     }
00657 
00658     else
00659     {
00660       ::close(epollfd);
00661       throw ConnectionException(SystemError,ulxr_i18n(ULXR_PCHAR("Could not perform epoll_create() call: ")), 500);
00662     }
00663 
00664 #else
00665 
00666 #ifdef __GNUC__
00667 // #warning ("message using select()")
00668 #endif
00669 
00670     ULXR_TRACE(ULXR_PCHAR("waiting for select()"));
00671 
00672     fd_set oReadSockSet;
00673     FD_ZERO( &oReadSockSet );
00674     FD_SET( getServerData()->getSocket(), &oReadSockSet );
00675 
00676     struct timeval  tv;
00677     struct timeval  *ptv = 0;
00678     tv.tv_sec = in_timeout;
00679     tv.tv_usec = 0;
00680     if (in_timeout != 0)
00681       ptv = &tv;
00682 
00683     int ret = 0;
00684 
00685     if((ret = select(FD_SETSIZE, &oReadSockSet, NULL, NULL, ptv)) < 0)
00686       throw ConnectionException(SystemError,
00687           ulxr_i18n(ULXR_PCHAR("Could not wait for the connection (select() error):"))
00688           + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00689 
00690     // checking whether the timeout occured
00691     if(!ret)
00692     {
00693       ULXR_TRACE(ULXR_PCHAR("accept returns false"));
00694       return false;
00695     }
00696 
00697 #endif // ULXR_USE_EPOLL
00698 
00699   }
00700 
00701   ULXR_TRACE(ULXR_PCHAR("waiting for connection"));
00702   do
00703     setHandle(::accept(getServerHandle(),
00704                               (sockaddr*) &pimpl->remotedata, &pimpl->remotedata_len ));
00705   while(getHandle() < 0 && (errno == EINTR || errno == EAGAIN));
00706 
00707   if(getHandle() < 0)
00708     throw ConnectionException(SystemError,
00709                               ulxr_i18n(ULXR_PCHAR("Could not accept a connection: "))
00710                                    + ULXR_GET_STRING(getErrorString(getLastError())), 500);
00711 
00712   doTcpNoDelay();
00713 
00714 #ifdef ULXR_ENABLE_GET_PEERNAME
00715   struct hostent *host = 0;
00716 
00717 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
00718   Mutex::Locker lock(gethostbyaddrMutex);
00719 #endif
00720 
00721 #ifdef ULXR_ENABLE_DNS_LOOKUP
00722   host = gethostbyaddr((char*)&pimpl->remotedata.sin_addr,
00723                         sizeof(pimpl->remotedata.sin_addr),
00724                         AF_INET);
00725 #endif
00726 
00727   if (0 == host)
00728     pimpl->remote_name = ULXR_GET_STRING(inet_ntoa(pimpl->remotedata.sin_addr))
00729                          + ULXR_GET_STRING(":") + HtmlFormHandler::makeNumber(ntohs(pimpl->remotedata.sin_port));
00730   else
00731     pimpl->remote_name = ULXR_GET_STRING(host->h_name);
00732 #else
00733   pimpl->remote_name = ULXR_PCHAR("");
00734 #endif
00735 
00736   ULXR_TRACE(ULXR_PCHAR("/accept"));
00737   return true;
00738 }
00739 
00740 
00741 ULXR_API_IMPL(unsigned) TcpIpConnection::getPort()
00742 {
00743   if(pimpl->port == 0)
00744   {
00745     struct sockaddr_in saddr_in;
00746     socklen_t size = sizeof(struct sockaddr_in);
00747 
00748     int err = getsockname(getServerHandle(), (struct sockaddr*) &saddr_in, &size);
00749     if(!err)
00750       pimpl->port = ntohs(saddr_in.sin_port);
00751   }
00752 
00753   return pimpl->port;
00754 }
00755 
00756 
00757 ULXR_API_IMPL(CppString) TcpIpConnection::getHostName() const
00758 {
00759   return pimpl->host_name;
00760 }
00761 
00762 
00763 ULXR_API_IMPL(CppString) TcpIpConnection::getServerDomain() const
00764 {
00765   return pimpl->serverdomain;
00766 }
00767 
00768 
00769 ULXR_API_IMPL(CppString) TcpIpConnection::getPeerName() const
00770 {
00771   return pimpl->remote_name;
00772 }
00773 
00774 
00775 ULXR_API_IMPL(void) TcpIpConnection::setServerData (ServerSocketData *in_server_data)
00776 {
00777   ULXR_TRACE(ULXR_PCHAR("setServerData ") << std::hex << (void*)in_server_data
00778                                                       << ULXR_PCHAR(" ") << (void*)pimpl->server_data << std::dec);
00779   // first closing the previous server, but no shutdown (a forked process can
00780   // be using it)!
00781   if(pimpl->server_data != 0)
00782     decrementServerRef();
00783 
00784   pimpl->server_data = in_server_data;
00785 }
00786 
00787 
00788 ULXR_API_IMPL(int) TcpIpConnection::getServerHandle ()
00789 {
00790   if (pimpl->server_data != 0)
00791     return pimpl->server_data->getSocket();
00792 
00793   return -1;
00794 }
00795 
00796 
00797 ULXR_API_IMPL(TcpIpConnection::ServerSocketData *) TcpIpConnection::getServerData () const
00798 {
00799   ULXR_TRACE(ULXR_PCHAR("getServerData ") << std::hex << (void*)pimpl->server_data << std::dec);
00800   return pimpl->server_data;
00801 }
00802 
00803 
00804 ULXR_API_IMPL(void) TcpIpConnection::shutdown(int in_mode)
00805 {
00806     int handle = getServerHandle ();
00807     if (handle < 0)
00808       handle = getHandle();
00809 
00810     ULXR_TRACE(ULXR_PCHAR("shutdown for ") << handle);
00811 
00812     int ret;
00813     do
00814       ret = ::shutdown(handle, in_mode);
00815     while(ret < 0 && (errno == EINTR || errno == EAGAIN));  // @todo remove errne check?
00816 
00817     if(ret < 0)
00818       throw ConnectionException(TransportError,
00819                                 ULXR_PCHAR("Shutdown failed: ")+getErrorString(getLastError()), 500);
00820 
00821     ULXR_TRACE(ULXR_PCHAR("shutdown succeeded"));
00822 }
00823 
00824 
00825 ULXR_API_IMPL(void) TcpIpConnection::close()
00826 {
00827   ULXR_TRACE(ULXR_PCHAR("close"));
00828 #ifdef ULXR_ENABLE_GET_PEERNAME
00829 //  pimpl->remote_name = ULXR_PCHAR("");
00830 #endif
00831   Connection::close();
00832 }
00833 
00834 
00835 ULXR_API_IMPL(int) TcpIpConnection::abortOnClose(int bOn)
00836 {
00837   linger sock_linger_struct = {1, 0};
00838   sock_linger_struct.l_onoff = bOn;
00839 
00840 #ifdef __WIN32__
00841   return setsockopt(getServerHandle(), SOL_SOCKET, SO_LINGER,
00842                     (const char*)&sock_linger_struct, sizeof(linger));
00843 #else
00844   return setsockopt(getServerHandle(), SOL_SOCKET, SO_LINGER,
00845                     &sock_linger_struct, sizeof(linger));
00846 #endif
00847 }
00848 
00849 
00850 ULXR_API_IMPL(void) TcpIpConnection::setTcpNoDelay(bool bOn)
00851 {
00852   noDelayOpt = 0;
00853   if (bOn)
00854     noDelayOpt = 1;
00855   doTcpNoDelay();
00856 }
00857 
00858 
00859 ULXR_API_IMPL(int) TcpIpConnection::doTcpNoDelay()
00860 {
00861  int sock;
00862  if (getServerData() != 0)
00863    sock = getServerData()->getSocket();
00864  else
00865    sock = getHandle();
00866 
00867  int ret = -1;
00868  if (sock > 0)
00869 #ifdef __WIN32__
00870    ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
00871                     (const char*)&noDelayOpt, sizeof(noDelayOpt));
00872 #else
00873    ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
00874                     &noDelayOpt, sizeof(noDelayOpt));
00875 #endif
00876 
00877   ULXR_TRACE(ULXR_PCHAR("/doTcpNoDelay:") << noDelayOpt
00878             << ULXR_PCHAR(" ret: ") << ret
00879             << ULXR_PCHAR(" sock: ") << sock);
00880   return ret;
00881 }
00882 
00883 
00884 ULXR_API_IMPL(CppString) TcpIpConnection::getInterfaceName()
00885 {
00886   return ULXR_PCHAR("tcpip");
00887 }
00888 
00889 
00890 ULXR_API_IMPL(int) TcpIpConnection::getLastError()
00891 {
00892 #ifdef __WIN32__
00893     return(WSAGetLastError());
00894 #else
00895     return(errno);
00896 #endif
00897 }
00898 
00899 
00900 }  // namespace ulxr
00901 
00902 
00903 #endif // ULXR_OMIT_TCP_STUFF

Generated on Sun Aug 19 20:08:57 2007 for ulxmlrpcpp by  doxygen 1.5.1