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/ServerSocketImpl.hpp" 00041 #include "blocxx/Format.hpp" 00042 #include "blocxx/ByteSwap.hpp" 00043 #include "blocxx/FileSystem.hpp" 00044 #include "blocxx/File.hpp" 00045 #include "blocxx/Thread.hpp" 00046 #include "blocxx/SocketUtils.hpp" 00047 #include "blocxx/System.hpp" 00048 #include "blocxx/TimeoutTimer.hpp" 00049 00050 extern "C" 00051 { 00052 #if !defined(BLOCXX_WIN32) 00053 #include <sys/types.h> 00054 #include <sys/stat.h> 00055 #include <sys/socket.h> 00056 #include <sys/time.h> 00057 #include <netinet/in.h> 00058 #include <arpa/inet.h> 00059 #include <netdb.h> 00060 #include <unistd.h> 00061 #include <fcntl.h> 00062 00063 #define INVALID_SOCKET -1 00064 #endif 00065 } 00066 00067 #include <cerrno> 00068 00069 namespace BLOCXX_NAMESPACE 00070 { 00072 ServerSocketImpl::ServerSocketImpl(SSLServerCtxRef sslCtx) 00073 : m_sockfd(INVALID_SOCKET) 00074 , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET)) 00075 , m_isActive(false) 00076 , m_sslCtx(sslCtx) 00077 #if defined(BLOCXX_WIN32) 00078 , m_event(NULL) 00079 , m_shuttingDown(false) 00080 { 00081 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL); 00082 BLOCXX_ASSERT(m_event != NULL); 00083 } 00084 #else 00085 , m_udsFile() 00086 { 00087 } 00088 #endif 00089 00091 ServerSocketImpl::ServerSocketImpl(SocketFlags::ESSLFlag isSSL) 00092 : m_sockfd(INVALID_SOCKET) 00093 , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET)) 00094 , m_isActive(false) 00095 , m_isSSL(isSSL) 00096 #if defined(BLOCXX_WIN32) 00097 , m_event(NULL) 00098 , m_shuttingDown(false) 00099 { 00100 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL); 00101 BLOCXX_ASSERT(m_event != NULL); 00102 } 00103 #else 00104 , m_udsFile() 00105 { 00106 } 00107 #endif 00108 00110 ServerSocketImpl::~ServerSocketImpl() 00111 { 00112 try 00113 { 00114 close(); 00115 } 00116 catch (...) 00117 { 00118 // don't let exceptions escape 00119 } 00120 #if defined(BLOCXX_WIN32) 00121 ::CloseHandle(m_event); 00122 #endif 00123 } 00124 00126 Select_t 00127 ServerSocketImpl::getSelectObj() const 00128 { 00129 #if defined(BLOCXX_WIN32) 00130 Select_t st; 00131 st.event = m_event; 00132 st.sockfd = m_sockfd; 00133 st.isSocket = true; 00134 st.networkevents = FD_ACCEPT; 00135 return st; 00136 #else 00137 return m_sockfd; 00138 #endif 00139 } 00140 00142 void 00143 ServerSocketImpl::doListen(UInt16 port, SocketFlags::ESSLFlag isSSL, 00144 int queueSize, const String& listenAddr, 00145 SocketFlags::EReuseAddrFlag reuseAddr) 00146 { 00147 m_isSSL = isSSL; 00148 doListen(port, queueSize,listenAddr, reuseAddr); 00149 } 00150 00151 #if defined(BLOCXX_WIN32) 00152 00153 void 00154 ServerSocketImpl::doListen(UInt16 port, 00155 int queueSize, const String& listenAddr, 00156 SocketFlags::EReuseAddrFlag reuseAddr) 00157 { 00158 SocketHandle_t sock_ipv6 = INVALID_SOCKET; 00159 m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET); 00160 close(); 00161 00162 #ifdef BLOCXX_HAVE_IPV6 00163 // This will try to use IPv6 (AF_INET6). If it is not supported, it will 00164 // fall back to the normal IPv4 (AF_INET). 00165 sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0); 00166 if (sock_ipv6 == INVALID_SOCKET) 00167 { 00168 switch(errno) 00169 { 00170 case EPROTONOSUPPORT: 00171 case EAFNOSUPPORT: 00172 case EPFNOSUPPORT: 00173 case EINVAL: 00174 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0); 00175 break; 00176 default: 00177 break; 00178 } 00179 } 00180 else 00181 { 00182 m_sockfd = sock_ipv6; 00183 } 00184 #else 00185 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0); 00186 #endif 00187 if (m_sockfd == INVALID_SOCKET) 00188 { 00189 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00190 System::lastErrorMsg(true)).c_str()); 00191 } 00192 // Set listen socket to nonblocking 00193 unsigned long cmdArg = 1; 00194 if (::ioctlsocket(m_sockfd, FIONBIO, &cmdArg) == SOCKET_ERROR) 00195 { 00196 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00197 System::lastErrorMsg(true)).c_str()); 00198 } 00199 00200 if (reuseAddr) 00201 { 00202 DWORD reuse = 1; 00203 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, 00204 (const char*)&reuse, sizeof(reuse)); 00205 } 00206 00207 if ( sock_ipv6 == INVALID_SOCKET ) 00208 { 00209 // IPv4 00210 ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr); 00211 } 00212 #ifdef BLOCXX_HAVE_IPV6 00213 else 00214 { 00215 // IPv6 00216 ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr, reuseAddr); 00217 } 00218 #endif 00219 } 00221 void 00222 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr ) 00223 { 00224 // use IPv4 protocol 00225 InetSocketAddress_t inetAddr; 00226 memset(&inetAddr, 0, sizeof(inetAddr)); 00227 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family = AF_INET; 00228 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port = hton16(port); 00229 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES) 00230 { 00231 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY); 00232 } 00233 else 00234 { 00235 SocketAddress addr = SocketAddress::getByName(listenAddr); 00236 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = 00237 reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr; 00238 } 00239 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1) 00240 { 00241 close(); 00242 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00243 System::lastErrorMsg(true)).c_str()); 00244 } 00245 if (::listen(m_sockfd, queueSize) == -1) 00246 { 00247 close(); 00248 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00249 System::lastErrorMsg(true)).c_str()); 00250 } 00251 fillAddrParms(); 00252 m_isActive = true; 00253 } 00255 #ifdef BLOCXX_HAVE_IPV6 00256 void 00257 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr) 00258 { 00259 // use IPv6 protocol 00260 InetSocketAddress_t inetAddr; 00261 memset(&inetAddr, 0, sizeof(inetAddr)); 00262 reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family = AF_INET6; 00263 reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port = hton16(port); 00264 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES) 00265 { 00266 // copy IPv6 address any 00267 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr)); 00268 } 00269 else 00270 { 00271 // create network address structure for IPv6 protocol 00272 if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr)) 00273 { 00274 addrinfo *addrinfos; 00275 addrinfo hints; 00276 memset(&hints, 0, sizeof(hints)); 00277 hints.ai_socktype = SOCK_STREAM; 00278 hints.ai_family = AF_INET6; 00279 if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos)) 00280 { 00281 close(); 00282 BLOCXX_THROW(SocketException, Format("ServerSocketImpl:: doListen(): getaddrinfo() %1", 00283 System::lastErrorMsg(true)).c_str()); 00284 } 00285 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen); 00286 freeaddrinfo(addrinfos); 00287 } 00288 } 00289 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1) 00290 { 00291 close(); 00292 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00293 System::lastErrorMsg(true)).c_str()); 00294 } 00295 if (::listen(m_sockfd, queueSize) == -1) 00296 { 00297 close(); 00298 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00299 System::lastErrorMsg(true)).c_str()); 00300 } 00301 fillAddrParms(); 00302 m_isActive = true; 00303 } 00304 #endif // BLOCXX_HAVE_IPV6 00305 00306 namespace 00307 { 00308 00309 int 00310 waitForAcceptIO(SocketHandle_t fd, HANDLE eventArg, const Timeout& timeOutSecs, 00311 long networkEvents) 00312 { 00313 TimeoutTimer timer(timeOutSecs); 00314 00315 if (networkEvents != -1L) 00316 { 00317 if(::WSAEventSelect(fd, eventArg, networkEvents) != 0) 00318 { 00319 BLOCXX_THROW(SocketException, 00320 Format("WSAEventSelect failed in waitForAcceptIO: %1", 00321 System::lastErrorMsg(true)).c_str()); 00322 } 00323 } 00324 00325 int cc; 00326 switch(::WaitForSingleObject(eventArg, timer.asDWORDMs())) 00327 { 00328 case WAIT_OBJECT_0: 00329 ::ResetEvent(eventArg); 00330 cc = 0; 00331 break; 00332 case WAIT_TIMEOUT: 00333 cc = ETIMEDOUT; 00334 break; 00335 default: 00336 cc = -1; 00337 break; 00338 } 00339 00340 return cc; 00341 } 00342 00343 } 00344 00346 Socket 00347 ServerSocketImpl::accept(const Timeout& timeoutSecs) 00348 { 00349 BLOCXX_ASSERT(m_localAddress.getType() == SocketAddress::INET); 00350 00351 if (!m_isActive) 00352 { 00353 BLOCXX_THROW(SocketException, "ServerSocketImpl::accept: NONE"); 00354 } 00355 00356 // Register interest in FD_ACCEPT events 00357 if(::WSAEventSelect(m_sockfd, m_event, FD_ACCEPT) != 0) 00358 { 00359 BLOCXX_THROW(SocketException, 00360 Format("WSAEventSelect failed in accept: %1", 00361 System::lastErrorMsg(true)).c_str()); 00362 } 00363 00364 SOCKET clntfd; 00365 socklen_t clntlen; 00366 InetSocketAddress_t clntInetAddr; 00367 HANDLE events[2]; 00368 int cc; 00369 00370 while (true) 00371 { 00372 clntlen = sizeof(clntInetAddr); 00373 clntfd = ::accept(m_sockfd, 00374 reinterpret_cast<struct sockaddr*>(&clntInetAddr), &clntlen); 00375 if (clntfd != INVALID_SOCKET) 00376 { 00377 // Got immediate connection 00378 break; 00379 } 00380 00381 if (::WSAGetLastError() != WSAEWOULDBLOCK) 00382 { 00383 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00384 System::lastErrorMsg(true)).c_str()); 00385 } 00386 00387 //cc = SocketUtils::waitForIO(m_sockfd, m_event, INFINITE, FD_ACCEPT); 00388 cc = waitForAcceptIO(m_sockfd, m_event, timeoutSecs, FD_ACCEPT); 00389 if(m_shuttingDown) 00390 { 00391 cc = -2; 00392 } 00393 00394 switch (cc) 00395 { 00396 case -1: 00397 BLOCXX_THROW(SocketException, "Error while waiting for network events"); 00398 case -2: 00399 BLOCXX_THROW(SocketException, "Shutdown event was signaled"); 00400 case ETIMEDOUT: 00401 BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection"); 00402 } 00403 } 00404 00405 // Unregister for any events. necessary to put us back in blocking mode. 00406 if(::WSAEventSelect(clntfd, NULL, 0) != 0) 00407 { 00408 BLOCXX_THROW(SocketException, 00409 Format("WSAEventSelect failed in accept: %1", 00410 System::lastErrorMsg(true)).c_str()); 00411 } 00412 00413 // set socket back to blocking; otherwise it'll inherit non-blocking from the listening socket 00414 unsigned long cmdArg = 0; 00415 if (::ioctlsocket(clntfd, FIONBIO, &cmdArg) == SOCKET_ERROR) 00416 { 00417 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1", 00418 System::lastErrorMsg(true)).c_str()); 00419 } 00420 00421 if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL) 00422 { 00423 return Socket(clntfd, m_localAddress.getType(), m_isSSL); 00424 } 00425 00426 return Socket(clntfd, m_localAddress.getType(), m_sslCtx); 00427 } 00428 #else 00429 00430 void 00431 ServerSocketImpl::doListen(UInt16 port, 00432 int queueSize, const String& listenAddr, 00433 SocketFlags::EReuseAddrFlag reuseAddr) 00434 { 00435 SocketHandle_t sock_ipv6 = INVALID_SOCKET; 00436 m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET); 00437 close(); 00438 00439 #ifdef BLOCXX_HAVE_IPV6 00440 // This will try to use IPv6 (AF_INET6). If it is not supported, it will 00441 // fall back to the normal IPv4 (AF_INET). 00442 sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0); 00443 if (sock_ipv6 == INVALID_SOCKET) 00444 { 00445 switch(errno) 00446 { 00447 case EPROTONOSUPPORT: 00448 case EAFNOSUPPORT: 00449 case EPFNOSUPPORT: 00450 case EINVAL: 00451 // open socket for IPv4 protocol 00452 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0); 00453 break; 00454 default: 00455 break; 00456 } 00457 } 00458 else 00459 { 00460 m_sockfd = sock_ipv6; 00461 #ifdef IPV6_V6ONLY 00462 int ipv6_proto = IPPROTO_IPV6; 00463 #ifdef SOL_IP 00464 ipv6_proto = SOL_IP; 00465 #endif 00466 int ipv6_only=0; 00467 ::setsockopt(m_sockfd, ipv6_proto, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)); 00468 #endif 00469 } 00470 #else 00471 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0); 00472 #endif 00473 if (m_sockfd == INVALID_SOCKET) 00474 { 00475 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()"); 00476 } 00477 // set the close on exec flag so child process can't keep the socket. 00478 if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1) 00479 { 00480 close(); 00481 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set " 00482 "close-on-exec flag on listen socket"); 00483 } 00484 // set listen socket to nonblocking; see Unix Network Programming, 00485 // pages 422-424. 00486 int fdflags = ::fcntl(m_sockfd, F_GETFL, 0); 00487 ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK); 00488 // is this safe? Should be, but some OS kernels have problems with it. 00489 // It's OK on current linux versions. Definitely not on 00490 // OLD (kernel < 1.3.60) ones. Who knows about on other OS's like UnixWare or 00491 // OpenServer? 00492 // See http://monkey.org/openbsd/archive/misc/9601/msg00031.html 00493 // or just google for "bind() Security Problems" 00494 // Let the kernel reuse the port without waiting for it to time out. 00495 // Without this line, you can't stop and immediately re-start the daemon. 00496 if (reuseAddr) 00497 { 00498 int reuse = 1; 00499 #if defined(BLOCXX_NCR) 00500 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)); 00501 #else 00502 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 00503 #endif 00504 } 00505 if ( sock_ipv6 == INVALID_SOCKET) 00506 { 00507 // IPv4 00508 ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr ); 00509 } 00510 #ifdef BLOCXX_HAVE_IPV6 00511 else 00512 { // IPv6 00513 ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr ); 00514 } 00515 #endif 00516 } 00517 00519 void 00520 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr ) 00521 { 00522 // use IPv4 protocol 00523 InetSocketAddress_t inetAddr; 00524 memset(&inetAddr, 0, sizeof(inetAddr)); 00525 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family = AF_INET; 00526 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port = hton16(port); 00527 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES) 00528 { 00529 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY); 00530 } 00531 else 00532 { 00533 SocketAddress addr = SocketAddress::getByName(listenAddr); 00534 reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = 00535 reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr; 00536 } 00537 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1) 00538 { 00539 close(); 00540 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind"); 00541 } 00542 if (::listen(m_sockfd, queueSize) == -1) 00543 { 00544 close(); 00545 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen"); 00546 } 00547 fillAddrParms(); 00548 m_isActive = true; 00549 } 00550 00551 #ifdef BLOCXX_HAVE_IPV6 00552 00553 void 00554 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr) 00555 { 00556 // use IPv6 protocol 00557 InetSocketAddress_t inetAddr; 00558 memset(&inetAddr, 0, sizeof(inetAddr)); 00559 reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family = AF_INET6; 00560 reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port = hton16(port); 00561 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES) 00562 { 00563 // copy IPv6 address any 00564 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr)); 00565 } 00566 else 00567 { 00568 // create network address structure for IPv6 protocol 00569 if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr)) 00570 { 00571 addrinfo *addrinfos; 00572 addrinfo hints; 00573 memset(&hints, 0, sizeof(hints)); 00574 hints.ai_socktype = SOCK_STREAM; 00575 hints.ai_family = AF_INET6; 00576 if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos)) 00577 { 00578 close(); 00579 BLOCXX_THROW_ERRNO_MSG(SocketException,"ServerSocketImpl::doListen(): getaddrinfo()"); 00580 } 00581 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen); 00582 freeaddrinfo(addrinfos); 00583 } 00584 } 00585 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1) 00586 { 00587 close(); 00588 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind"); 00589 } 00590 if (::listen(m_sockfd, queueSize) == -1) 00591 { 00592 close(); 00593 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen"); 00594 } 00595 fillAddrParms(); 00596 m_isActive = true; 00597 } 00598 #endif 00599 00600 void 00601 ServerSocketImpl::doListenUDS(const String& filename, int queueSize, bool reuseAddr) 00602 { 00603 m_localAddress = SocketAddress::getUDS(filename); 00604 close(); 00605 m_sockfd = ::socket(PF_UNIX,SOCK_STREAM, 0); 00606 if (m_sockfd == INVALID_SOCKET) 00607 { 00608 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()"); 00609 } 00610 // set the close on exec flag so child process can't keep the socket. 00611 if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1) 00612 { 00613 close(); 00614 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set " 00615 "close-on-exec flag on listen socket"); 00616 } 00617 00618 // set listen socket to nonblocking; see Unix Network Programming, 00619 // pages 422-424. 00620 int fdflags = ::fcntl(m_sockfd, F_GETFL, 0); 00621 ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK); 00622 00623 if (reuseAddr) 00624 { 00625 // Let the kernel reuse the port without waiting for it to time out. 00626 // Without this line, you can't stop and immediately re-start the daemon. 00627 int reuse = 1; 00628 #if defined(BLOCXX_NCR) 00629 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 00630 #else 00631 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 00632 #endif 00633 } 00634 String lockfilename = filename + ".lock"; 00635 m_udsFile = FileSystem::openOrCreateFile(lockfilename); 00636 if (!m_udsFile) 00637 { 00638 BLOCXX_THROW_ERRNO_MSG(SocketException, 00639 Format("ServerSocketImpl::doListen(): Unable to open or create Unix Domain Socket lock: %1", 00640 lockfilename).c_str()); 00641 } 00642 // if we can't get a lock, someone else has got it open. 00643 if (m_udsFile.tryLock() == -1) 00644 { 00645 BLOCXX_THROW_ERRNO_MSG(SocketException, 00646 Format("ServerSocketImpl::doListen(): Unable to lock Unix Domain Socket: %1", 00647 filename).c_str()); 00648 } 00649 // We got the lock, so clobber the UDS if it's there so bind will succeed. 00650 // If it's not gone, bind will fail. 00651 if (FileSystem::exists(filename)) 00652 { 00653 if (!FileSystem::removeFile(filename.c_str())) 00654 { 00655 BLOCXX_THROW_ERRNO_MSG(SocketException, 00656 Format("ServerSocketImpl::doListen(): Unable to unlink Unix Domain Socket: %1", 00657 filename).c_str()); 00658 } 00659 } 00660 00661 #if defined(BLOCXX_NCR) 00662 if (::bind(m_sockfd, const_cast<SocketAddress_t *>(m_localAddress.getNativeForm()), m_localAddress.getNativeFormSize()) == -1) 00663 #else 00664 if (::bind(m_sockfd, m_localAddress.getNativeForm(), m_localAddress.getNativeFormSize()) == -1) 00665 #endif 00666 { 00667 close(); 00668 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind()"); 00669 } 00670 // give anybody access to the socket 00671 // unfortunately, fchmod() doesn't work on a UDS 00672 if (::chmod(filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1) 00673 { 00674 close(); 00675 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): chmod()"); 00676 } 00677 if (::listen(m_sockfd, queueSize) == -1) 00678 { 00679 close(); 00680 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen()"); 00681 } 00682 fillAddrParms(); 00683 m_isActive = true; 00684 } 00686 /* 00687 String 00688 ServerSocketImpl::addrString() 00689 { 00690 return inetAddrToString(m_localAddress, m_localPort); 00691 } 00692 */ 00694 Socket 00695 ServerSocketImpl::accept(const Timeout& timeout) 00696 { 00697 if (!m_isActive) 00698 { 00699 BLOCXX_THROW(SocketException, "ServerSocketImpl::accept(): m_isActive == false"); 00700 } 00701 int rc = 0; 00702 if ((rc = SocketUtils::waitForIO(m_sockfd, timeout, SocketFlags::E_WAIT_FOR_INPUT)) == 0) 00703 { 00704 int clntfd; 00705 socklen_t clntlen; 00706 InetSocketAddress_t clntInetAddr; 00707 struct sockaddr_un clntUnixAddr; 00708 struct sockaddr* pSA(0); 00709 if (m_localAddress.getType() == SocketAddress::INET) 00710 { 00711 pSA = reinterpret_cast<struct sockaddr*>(&clntInetAddr); 00712 clntlen = sizeof(clntInetAddr); 00713 } 00714 else if (m_localAddress.getType() == SocketAddress::UDS) 00715 { 00716 pSA = reinterpret_cast<struct sockaddr*>(&clntUnixAddr); 00717 clntlen = sizeof(clntUnixAddr); 00718 } 00719 else 00720 { 00721 BLOCXX_ASSERT(0); 00722 } 00723 00724 clntfd = ::accept(m_sockfd, pSA, &clntlen); 00725 if (clntfd < 0) 00726 { 00727 // check to see if client aborts connection between select and accept. 00728 // see Unix Network Programming pages 422-424. 00729 if (errno == EWOULDBLOCK 00730 || errno == ECONNABORTED 00731 #ifdef EPROTO 00732 || errno == EPROTO 00733 #endif 00734 ) 00735 { 00736 BLOCXX_THROW(SocketException, "Client aborted TCP connection " 00737 "between select() and accept()"); 00738 } 00739 00740 if (errno == EINTR) 00741 { 00742 Thread::testCancel(); 00743 } 00744 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::accept(): accept()"); 00745 } 00746 // set socket back to blocking; see Unix Network Programming, 00747 // pages 422-424. 00748 int fdflags = ::fcntl(clntfd, F_GETFL, 0); 00749 // On most OSs non-blocking is inherited from the listen socket, 00750 // but it's not on Openserver. 00751 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) 00752 { 00753 ::fcntl(clntfd, F_SETFL, fdflags ^ O_NONBLOCK); 00754 } 00755 // TODO, how to make this bw compatible? 00756 //return Socket(clntfd, m_localAddress.getType(), m_isSSL); 00757 if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL) 00758 { 00759 return Socket(clntfd, m_localAddress.getType(), m_isSSL); // for bw compat. 00760 } 00761 return Socket(clntfd, m_localAddress.getType(), m_sslCtx); 00762 } 00763 else if (rc == ETIMEDOUT) 00764 { 00765 // The timeout expired. 00766 BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection"); 00767 } 00768 else 00769 { 00770 BLOCXX_THROW_ERRNO_MSG(SocketException,"Timed out waiting for a connection"); 00771 } 00772 } 00773 #endif 00774 00776 void 00777 ServerSocketImpl::close() 00778 { 00779 if (m_isActive) 00780 { 00781 #if defined(BLOCXX_WIN32) 00782 ::closesocket(m_sockfd); 00783 m_sockfd = INVALID_SOCKET; 00784 #else 00785 ::close(m_sockfd); 00786 if (m_localAddress.getType() == SocketAddress::UDS) 00787 { 00788 String filename = m_localAddress.toString(); 00789 if (!FileSystem::removeFile(filename.c_str())) 00790 { 00791 BLOCXX_THROW_ERRNO_MSG(SocketException, 00792 Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket: %1", 00793 filename).c_str()); 00794 } 00795 if (m_udsFile) 00796 { 00797 String lockfilename = filename + ".lock"; 00798 if (m_udsFile.unlock() == -1) 00799 { 00800 BLOCXX_THROW_ERRNO_MSG(SocketException, 00801 Format("ServerSocketImpl::close(): Failed to unlock Unix Domain Socket: %1", 00802 lockfilename).c_str()); 00803 } 00804 m_udsFile.close(); 00805 if (!FileSystem::removeFile(lockfilename.c_str())) 00806 { 00807 BLOCXX_THROW_ERRNO_MSG(SocketException, 00808 Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket lock: %1", 00809 lockfilename).c_str()); 00810 } 00811 } 00812 } 00813 #endif 00814 m_isActive = false; 00815 } 00816 } 00818 void 00819 ServerSocketImpl::fillAddrParms() 00820 { 00821 socklen_t len; 00822 if (m_localAddress.getType() == SocketAddress::INET) 00823 { 00824 // get information of local address for IPv6 protocol 00825 struct sockaddr *p_addr; 00826 InetSocketAddress_t ss; 00827 memset(&ss, 0, sizeof(ss)); 00828 len = sizeof(ss); 00829 p_addr = reinterpret_cast<struct sockaddr*>(&ss); 00830 if (getsockname(m_sockfd, p_addr, &len) == -1) 00831 { 00832 BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname"); 00833 } 00834 m_localAddress.assignFromNativeForm(&ss, len); 00835 } 00836 #if !defined(BLOCXX_WIN32) 00837 else if (m_localAddress.getType() == SocketAddress::UDS) 00838 { 00839 struct sockaddr_un addr; 00840 memset(&addr, 0, sizeof(addr)); 00841 len = sizeof(addr); 00842 if (getsockname(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1) 00843 { 00844 BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname"); 00845 } 00846 m_localAddress.assignFromNativeForm(&addr, len); 00847 } 00848 #endif 00849 else 00850 { 00851 BLOCXX_ASSERT(0); 00852 } 00853 } 00854 00855 } // end namespace BLOCXX_NAMESPACE 00856