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/ServerSocketImpl.hpp"
00040 #include "blocxx/Format.hpp"
00041 #include "blocxx/ByteSwap.hpp"
00042 #include "blocxx/FileSystem.hpp"
00043 #include "blocxx/File.hpp"
00044 #include "blocxx/Thread.hpp"
00045 #include "blocxx/SocketUtils.hpp"
00046 #include "blocxx/System.hpp"
00047
00048 extern "C"
00049 {
00050 #if !defined(BLOCXX_WIN32)
00051 #include <sys/types.h>
00052 #include <sys/stat.h>
00053 #include <sys/socket.h>
00054 #include <sys/time.h>
00055 #include <netinet/in.h>
00056 #include <arpa/inet.h>
00057 #include <netdb.h>
00058 #include <unistd.h>
00059 #include <fcntl.h>
00060 #endif
00061 }
00062
00063 #include <cerrno>
00064
00065 namespace BLOCXX_NAMESPACE
00066 {
00068 ServerSocketImpl::ServerSocketImpl(SSLServerCtxRef sslCtx)
00069 : m_sockfd(-1)
00070 , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
00071 , m_isActive(false)
00072 , m_sslCtx(sslCtx)
00073 #if defined(BLOCXX_WIN32)
00074 , m_event(NULL)
00075 , m_shuttingDown(false)
00076 {
00077 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00078 BLOCXX_ASSERT(m_event != NULL);
00079 }
00080 #else
00081 , m_udsFile()
00082 {
00083 }
00084 #endif
00085
00087 ServerSocketImpl::ServerSocketImpl(SocketFlags::ESSLFlag isSSL)
00088 : m_sockfd(-1)
00089 , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
00090 , m_isActive(false)
00091 , m_isSSL(isSSL)
00092 #if defined(BLOCXX_WIN32)
00093 , m_event(NULL)
00094 , m_shuttingDown(false)
00095 {
00096 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00097 BLOCXX_ASSERT(m_event != NULL);
00098 }
00099 #else
00100 , m_udsFile()
00101 {
00102 }
00103 #endif
00104
00106 ServerSocketImpl::~ServerSocketImpl()
00107 {
00108 try
00109 {
00110 close();
00111 }
00112 catch (...)
00113 {
00114
00115 }
00116 #if defined(BLOCXX_WIN32)
00117 ::CloseHandle(m_event);
00118 #endif
00119 }
00120
00122 Select_t
00123 ServerSocketImpl::getSelectObj() const
00124 {
00125 #if defined(BLOCXX_WIN32)
00126 Select_t st;
00127 st.event = m_event;
00128 st.sockfd = m_sockfd;
00129 st.networkevents = FD_ACCEPT;
00130 return st;
00131 #else
00132 return m_sockfd;
00133 #endif
00134 }
00135
00137 void
00138 ServerSocketImpl::doListen(UInt16 port, SocketFlags::ESSLFlag isSSL,
00139 int queueSize, const String& listenAddr,
00140 SocketFlags::EReuseAddrFlag reuseAddr)
00141 {
00142 m_isSSL = isSSL;
00143 doListen(port, queueSize,listenAddr, reuseAddr);
00144 }
00145
00146 #if defined(BLOCXX_WIN32)
00147
00148 void
00149 ServerSocketImpl::doListen(UInt16 port,
00150 int queueSize, const String& listenAddr,
00151 SocketFlags::EReuseAddrFlag reuseAddr)
00152 {
00153 m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET);
00154 close();
00155 if ((m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
00156 {
00157 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00158 System::lastErrorMsg(true)).c_str());
00159 }
00160
00161
00162 unsigned long cmdArg = 1;
00163 if (::ioctlsocket(m_sockfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
00164 {
00165 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00166 System::lastErrorMsg(true)).c_str());
00167 }
00168
00169 if (reuseAddr)
00170 {
00171 DWORD reuse = 1;
00172 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR,
00173 (const char*)&reuse, sizeof(reuse));
00174 }
00175
00176 InetSocketAddress_t inetAddr;
00177 inetAddr.sin_family = AF_INET;
00178 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00179 {
00180 inetAddr.sin_addr.s_addr = hton32(INADDR_ANY);
00181 }
00182 else
00183 {
00184 SocketAddress addr = SocketAddress::getByName(listenAddr);
00185 inetAddr.sin_addr.s_addr = addr.getInetAddress()->sin_addr.s_addr;
00186 }
00187 inetAddr.sin_port = hton16(port);
00188 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00189 {
00190 close();
00191 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00192 System::lastErrorMsg(true)).c_str());
00193 }
00194 if (::listen(m_sockfd, queueSize) == -1)
00195 {
00196 close();
00197 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00198 System::lastErrorMsg(true)).c_str());
00199 }
00200 fillAddrParms();
00201 m_isActive = true;
00202 }
00203
00204 namespace
00205 {
00206
00207 int
00208 waitForAcceptIO(SocketHandle_t fd, HANDLE eventArg, int timeOutSecs,
00209 long networkEvents)
00210 {
00211 DWORD timeout = (timeOutSecs != -1)
00212 ? static_cast<DWORD>(timeOutSecs * 1000)
00213 : INFINITE;
00214
00215 if (networkEvents != -1L)
00216 {
00217 if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
00218 {
00219 BLOCXX_THROW(SocketException,
00220 Format("WSAEventSelect failed in waitForAcceptIO: %1",
00221 System::lastErrorMsg(true)).c_str());
00222 }
00223 }
00224
00225 int cc;
00226 switch(::WaitForSingleObject(eventArg, timeout))
00227 {
00228 case WAIT_OBJECT_0:
00229 ::ResetEvent(eventArg);
00230 cc = 0;
00231 break;
00232 case WAIT_TIMEOUT:
00233 cc = ETIMEDOUT;
00234 break;
00235 default:
00236 cc = -1;
00237 break;
00238 }
00239
00240 return cc;
00241 }
00242
00243 }
00244
00246 Socket
00247 ServerSocketImpl::accept(int timeoutSecs)
00248 {
00249 BLOCXX_ASSERT(m_localAddress.getType() == SocketAddress::INET);
00250
00251 if (!m_isActive)
00252 {
00253 BLOCXX_THROW(SocketException, "ServerSocketImpl::accept: NONE");
00254 }
00255
00256
00257 if(::WSAEventSelect(m_sockfd, m_event, FD_ACCEPT) != 0)
00258 {
00259 BLOCXX_THROW(SocketException,
00260 Format("WSAEventSelect failed in accept: %1",
00261 System::lastErrorMsg(true)).c_str());
00262 }
00263
00264 SOCKET clntfd;
00265 socklen_t clntlen;
00266 struct sockaddr_in clntInetAddr;
00267 HANDLE events[2];
00268 int cc;
00269
00270 while (true)
00271 {
00272 clntlen = sizeof(clntInetAddr);
00273 clntfd = ::accept(m_sockfd,
00274 reinterpret_cast<struct sockaddr*>(&clntInetAddr), &clntlen);
00275 if (clntfd != INVALID_SOCKET)
00276 {
00277
00278 break;
00279 }
00280
00281 if (::WSAGetLastError() != WSAEWOULDBLOCK)
00282 {
00283 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00284 System::lastErrorMsg(true)).c_str());
00285 }
00286
00287
00288 cc = waitForAcceptIO(m_sockfd, m_event, timeoutSecs, FD_ACCEPT);
00289 if(m_shuttingDown)
00290 {
00291 cc = -2;
00292 }
00293
00294 switch (cc)
00295 {
00296 case -1:
00297 BLOCXX_THROW(SocketException, "Error while waiting for network events");
00298 case -2:
00299 BLOCXX_THROW(SocketException, "Shutdown event was signaled");
00300 case ETIMEDOUT:
00301 BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
00302 }
00303 }
00304
00305
00306 if(::WSAEventSelect(clntfd, NULL, 0) != 0)
00307 {
00308 BLOCXX_THROW(SocketException,
00309 Format("WSAEventSelect failed in accept: %1",
00310 System::lastErrorMsg(true)).c_str());
00311 }
00312
00313
00314 unsigned long cmdArg = 0;
00315 if (::ioctlsocket(clntfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
00316 {
00317 BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00318 System::lastErrorMsg(true)).c_str());
00319 }
00320
00321 if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL)
00322 {
00323 return Socket(clntfd, m_localAddress.getType(), m_isSSL);
00324 }
00325
00326 return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
00327 }
00328 #else
00329
00330 void
00331 ServerSocketImpl::doListen(UInt16 port,
00332 int queueSize, const String& listenAddr,
00333 SocketFlags::EReuseAddrFlag reuseAddr)
00334 {
00335 m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET);
00336 close();
00337 if ((m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0)) == -1)
00338 {
00339 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
00340 }
00341
00342 if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
00343 {
00344 close();
00345 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
00346 "close-on-exec flag on listen socket");
00347 }
00348
00349
00350 int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
00351 ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
00352
00353
00354
00355
00356
00357
00358
00359
00360 if (reuseAddr)
00361 {
00362 int reuse = 1;
00363 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
00364 }
00365
00366 InetSocketAddress_t inetAddr;
00367 inetAddr.sin_family = AF_INET;
00368 if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00369 {
00370 inetAddr.sin_addr.s_addr = hton32(INADDR_ANY);
00371 }
00372 else
00373 {
00374 SocketAddress addr = SocketAddress::getByName(listenAddr);
00375 inetAddr.sin_addr.s_addr = addr.getInetAddress()->sin_addr.s_addr;
00376 }
00377 inetAddr.sin_port = hton16(port);
00378 if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00379 {
00380 close();
00381 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind");
00382 }
00383 if (::listen(m_sockfd, queueSize) == -1)
00384 {
00385 close();
00386 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen");
00387 }
00388 fillAddrParms();
00389 m_isActive = true;
00390 }
00391
00393 void
00394 ServerSocketImpl::doListen(const String& filename, int queueSize, bool reuseAddr)
00395 {
00396 m_localAddress = SocketAddress::getUDS(filename);
00397 close();
00398 if ((m_sockfd = ::socket(PF_UNIX,SOCK_STREAM, 0)) == -1)
00399 {
00400 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
00401 }
00402
00403 if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
00404 {
00405 close();
00406 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
00407 "close-on-exec flag on listen socket");
00408 }
00409
00410
00411
00412 int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
00413 ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
00414
00415 if (reuseAddr)
00416 {
00417
00418
00419 int reuse = 1;
00420 ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
00421 }
00422 String lockfilename = filename + ".lock";
00423 m_udsFile = FileSystem::openOrCreateFile(lockfilename);
00424 if (!m_udsFile)
00425 {
00426 BLOCXX_THROW_ERRNO_MSG(SocketException,
00427 Format("ServerSocketImpl::doListen(): Unable to open or create Unix Domain Socket lock: %1",
00428 lockfilename).c_str());
00429 }
00430
00431 if (m_udsFile.tryLock() == -1)
00432 {
00433 BLOCXX_THROW_ERRNO_MSG(SocketException,
00434 Format("ServerSocketImpl::doListen(): Unable to lock Unix Domain Socket: %1",
00435 filename).c_str());
00436 }
00437
00438
00439 if (FileSystem::exists(filename))
00440 {
00441 if (!FileSystem::removeFile(filename.c_str()))
00442 {
00443 BLOCXX_THROW_ERRNO_MSG(SocketException,
00444 Format("ServerSocketImpl::doListen(): Unable to unlink Unix Domain Socket: %1",
00445 filename).c_str());
00446 }
00447 }
00448
00449 if (::bind(m_sockfd, m_localAddress.getNativeForm(),
00450 m_localAddress.getNativeFormSize()) == -1)
00451 {
00452 close();
00453 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind()");
00454 }
00455
00456
00457 if (::chmod(filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1)
00458 {
00459 close();
00460 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): chmod()");
00461 }
00462 if (::listen(m_sockfd, queueSize) == -1)
00463 {
00464 close();
00465 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen()");
00466 }
00467 fillAddrParms();
00468 m_isActive = true;
00469 }
00471 Socket
00472 ServerSocketImpl::accept(int timeoutSecs)
00473 {
00474 if (!m_isActive)
00475 {
00476 BLOCXX_THROW(SocketException, "ServerSocketImpl::accept(): m_isActive == false");
00477 }
00478 if (SocketUtils::waitForIO(m_sockfd, timeoutSecs, SocketFlags::E_WAIT_FOR_INPUT) == 0)
00479 {
00480 int clntfd;
00481 socklen_t clntlen;
00482 struct sockaddr_in clntInetAddr;
00483 struct sockaddr_un clntUnixAddr;
00484 struct sockaddr* pSA(0);
00485 if (m_localAddress.getType() == SocketAddress::INET)
00486 {
00487 pSA = reinterpret_cast<struct sockaddr*>(&clntInetAddr);
00488 clntlen = sizeof(clntInetAddr);
00489 }
00490 else if (m_localAddress.getType() == SocketAddress::UDS)
00491 {
00492 pSA = reinterpret_cast<struct sockaddr*>(&clntUnixAddr);
00493 clntlen = sizeof(clntUnixAddr);
00494 }
00495 else
00496 {
00497 BLOCXX_ASSERT(0);
00498 }
00499
00500 clntfd = ::accept(m_sockfd, pSA, &clntlen);
00501 if (clntfd < 0)
00502 {
00503
00504
00505 if (errno == EWOULDBLOCK
00506 || errno == ECONNABORTED
00507 #ifdef EPROTO
00508 || errno == EPROTO
00509 #endif
00510 )
00511 {
00512 BLOCXX_THROW(SocketException, "Client aborted TCP connection "
00513 "between select() and accept()");
00514 }
00515
00516 if (errno == EINTR)
00517 {
00518 Thread::testCancel();
00519 }
00520 BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::accept(): accept()");
00521 }
00522
00523
00524 int fdflags = ::fcntl(clntfd, F_GETFL, 0);
00525
00526
00527 if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
00528 {
00529 ::fcntl(clntfd, F_SETFL, fdflags ^ O_NONBLOCK);
00530 }
00531
00532
00533 if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL)
00534 {
00535 return Socket(clntfd, m_localAddress.getType(), m_isSSL);
00536 }
00537 return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
00538 }
00539 else
00540 {
00541
00542 BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
00543 }
00544 }
00545 #endif
00546
00548 void
00549 ServerSocketImpl::close()
00550 {
00551 if (m_isActive)
00552 {
00553 #if defined(BLOCXX_WIN32)
00554 ::closesocket(m_sockfd);
00555 m_sockfd = INVALID_SOCKET;
00556 #else
00557 ::close(m_sockfd);
00558 if (m_localAddress.getType() == SocketAddress::UDS)
00559 {
00560 String filename = m_localAddress.toString();
00561 if (!FileSystem::removeFile(filename.c_str()))
00562 {
00563 BLOCXX_THROW_ERRNO_MSG(SocketException,
00564 Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket: %1",
00565 filename).c_str());
00566 }
00567 if (m_udsFile)
00568 {
00569 String lockfilename = filename + ".lock";
00570 if (m_udsFile.unlock() == -1)
00571 {
00572 BLOCXX_THROW_ERRNO_MSG(SocketException,
00573 Format("ServerSocketImpl::close(): Failed to unlock Unix Domain Socket: %1",
00574 lockfilename).c_str());
00575 }
00576 m_udsFile.close();
00577 if (!FileSystem::removeFile(lockfilename.c_str()))
00578 {
00579 BLOCXX_THROW_ERRNO_MSG(SocketException,
00580 Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket lock: %1",
00581 lockfilename).c_str());
00582 }
00583 }
00584 }
00585 #endif
00586 m_isActive = false;
00587 }
00588 }
00590 void
00591 ServerSocketImpl::fillAddrParms()
00592 {
00593 socklen_t len;
00594 if (m_localAddress.getType() == SocketAddress::INET)
00595 {
00596 struct sockaddr_in addr;
00597 memset(&addr, 0, sizeof(addr));
00598 len = sizeof(addr);
00599 if (getsockname(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1)
00600 {
00601 BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
00602 }
00603 m_localAddress.assignFromNativeForm(&addr, len);
00604 }
00605 #if !defined(BLOCXX_WIN32)
00606 else if (m_localAddress.getType() == SocketAddress::UDS)
00607 {
00608 struct sockaddr_un addr;
00609 memset(&addr, 0, sizeof(addr));
00610 len = sizeof(addr);
00611 if (getsockname(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1)
00612 {
00613 BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
00614 }
00615 m_localAddress.assignFromNativeForm(&addr, len);
00616 }
00617 #endif
00618 else
00619 {
00620 BLOCXX_ASSERT(0);
00621 }
00622 }
00623
00624 }
00625