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
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/Select.hpp"
00040 #include "blocxx/SocketException.hpp"
00041 #include "blocxx/SocketUtils.hpp"
00042 #include "blocxx/PosixUnnamedPipe.hpp"
00043 #include "blocxx/Assertion.hpp"
00044 #include "blocxx/Socket.hpp"
00045 #include "blocxx/Format.hpp"
00046 #include "blocxx/Thread.hpp"
00047 #include "blocxx/System.hpp"
00048
00049 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R
00050 #include "blocxx/Mutex.hpp"
00051 #include "blocxx/MutexLock.hpp"
00052 #endif
00053
00054 extern "C"
00055 {
00056 #if !defined(BLOCXX_WIN32)
00057 #ifdef BLOCXX_HAVE_SYS_POLL_H
00058 #include <sys/poll.h>
00059 #elif defined (BLOCXX_HAVE_SYS_SELECT_H)
00060 #include <sys/select.h>
00061 #else
00062 #error "port me!"
00063 #endif
00064
00065 #include <ctype.h>
00066 #include <sys/types.h>
00067 #include <sys/wait.h>
00068 #include <sys/time.h>
00069 #include <sys/socket.h>
00070 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H
00071 #include <sys/resource.h>
00072 #endif
00073 #include <netdb.h>
00074 #include <arpa/inet.h>
00075 #include <unistd.h>
00076 #endif
00077 }
00078
00079 #include <cstring>
00080 #include <cstdio>
00081 #include <cerrno>
00082
00083 namespace BLOCXX_NAMESPACE
00084 {
00085
00086 namespace SocketUtils
00087 {
00088
00090 String
00091 inetAddrToString(UInt64 addr)
00092 {
00093 struct in_addr iaddr;
00094 iaddr.s_addr = addr;
00095 String s(inet_ntoa(iaddr));
00096 return s;
00097 }
00098 #ifndef MAX
00099 #define MAX(A,B) (((A) > (B))? (A): (B))
00100 #endif
00101
00102 #if defined(BLOCXX_WIN32)
00103 int
00104 waitForIO(SocketHandle_t fd, HANDLE eventArg, int timeOutSecs,
00105 long networkEvents)
00106 {
00107 DWORD timeout = (timeOutSecs != -1)
00108 ? static_cast<DWORD>(timeOutSecs * 1000)
00109 : INFINITE;
00110
00111 if (networkEvents != -1L)
00112 {
00113 if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
00114 {
00115 BLOCXX_THROW(SocketException,
00116 Format("WSAEventSelect failed in waitForIO: %1",
00117 System::lastErrorMsg(true)).c_str());
00118 }
00119 }
00120
00121 int cc;
00122 if(Socket::getShutDownMechanism() != NULL)
00123 {
00124 HANDLE events[2];
00125 events[0] = Socket::getShutDownMechanism();
00126 events[1] = eventArg;
00127
00128 DWORD index = ::WaitForMultipleObjects(
00129 2,
00130 events,
00131 FALSE,
00132 timeout);
00133
00134 switch (index)
00135 {
00136 case WAIT_FAILED:
00137 cc = -1;
00138 break;
00139 case WAIT_TIMEOUT:
00140 cc = ETIMEDOUT;
00141 break;
00142 default:
00143 index -= WAIT_OBJECT_0;
00144
00145 if (index != 0)
00146 {
00147 ::ResetEvent(eventArg);
00148 cc = 0;
00149 }
00150 else
00151 {
00152
00153 cc = -2;
00154 }
00155 break;
00156 }
00157 }
00158 else
00159 {
00160 switch(::WaitForSingleObject(eventArg, timeout))
00161 {
00162 case WAIT_OBJECT_0:
00163 ::ResetEvent(eventArg);
00164 cc = 0;
00165 break;
00166 case WAIT_TIMEOUT:
00167 cc = ETIMEDOUT;
00168 break;
00169 default:
00170 cc = -1;
00171 break;
00172 }
00173 }
00174
00175
00176 if(::WSAEventSelect(fd, eventArg, 0) != 0)
00177 {
00178 BLOCXX_THROW(SocketException,
00179 Format("Resetting socket with WSAEventSelect failed: %1",
00180 System::lastErrorMsg(true)).c_str());
00181 }
00182 u_long ioctlarg = 0;
00183 ::ioctlsocket(fd, FIONBIO, &ioctlarg);
00184 return cc;
00185 }
00186
00187 #else
00188
00189 int
00190 waitForIO(SocketHandle_t fd, int timeOutSecs, SocketFlags::EWaitDirectionFlag waitFlag)
00191 {
00192 if (fd == -1)
00193 {
00194 errno = EBADF;
00195 return -1;
00196 }
00197
00198 Select::SelectObject so(fd);
00199 if (waitFlag == SocketFlags::E_WAIT_FOR_INPUT)
00200 {
00201 so.waitForRead = true;
00202 }
00203 else if (waitFlag == SocketFlags::E_WAIT_FOR_OUTPUT)
00204 {
00205 so.waitForWrite = true;
00206 }
00207 else
00208 {
00209 so.waitForRead = true;
00210 so.waitForWrite = true;
00211 }
00212 Select::SelectObjectArray selarray;
00213 selarray.push_back(so);
00214
00215 PosixUnnamedPipeRef lUPipe;
00216 int pipefd = -1;
00217 if (Socket::getShutDownMechanism())
00218 {
00219 UnnamedPipeRef foo = Socket::getShutDownMechanism();
00220 lUPipe = foo.cast_to<PosixUnnamedPipe>();
00221 BLOCXX_ASSERT(lUPipe);
00222 pipefd = lUPipe->getInputHandle();
00223 }
00224 if (pipefd != -1)
00225 {
00226 so = Select::SelectObject(pipefd);
00227 so.waitForRead = true;
00228 selarray.push_back(so);
00229 }
00230
00231 int rc = Select::selectRW(selarray, timeOutSecs*1000);
00232 switch (rc)
00233 {
00234 case Select::SELECT_TIMEOUT:
00235 rc = ETIMEDOUT;
00236 break;
00237 case 2:
00238 rc = -1;
00239 break;
00240 case 1:
00241 if (pipefd != -1)
00242 {
00243 if (selarray[1].readAvailable)
00244 {
00245 rc = -1;
00246 }
00247 }
00248 if (selarray[0].writeAvailable || selarray[0].readAvailable)
00249 {
00250 rc = 0;
00251 }
00252 break;
00253 default:
00254 rc = -1;
00255 }
00256 return rc;
00257 }
00258 #endif
00259
00260 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R
00261 }
00262 extern Mutex gethostbynameMutex;
00263 namespace SocketUtils {
00264 #endif
00265
00266 #ifndef BLOCXX_WIN32
00267 String getFullyQualifiedHostName()
00268 {
00269 char hostName [2048];
00270 if (gethostname (hostName, sizeof(hostName)) == 0)
00271 {
00272 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R
00273 MutexLock lock(gethostbynameMutex);
00274 struct hostent *he;
00275 if ((he = gethostbyname (hostName)) != 0)
00276 {
00277 return he->h_name;
00278 }
00279 else
00280 {
00281 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname failed: %1", h_errno).c_str());
00282 }
00283 #else
00284 hostent hostbuf;
00285 hostent* host = &hostbuf;
00286 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6 || BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5)
00287 char buf[2048];
00288 int h_err = 0;
00289 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3)
00290 hostent_data hostdata;
00291 int h_err = 0;
00292 #else
00293 #error Not yet supported: gethostbyname_r() with other argument counts.
00294 #endif
00295
00296
00297
00298 bool worked = false;
00299 for (int i = 0; i < 10 && (!worked || host == 0); ++i)
00300 {
00301 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6)
00302 if (gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf),
00303 &host, &h_err) != -1)
00304 {
00305 worked = true;
00306 break;
00307 }
00308 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5)
00309
00310 if ((host = gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf), &h_err))) {
00311 worked = true;
00312 break;
00313 }
00314 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3)
00315 if (gethostbyname_r(hostName, &hostbuf, &hostdata) == 0)
00316 {
00317 worked = true;
00318 break;
00319 }
00320 else
00321 {
00322 h_err = h_errno;
00323 }
00324 #else
00325 #error Not yet supported: gethostbyname_r() with other argument counts.
00326 #endif
00327 }
00328 if (worked && host != 0)
00329 {
00330 return host->h_name;
00331 }
00332 else
00333 {
00334 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname_r(%1) failed: %2", hostName, h_err).c_str());
00335 }
00336 #endif
00337 }
00338 else
00339 {
00340 BLOCXX_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)", errno, strerror(errno)).c_str());
00341 }
00342 return "";
00343 }
00344 #else
00345
00346 String getFullyQualifiedHostName()
00347 {
00348 String rv;
00349 struct hostent *hostentp;
00350 char bfr[1024], ipaddrstr[128];
00351 struct in_addr iaHost;
00352
00353 if(gethostname(bfr, sizeof(bfr)-1) == SOCKET_ERROR)
00354 {
00355 BLOCXX_THROW(SocketException,
00356 Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)",
00357 WSAGetLastError(), System::lastErrorMsg(true)).c_str());
00358 }
00359
00360 if(strchr(bfr, '.'))
00361 {
00362
00363 return String(bfr);
00364 }
00365
00366 if((hostentp = gethostbyname(bfr)) == NULL)
00367 {
00368 BLOCXX_THROW(SocketException,
00369 Format("SocketUtils::getFullyQualifiedHostName: gethostbyname"
00370 " failed: %1(%2)", WSAGetLastError(),
00371 System::lastErrorMsg(true)).c_str());
00372 }
00373
00374 if(strchr(hostentp->h_name, '.'))
00375 {
00376 rv = hostentp->h_name;
00377 }
00378 else
00379 {
00380 rv = inet_ntoa(*(struct in_addr*) (hostentp->h_addr_list[0]));
00381 iaHost.s_addr = inet_addr(rv.c_str());
00382 if(iaHost.s_addr != INADDR_NONE)
00383 {
00384 hostentp = gethostbyaddr((const char*)&iaHost,
00385 sizeof(struct in_addr), AF_INET);
00386 if(hostentp)
00387 {
00388 if(strchr(hostentp->h_name, '.'))
00389 {
00390
00391 rv = hostentp->h_name;
00392 }
00393 }
00394 }
00395 }
00396
00397 return rv;
00398 }
00399 #endif
00400
00401
00402 }
00403
00404 }
00405