00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00156 if (index != 0)
00157 {
00158 ::ResetEvent(eventArg);
00159 cc = 0;
00160 }
00161 else
00162 {
00163
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
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;
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 }
00282 extern Mutex gethostbynameMutex;
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
00315
00316
00317
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
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
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
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
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
00421 rv = hostentp->h_name;
00422 }
00423 }
00424 }
00425 }
00426
00427 return rv;
00428 }
00429 #endif
00430
00431
00432 }
00433
00434 }
00435