blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00039 #include "blocxx/BLOCXX_config.h" 00040 #include "blocxx/SocketException.hpp" 00041 #include "blocxx/SocketUtils.hpp" 00042 #include "blocxx/Assertion.hpp" 00043 #include "blocxx/Socket.hpp" 00044 #include "blocxx/Format.hpp" 00045 #include "blocxx/Thread.hpp" 00046 #include "blocxx/System.hpp" 00047 #include "blocxx/Select.hpp" 00048 #include "blocxx/TimeoutTimer.hpp" 00049 00050 #if defined(BLOCXX_WIN32) 00051 #include "blocxx/SocketAddress.hpp" 00052 #endif 00053 00054 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R 00055 #include "blocxx/Mutex.hpp" 00056 #include "blocxx/MutexLock.hpp" 00057 #endif 00058 00059 extern "C" 00060 { 00061 #if !defined(BLOCXX_WIN32) 00062 #include "blocxx/PosixUnnamedPipe.hpp" 00063 00064 #include <ctype.h> 00065 #include <sys/types.h> 00066 #include <sys/wait.h> 00067 #include <sys/time.h> 00068 #include <sys/socket.h> 00069 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H 00070 #include <sys/resource.h> 00071 #endif 00072 #include <netdb.h> 00073 #include <arpa/inet.h> 00074 #include <unistd.h> 00075 #endif 00076 } 00077 00078 #include <cstring> 00079 #include <cstdio> 00080 #include <cerrno> 00081 00082 namespace BLOCXX_NAMESPACE 00083 { 00084 00085 namespace SocketUtils 00086 { 00087 00089 String 00090 inetAddrToString(UInt64 addr) 00091 { 00092 sockaddr_in iaddr; 00093 iaddr.sin_family = AF_INET; 00094 iaddr.sin_addr.s_addr = addr; 00095 iaddr.sin_port = 0; 00096 #ifdef BLOCXX_HAVE_IPV6 00097 char buf[INET6_ADDRSTRLEN]; 00098 String s(inet_ntop(iaddr.sin_family, &(iaddr.sin_addr), buf, sizeof(buf))); 00099 #else 00100 String s(inet_ntoa(iaddr.sin_addr)); 00101 #endif 00102 00103 return s; 00104 } 00105 00106 #if defined(BLOCXX_WIN32) 00107 int 00108 waitForIO(SocketHandle_t fd, HANDLE eventArg, int timeOutSecs, 00109 long networkEvents) 00110 { 00111 return waitForIO(fd, eventArg, Timeout::relative(timeOutSecs), networkEvents); 00112 } 00113 00114 int 00115 waitForIO(SocketHandle_t fd, HANDLE eventArg, const Timeout& classTimeout, 00116 long networkEvents) 00117 { 00118 TimeoutTimer timer(classTimeout); 00119 00120 DWORD timeout= timer.asDWORDMs(); 00121 00122 if (networkEvents != -1L) 00123 { 00124 if(::WSAEventSelect(fd, eventArg, networkEvents) != 0) 00125 { 00126 BLOCXX_THROW(SocketException, 00127 Format("WSAEventSelect failed in waitForIO: %1", 00128 System::lastErrorMsg(true)).c_str()); 00129 } 00130 } 00131 00132 int cc; 00133 if(Socket::getShutDownMechanism() != NULL) 00134 { 00135 HANDLE events[2]; 00136 events[0] = Socket::getShutDownMechanism(); 00137 events[1] = eventArg; 00138 00139 DWORD index = ::WaitForMultipleObjects( 00140 2, 00141 events, 00142 FALSE, 00143 timeout); 00144 00145 switch (index) 00146 { 00147 case WAIT_FAILED: 00148 cc = -1; 00149 break; 00150 case WAIT_TIMEOUT: 00151 cc = ETIMEDOUT; 00152 break; 00153 default: 00154 index -= WAIT_OBJECT_0; 00155 // If not shutdown event, then reset 00156 if (index != 0) 00157 { 00158 ::ResetEvent(eventArg); 00159 cc = 0; 00160 } 00161 else 00162 { 00163 // Shutdown handle was signaled 00164 cc = -2; 00165 } 00166 break; 00167 } 00168 } 00169 else 00170 { 00171 switch(::WaitForSingleObject(eventArg, timeout)) 00172 { 00173 case WAIT_OBJECT_0: 00174 ::ResetEvent(eventArg); 00175 cc = 0; 00176 break; 00177 case WAIT_TIMEOUT: 00178 cc = ETIMEDOUT; 00179 break; 00180 default: 00181 cc = -1; 00182 break; 00183 } 00184 } 00185 00186 // Set socket back to blocking 00187 if(::WSAEventSelect(fd, eventArg, 0) != 0) 00188 { 00189 BLOCXX_THROW(SocketException, 00190 Format("Resetting socket with WSAEventSelect failed: %1", 00191 System::lastErrorMsg(true)).c_str()); 00192 } 00193 u_long ioctlarg = 0; 00194 ::ioctlsocket(fd, FIONBIO, &ioctlarg); 00195 return cc; 00196 } 00197 00198 #else 00199 00200 int 00201 waitForIO(SocketHandle_t fd, int timeOutSecs, SocketFlags::EWaitDirectionFlag waitFlag) 00202 { 00203 return waitForIO(fd, Timeout::relative(timeOutSecs), waitFlag); 00204 } 00205 00207 int 00208 waitForIO(SocketHandle_t fd, const Timeout& timeout, SocketFlags::EWaitDirectionFlag waitFlag) 00209 { 00210 if (fd == -1) 00211 { 00212 errno = EBADF; 00213 return -1; 00214 } 00215 00216 Select::SelectObject so(fd); 00217 if (waitFlag == SocketFlags::E_WAIT_FOR_INPUT) 00218 { 00219 so.waitForRead = true; 00220 } 00221 else if (waitFlag == SocketFlags::E_WAIT_FOR_OUTPUT) 00222 { 00223 so.waitForWrite = true; 00224 } 00225 else 00226 { 00227 so.waitForRead = true; 00228 so.waitForWrite = true; 00229 } 00230 Select::SelectObjectArray selarray; 00231 selarray.push_back(so); 00232 00233 PosixUnnamedPipeRef lUPipe; 00234 int pipefd = -1; 00235 if (Socket::getShutDownMechanism()) 00236 { 00237 UnnamedPipeRef foo = Socket::getShutDownMechanism(); 00238 lUPipe = foo.cast_to<PosixUnnamedPipe>(); 00239 BLOCXX_ASSERT(lUPipe); 00240 pipefd = lUPipe->getInputHandle(); 00241 } 00242 if (pipefd != -1) 00243 { 00244 so = Select::SelectObject(pipefd); 00245 so.waitForRead = true; 00246 selarray.push_back(so); 00247 } 00248 00249 int rc = Select::selectRW(selarray, timeout); 00250 switch (rc) 00251 { 00252 case Select::SELECT_TIMEOUT: 00253 rc = ETIMEDOUT; 00254 break; 00255 case 2: 00256 rc = -1; // pipe was signalled 00257 errno = ECANCELED; 00258 break; 00259 case 1: 00260 if (pipefd != -1) 00261 { 00262 if (selarray[1].readAvailable) 00263 { 00264 rc = -1; 00265 } 00266 } 00267 if (selarray[0].writeAvailable || selarray[0].readAvailable) 00268 { 00269 rc = 0; 00270 } 00271 break; 00272 default: 00273 rc = -1; 00274 } 00275 return rc; 00276 00277 } 00278 #endif // 00279 00280 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R 00281 } // end namespace SocketUtils 00282 extern Mutex gethostbynameMutex; // defined in SocketAddress.cpp 00283 namespace SocketUtils { 00284 #endif 00285 00286 #ifndef BLOCXX_WIN32 00287 String getFullyQualifiedHostName() 00288 { 00289 char hostName [2048]; 00290 if (gethostname (hostName, sizeof(hostName)) == 0) 00291 { 00292 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R 00293 MutexLock lock(gethostbynameMutex); 00294 struct hostent *he; 00295 if ((he = gethostbyname (hostName)) != 0) 00296 { 00297 return he->h_name; 00298 } 00299 else 00300 { 00301 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname failed: %1", h_errno).c_str()); 00302 } 00303 #else 00304 hostent hostbuf; 00305 hostent* host = &hostbuf; 00306 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6 || BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5) 00307 char buf[2048]; 00308 int h_err = 0; 00309 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3) 00310 hostent_data hostdata; 00311 int h_err = 0; 00312 #else 00313 #error Not yet supported: gethostbyname_r() with other argument counts. 00314 #endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */ 00315 // gethostbyname_r will randomly fail on some platforms/networks 00316 // maybe the DNS server is overloaded or something. So we'll 00317 // give it a few tries to see if it can get it right. 00318 bool worked = false; 00319 for (int i = 0; i < 10 && (!worked || host == 0); ++i) 00320 { 00321 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6) 00322 if (gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf), 00323 &host, &h_err) != -1) 00324 { 00325 worked = true; 00326 break; 00327 } 00328 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5) 00329 // returns NULL if not successful 00330 if ((host = gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf), &h_err))) { 00331 worked = true; 00332 break; 00333 } 00334 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3) 00335 if (gethostbyname_r(hostName, &hostbuf, &hostdata) == 0) 00336 { 00337 worked = true; 00338 break; 00339 } 00340 else 00341 { 00342 h_err = h_errno; 00343 } 00344 #else 00345 #error Not yet supported: gethostbyname_r() with other argument counts. 00346 #endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */ 00347 } 00348 if (worked && host != 0) 00349 { 00350 return host->h_name; 00351 } 00352 else 00353 { 00354 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname_r(%1) failed: %2", hostName, h_err).c_str()); 00355 } 00356 #endif 00357 } 00358 else 00359 { 00360 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)", errno, strerror(errno)).c_str()); 00361 } 00362 return ""; 00363 } 00364 #else 00365 // WIN32 defined 00366 String getFullyQualifiedHostName() 00367 { 00368 String rv; 00369 struct hostent *hostentp; 00370 char bfr[1024], ipaddrstr[128]; 00371 struct in_addr iaHost; 00372 00373 if(gethostname(bfr, sizeof(bfr)-1) == SOCKET_ERROR) 00374 { 00375 BLOCXX_THROW(SocketException, 00376 Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)", 00377 WSAGetLastError(), System::lastErrorMsg(true)).c_str()); 00378 } 00379 00380 if(strchr(bfr, '.')) 00381 { 00382 // Guess we already have the DNS name 00383 return String(bfr); 00384 } 00385 00386 if((hostentp = gethostbyname(bfr)) == NULL) 00387 { 00388 BLOCXX_THROW(SocketException, 00389 Format("SocketUtils::getFullyQualifiedHostName: gethostbyname" 00390 " failed: %1(%2)", WSAGetLastError(), 00391 System::lastErrorMsg(true)).c_str()); 00392 } 00393 00394 if(strchr(hostentp->h_name, '.')) 00395 { 00396 rv = hostentp->h_name; 00397 } 00398 else 00399 { 00400 sockaddr_in addr; 00401 addr.sin_family = AF_INET; 00402 addr.sin_port = 0; 00403 memcpy(&addr.sin_addr, hostentp->h_addr_list[0], sizeof(addr.sin_addr)); 00404 #ifdef BLOCXX_HAVE_IPV6 00405 char buf[INET6_ADDRSTRLEN]; 00406 rv = inet_ntop(addr.sin_family, &(addr.sin_addr), buf, sizeof(buf)); 00407 #else 00408 rv = inet_ntoa(addr.sin_addr); 00409 #endif 00410 00411 iaHost.s_addr = inet_addr(rv.c_str()); 00412 if(iaHost.s_addr != INADDR_NONE) 00413 { 00414 hostentp = gethostbyaddr((const char*)&iaHost, 00415 sizeof(struct in_addr), AF_INET); 00416 if(hostentp) 00417 { 00418 if(strchr(hostentp->h_name, '.')) 00419 { 00420 // GOT IT 00421 rv = hostentp->h_name; 00422 } 00423 } 00424 } 00425 } 00426 00427 return rv; 00428 } 00429 #endif 00430 00431 00432 } // end namespace SocketUtils 00433 00434 } // end namespace BLOCXX_NAMESPACE 00435