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