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