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
00040 #include "blocxx/BLOCXX_config.h"
00041
00042 #if defined(BLOCXX_WIN32)
00043
00044 #include "blocxx/SocketBaseImpl.hpp"
00045 #include "blocxx/SocketUtils.hpp"
00046 #include "blocxx/Format.hpp"
00047 #include "blocxx/Assertion.hpp"
00048 #include "blocxx/IOException.hpp"
00049 #include "blocxx/Mutex.hpp"
00050 #include "blocxx/MutexLock.hpp"
00051 #include "blocxx/Socket.hpp"
00052 #include "blocxx/Thread.hpp"
00053 #include "blocxx/System.hpp"
00054 #include "blocxx/TimeoutTimer.hpp"
00055
00056 #include <cstdio>
00057 #include <cerrno>
00058 #include <fstream>
00059 #include <ws2tcpip.h>
00060
00061 namespace
00062 {
00063
00064 class SockInitializer
00065 {
00066 public:
00067 SockInitializer()
00068 {
00069 WSADATA wsaData;
00070 ::WSAStartup(MAKEWORD(2,2), &wsaData);
00071 }
00072
00073 ~SockInitializer()
00074 {
00075 ::WSACleanup();
00076 }
00077 };
00078
00079
00080 SockInitializer _sockInitializer;
00081
00083 void
00084 _closeSocket(SOCKET& sockfd)
00085 {
00086 if (sockfd != INVALID_SOCKET)
00087 {
00088 ::closesocket(sockfd);
00089 sockfd = INVALID_SOCKET;
00090 }
00091 }
00092
00094 int
00095 getAddrFromIface(BLOCXX_NAMESPACE::InetSocketAddress_t& addr)
00096 {
00097 SOCKET sd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00098 if (sd == SOCKET_ERROR)
00099 {
00100 return -1;
00101 }
00102
00103 int cc = -1;
00104 INTERFACE_INFO interfaceList[20];
00105 unsigned long nBytesReturned;
00106 if (::WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &interfaceList,
00107 sizeof(interfaceList), &nBytesReturned, 0, 0) != SOCKET_ERROR)
00108 {
00109 int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
00110 for (int i = 0; i < nNumInterfaces; ++i)
00111 {
00112 u_long nFlags = interfaceList[i].iiFlags;
00113 if (nFlags & IFF_UP)
00114 {
00115 cc = 0;
00116 ::memcpy(&addr, &(interfaceList[i].iiAddress), sizeof(addr));
00117 if (!(nFlags & IFF_LOOPBACK))
00118 {
00119 break;
00120 }
00121 }
00122 }
00123 }
00124
00125 ::closesocket(sd);
00126 return 0;
00127 }
00128
00129 }
00130
00131 namespace BLOCXX_NAMESPACE
00132 {
00133
00134 using std::istream;
00135 using std::ostream;
00136 using std::iostream;
00137 using std::ifstream;
00138 using std::ofstream;
00139 using std::fstream;
00140 using std::ios;
00141 String SocketBaseImpl::m_traceFileOut;
00142 String SocketBaseImpl::m_traceFileIn;
00143
00145
00146 int
00147 SocketBaseImpl::waitForEvent(HANDLE eventArg, int secsToTimeout)
00148 {
00149 DWORD timeout = (secsToTimeout != -1)
00150 ? static_cast<DWORD>(secsToTimeout * 1000)
00151 : INFINITE;
00152
00153 int cc;
00154 if(Socket::getShutDownMechanism() != NULL)
00155 {
00156 HANDLE events[2];
00157 events[0] = Socket::getShutDownMechanism();
00158 events[1] = eventArg;
00159
00160 DWORD index = ::WaitForMultipleObjects(
00161 2,
00162 events,
00163 FALSE,
00164 timeout);
00165
00166 switch (index)
00167 {
00168 case WAIT_FAILED:
00169 cc = -2;
00170 break;
00171 case WAIT_TIMEOUT:
00172 cc = -1;
00173 break;
00174 default:
00175 index -= WAIT_OBJECT_0;
00176
00177 if (index != 0)
00178 {
00179 ::ResetEvent(eventArg);
00180 }
00181 cc = static_cast<int>(index);
00182 break;
00183 }
00184 }
00185 else
00186 {
00187 switch(::WaitForSingleObject(eventArg, timeout))
00188 {
00189 case WAIT_OBJECT_0:
00190 ::ResetEvent(eventArg);
00191 cc = 1;
00192 break;
00193 case WAIT_TIMEOUT:
00194 cc = -1;
00195 break;
00196 default:
00197 cc = -2;
00198 break;
00199 }
00200 }
00201
00202 return cc;
00203 }
00204
00205 #pragma warning (push)
00206 #pragma warning (disable: 4355)
00207
00209 SocketBaseImpl::SocketBaseImpl()
00210 : SelectableIFC()
00211 , IOIFC()
00212 , m_isConnected(false)
00213 , m_sockfd(INVALID_SOCKET)
00214 , m_localAddress()
00215 , m_peerAddress()
00216 , m_event(NULL)
00217 , m_recvTimeoutExprd(false)
00218 , m_streamBuf(this)
00219 , m_in(&m_streamBuf)
00220 , m_out(&m_streamBuf)
00221 , m_inout(&m_streamBuf)
00222 , m_recvTimeout(Timeout::infinite)
00223 , m_sendTimeout(Timeout::infinite)
00224 , m_connectTimeout(Timeout::relative(0))
00225 {
00226 m_out.exceptions(std::ios::badbit);
00227 m_inout.exceptions(std::ios::badbit);
00228 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00229 BLOCXX_ASSERT(m_event != NULL);
00230 }
00232 SocketBaseImpl::SocketBaseImpl(SocketHandle_t fd,
00233 SocketAddress::AddressType addrType)
00234 : SelectableIFC()
00235 , IOIFC()
00236 , m_isConnected(true)
00237 , m_sockfd(fd)
00238 , m_localAddress(SocketAddress::getAnyLocalHost())
00239 , m_peerAddress(SocketAddress::allocEmptyAddress(addrType))
00240 , m_event(NULL)
00241 , m_recvTimeoutExprd(false)
00242 , m_streamBuf(this)
00243 , m_in(&m_streamBuf)
00244 , m_out(&m_streamBuf)
00245 , m_inout(&m_streamBuf)
00246 , m_recvTimeout(Timeout::infinite)
00247 , m_sendTimeout(Timeout::infinite)
00248 , m_connectTimeout(Timeout::relative(0))
00249 {
00250 BLOCXX_ASSERT(addrType == SocketAddress::INET);
00251
00252 m_out.exceptions(std::ios::badbit);
00253 m_inout.exceptions(std::ios::badbit);
00254 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00255 BLOCXX_ASSERT(m_event != NULL);
00256 fillInetAddrParms();
00257 }
00259 SocketBaseImpl::SocketBaseImpl(const SocketAddress& addr)
00260 : SelectableIFC()
00261 , IOIFC()
00262 , m_isConnected(false)
00263 , m_sockfd(INVALID_SOCKET)
00264 , m_localAddress(SocketAddress::getAnyLocalHost())
00265 , m_peerAddress(addr)
00266 , m_event(NULL)
00267 , m_recvTimeoutExprd(false)
00268 , m_streamBuf(this)
00269 , m_in(&m_streamBuf)
00270 , m_out(&m_streamBuf)
00271 , m_inout(&m_streamBuf)
00272 , m_recvTimeout(Timeout::infinite)
00273 , m_sendTimeout(Timeout::infinite)
00274 , m_connectTimeout(Timeout::relative(0))
00275 {
00276 m_out.exceptions(std::ios::badbit);
00277 m_inout.exceptions(std::ios::badbit);
00278 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00279 BLOCXX_ASSERT(m_event != NULL);
00280 connect(m_peerAddress);
00281 }
00282
00283 #pragma warning (pop)
00284
00286 SocketBaseImpl::~SocketBaseImpl()
00287 {
00288 try
00289 {
00290 disconnect();
00291 }
00292 catch (...)
00293 {
00294
00295 }
00296 ::CloseHandle(m_event);
00297 }
00299 Select_t
00300 SocketBaseImpl::getSelectObj() const
00301 {
00302 Select_t st;
00303 st.event = m_event;
00304 st.sockfd = m_sockfd;
00305 st.isSocket = true;
00306 st.networkevents = FD_READ | FD_WRITE;
00307 st.doreset = true;
00308 return st;
00309 }
00311 void
00312 SocketBaseImpl::connect(const SocketAddress& addr)
00313 {
00314 if (m_isConnected)
00315 {
00316 disconnect();
00317 }
00318 m_streamBuf.reset();
00319 m_in.clear();
00320 m_out.clear();
00321 m_inout.clear();
00322 BLOCXX_ASSERT(addr.getType() == SocketAddress::INET);
00323
00324 m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00325 if (m_sockfd == INVALID_SOCKET)
00326 {
00327 BLOCXX_THROW(SocketException,
00328 Format("Failed to create a socket: %1",
00329 System::lastErrorMsg(true)).c_str());
00330 }
00331
00332 int cc;
00333 WSANETWORKEVENTS networkEvents;
00334
00335
00336 if(::WSAEventSelect(m_sockfd, m_event, FD_CONNECT) != 0)
00337 {
00338 BLOCXX_THROW(SocketException,
00339 Format("WSAEventSelect Failed: %1",
00340 System::lastErrorMsg(true)).c_str());
00341 }
00342
00343 if (::connect(m_sockfd, addr.getNativeForm(), addr.getNativeFormSize())
00344 == SOCKET_ERROR)
00345 {
00346 int lastError = ::WSAGetLastError();
00347 if (lastError != WSAEWOULDBLOCK && lastError != WSAEINPROGRESS)
00348 {
00349 _closeSocket(m_sockfd);
00350 BLOCXX_THROW(SocketException,
00351 Format("Failed to connect to: %1: %2(%3)", addr.toString(),
00352 lastError, System::lastErrorMsg(true)).c_str());
00353 }
00354
00355 TimeoutTimer timer(m_connectTimeout);
00356 int tmoutval = timer.asDWORDMs();
00357
00358
00359 while (true)
00360 {
00361
00362 if ((cc = waitForEvent(m_event, tmoutval)) < 1)
00363 {
00364 _closeSocket(m_sockfd);
00365 switch (cc)
00366 {
00367 case 0:
00368 BLOCXX_THROW(SocketException,
00369 "Sockets have been shutdown");
00370 case -1:
00371 BLOCXX_THROW(SocketException,
00372 Format("Win32SocketBaseImpl connection"
00373 " timed out. Timeout val = %1",
00374 tmoutval).c_str());
00375 default:
00376 BLOCXX_THROW(SocketException, Format("SocketBaseImpl::"
00377 "connect() wait failed: %1(%2)",
00378 ::WSAGetLastError(),
00379 System::lastErrorMsg(true)).c_str());
00380 }
00381 }
00382
00383
00384 if (::WSAEnumNetworkEvents(m_sockfd, m_event, &networkEvents)
00385 == SOCKET_ERROR)
00386 {
00387 _closeSocket(m_sockfd);
00388 BLOCXX_THROW(SocketException,
00389 Format("SocketBaseImpl::connect()"
00390 " failed getting network events: %1(%2)",
00391 ::WSAGetLastError(),
00392 System::lastErrorMsg(true)).c_str());
00393 }
00394
00395
00396 if (networkEvents.lNetworkEvents & FD_CONNECT)
00397 {
00398
00399 if (networkEvents.iErrorCode[FD_CONNECT_BIT])
00400 {
00401 ::WSASetLastError(networkEvents.iErrorCode[FD_CONNECT_BIT]);
00402 _closeSocket(m_sockfd);
00403 BLOCXX_THROW(SocketException,
00404 Format("SocketBaseImpl::connect() failed: %1(%2)",
00405 ::WSAGetLastError(),
00406 System::lastErrorMsg(true)).c_str());
00407 }
00408 break;
00409 }
00410 }
00411 }
00412
00413
00414 if(::WSAEventSelect(m_sockfd, m_event, 0) != 0)
00415 {
00416 _closeSocket(m_sockfd);
00417 BLOCXX_THROW(SocketException,
00418 Format("Resetting socket with WSAEventSelect Failed: %1",
00419 System::lastErrorMsg(true)).c_str());
00420 }
00421 u_long ioctlarg = 0;
00422 ::ioctlsocket(m_sockfd, FIONBIO, &ioctlarg);
00423
00424 m_isConnected = true;
00425
00426 m_peerAddress = addr;
00427
00428 BLOCXX_ASSERT(addr.getType() == SocketAddress::INET);
00429
00430 fillInetAddrParms();
00431 }
00432
00434 void
00435 SocketBaseImpl::disconnect()
00436 {
00437 if(m_in)
00438 {
00439 m_in.clear(ios::eofbit);
00440 }
00441 if(m_out)
00442 {
00443 m_out.clear(ios::eofbit);
00444 }
00445 if(!m_inout.fail())
00446 {
00447 m_inout.clear(ios::eofbit);
00448 }
00449
00450 ::SetEvent(m_event);
00451 _closeSocket(m_sockfd);
00452 m_isConnected = false;
00453 }
00454
00456 void
00457 SocketBaseImpl::fillInetAddrParms()
00458 {
00459 socklen_t len;
00460 InetSocketAddress_t addr;
00461 ::memset(&addr, 0, sizeof(addr));
00462 len = sizeof(addr);
00463 bool gotAddr = false;
00464
00465 if (m_sockfd != INVALID_SOCKET)
00466 {
00467 len = sizeof(addr);
00468 if (::getsockname(m_sockfd,
00469 reinterpret_cast<struct sockaddr*>(&addr), &len) != SOCKET_ERROR)
00470 {
00471 m_localAddress.assignFromNativeForm(&addr, len);
00472 }
00473 else if (getAddrFromIface(addr) == 0)
00474 {
00475 len = sizeof(addr);
00476 m_localAddress.assignFromNativeForm(&addr, len);
00477 }
00478
00479 len = sizeof(addr);
00480 if (::getpeername(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr),
00481 &len) != SOCKET_ERROR)
00482 {
00483 m_peerAddress.assignFromNativeForm(&addr, len);
00484 }
00485 }
00486 else if (getAddrFromIface(addr) == 0)
00487 {
00488 m_localAddress.assignFromNativeForm(&addr, len);
00489 }
00490 }
00491
00492 static Mutex guard;
00494 int
00495 SocketBaseImpl::write(const void* dataOut, int dataOutLen, ErrorAction errorAsException)
00496 {
00497 int rc = 0;
00498 bool isError = false;
00499 if (m_isConnected)
00500 {
00501 isError = waitForOutput(m_sendTimeout);
00502 if (isError)
00503 {
00504 rc = -1;
00505 }
00506 else
00507 {
00508 rc = writeAux(dataOut, dataOutLen);
00509 if (!m_traceFileOut.empty() && rc > 0)
00510 {
00511 MutexLock ml(guard);
00512 ofstream traceFile(m_traceFileOut.c_str(), std::ios::app);
00513 if (!traceFile)
00514 {
00515 BLOCXX_THROW(IOException, "Failed opening socket dump file");
00516 }
00517 if (!traceFile.write(static_cast<const char*>(dataOut), rc))
00518 {
00519 BLOCXX_THROW(IOException, "Failed writing to socket dump");
00520 }
00521
00522 ofstream comboTraceFile(String(m_traceFileOut + "Combo").c_str(), std::ios::app);
00523 if (!comboTraceFile)
00524 {
00525 BLOCXX_THROW(IOException, "Failed opening socket dump file");
00526 }
00527 comboTraceFile << "\n--->Out " << rc << " bytes<---\n";
00528 if (!comboTraceFile.write(static_cast<const char*>(dataOut), rc))
00529 {
00530 BLOCXX_THROW(IOException, "Failed writing to socket dump");
00531 }
00532 }
00533 }
00534 }
00535 else
00536 {
00537 rc = -1;
00538 }
00539 if (rc < 0 && errorAsException)
00540 {
00541 BLOCXX_THROW(SocketException, "SocketBaseImpl::write");
00542 }
00543 return rc;
00544 }
00546 int
00547 SocketBaseImpl::read(void* dataIn, int dataInLen, ErrorAction errorAsException)
00548 {
00549 int rc = 0;
00550 bool isError = false;
00551 if (m_isConnected)
00552 {
00553 isError = waitForInput(m_recvTimeout);
00554 if (isError)
00555 {
00556 rc = -1;
00557 }
00558 else
00559 {
00560 rc = readAux(dataIn, dataInLen);
00561 if (!m_traceFileIn.empty() && rc > 0)
00562 {
00563 MutexLock ml(guard);
00564 ofstream traceFile(m_traceFileIn.c_str(), std::ios::app);
00565 if (!traceFile)
00566 {
00567 BLOCXX_THROW(IOException, "Failed opening tracefile");
00568 }
00569 if (!traceFile.write(reinterpret_cast<const char*>(dataIn), rc))
00570 {
00571 BLOCXX_THROW(IOException, "Failed writing to socket dump");
00572 }
00573
00574 ofstream comboTraceFile(String(m_traceFileOut + "Combo").c_str(), std::ios::app);
00575 if (!comboTraceFile)
00576 {
00577 BLOCXX_THROW(IOException, "Failed opening socket dump file");
00578 }
00579 comboTraceFile << "\n--->In " << rc << " bytes<---\n";
00580 if (!comboTraceFile.write(reinterpret_cast<const char*>(dataIn), rc))
00581 {
00582 BLOCXX_THROW(IOException, "Failed writing to socket dump");
00583 }
00584 }
00585 }
00586 }
00587 else
00588 {
00589 rc = -1;
00590 }
00591 if (rc < 0)
00592 {
00593 if (errorAsException)
00594 BLOCXX_THROW(SocketException, "SocketBaseImpl::read");
00595 }
00596 return rc;
00597 }
00599 bool
00600 SocketBaseImpl::waitForInput(const Timeout& timeOutSecs)
00601 {
00602 int rval = SocketUtils::waitForIO(m_sockfd, m_event, timeOutSecs, FD_READ);
00603 if (rval == ETIMEDOUT)
00604 {
00605 m_recvTimeoutExprd = true;
00606 }
00607 else
00608 {
00609 m_recvTimeoutExprd = false;
00610 }
00611 return (rval != 0);
00612 }
00614 bool
00615 SocketBaseImpl::waitForOutput(const Timeout& timeOutSecs)
00616 {
00617 return SocketUtils::waitForIO(m_sockfd, m_event, timeOutSecs,
00618 FD_WRITE) != 0;
00619 }
00621 istream&
00622 SocketBaseImpl::getInputStream()
00623 {
00624 return m_in;
00625 }
00627 ostream&
00628 SocketBaseImpl::getOutputStream()
00629 {
00630 return m_out;
00631 }
00633 iostream&
00634 SocketBaseImpl::getIOStream()
00635 {
00636 return m_inout;
00637 }
00639
00640 void
00641 SocketBaseImpl::setDumpFiles(const String& in, const String& out)
00642 {
00643 m_traceFileOut = out;
00644 m_traceFileIn = in;
00645 }
00646
00647 }
00648
00649 #endif // #if defined(BLOCXX_WIN32)