win32/ntcpsocket.cpp

00001 // LICENSE: (Please see the file COPYING for details)
00002 //
00003 // NUS - Nemesis Utilities System: A C++ application development framework 
00004 // Copyright (C) 2006, 2008 Otavio Rodolfo Piske
00005 //
00006 //  This file is part of NUS
00007 //
00008 //  This library is free software; you can redistribute it and/or
00009 //  modify it under the terms of the GNU Lesser General Public
00010 //  License as published by the Free Software Foundation version 2.1
00011 //  of the License.
00012 //
00013 //  This library is distributed in the hope that it will be useful,
00014 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 //  Lesser General Public License for more details.
00017 //
00018 //  You should have received a copy of the GNU Lesser General Public
00019 //  License along with this library; if not, write to the Free Software
00020 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021 //
00022 #include "ntcpsocket.h"
00023 
00024 NTcpSocket::NTcpSocket(void)
00025       : NAbstractSocket(), 
00026       m_sock(INVALID_SOCKET)
00027 {
00028       init();
00029 }
00030 
00031 
00032 NTcpSocket::NTcpSocket(NHostAddress &host)
00033       : NAbstractSocket(host), 
00034       m_sock(INVALID_SOCKET)
00035 {
00036       init();
00037 }
00038 
00039 
00040 NTcpSocket::NTcpSocket(const NString &host, nuint16 port)
00041       : NAbstractSocket(host, port), 
00042       m_sock(INVALID_SOCKET)
00043 {
00044       init();
00045 }
00046 
00047 NTcpSocket::NTcpSocket(nuint16 timeout, nint32 sock)
00048       : NAbstractSocket(),
00049       m_addr(),
00050       m_sock(sock)
00051 {
00052       init();
00053       setTimeout(timeout);
00054       try {
00055             NDebug::print() << "Creating structures";
00056             m_addr = new struct addrinfo;
00057             NDebug::print() << "Zeroing";
00058             memset(m_addr, 0, sizeof(struct addrinfo));
00059 
00060             m_addr->ai_addr = new struct sockaddr;
00061             memset(m_addr->ai_addr, 0, sizeof(struct sockaddr));
00062 
00063             NDebug::print() << "Done zeroing";
00064       }
00065       catch (std::bad_alloc &) {
00066             if (m_addr && m_addr->ai_addr) {
00067                   delete m_addr->ai_addr;
00068             }
00069             
00070             delete m_addr;
00071             throw;
00072       }
00073 
00074       NDebug::print() << "Setting peer address";
00075       m_host = peerAddress();
00076       setPort(peerPort());
00077 }
00078 
00079 
00080 NTcpSocket::~NTcpSocket(void) {
00081    WSACleanup();
00082 }
00083 
00084 
00085 void NTcpSocket::init(void) {
00086       WORD version; 
00087       WSADATA wsaData; 
00088 
00089       memset(&m_host, 0, sizeof(m_host));
00090       
00091       version = MAKEWORD(2 , 2);
00092       
00093       if (WSAStartup(version, &wsaData) != 0) {
00094             throw NNetworkException("Unable to initialize winsock", "",
00095                   NException::NETWORK, NNetworkException::SOCKET_INIT_FAILED);
00096       }
00097 
00098       if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
00099             WSACleanup();
00100             throw NNetworkException("Incorrect Winsock version", "", 
00101                   NException::NETWORK, NNetworkException::SOCKET_INIT_FAILED);
00102       }
00103 
00104       
00105 }
00106 
00107 
00108 void NTcpSocket::setPort(nint16 port) {
00109       NAbstractSocket::setPort(port);
00110 }
00111 
00112 
00113 void NTcpSocket::setSocketOptions(nint32 opt) {
00114 
00115 }
00116 
00117 
00118 void NTcpSocket::throwSocketError(int err) const {
00119       NString msg;
00120       
00121       switch (err) {
00122             case WSANOTINITIALISED: {
00123                   msg = "Winsock was not initialized";
00124                   break;
00125             }
00126             case WSAENETDOWN: {
00127                   msg = "The network subsystem is down";
00128                   break;
00129             }
00130             case WSAEAFNOSUPPORT: {
00131                   msg = "Address family not supported";
00132                   break;
00133             }
00134             case WSAEINPROGRESS: {
00135                   msg = "A blocking winsock call is in progress";
00136                   break;
00137             }
00138             case WSAEMFILE: {
00139                   msg = "No more socket descriptors available";
00140                   break;
00141             }
00142             case WSAENOBUFS: {
00143                   msg = "No buffer space is available";
00144                   break;
00145             }
00146             case WSAEPROTONOSUPPORT: {
00147                   msg = "Protocol not supported";
00148                   break;
00149             }
00150             case WSAEPROTOTYPE: {
00151                   msg = "The specified protocol is incorrect";
00152                   break;
00153             } 
00154             case WSAESOCKTNOSUPPORT: {
00155                   msg = "The specified socket type is incorrect";
00156                   break;
00157             }
00158             case WSATRY_AGAIN: {
00159                   msg = "Temporary failure in name resolution";
00160                   break;
00161             }
00162             case WSAEINVAL: {
00163                   msg = "Invalid value";
00164                   break;
00165             }
00166             case WSANO_RECOVERY: {
00167                   msg = "Nonrecoverable error in name resolution";
00168                   break;
00169             }
00170             case WSA_NOT_ENOUGH_MEMORY: {
00171                   msg = "Not enough memory";
00172                   break;
00173             }
00174             case WSAHOST_NOT_FOUND: {
00175                   msg = "Host not found";
00176                   break;
00177             }
00178             case WSATYPE_NOT_FOUND: {
00179                   msg = "Unsupported service type";
00180                   break;
00181             }
00182             default: {
00183                   msg = "Unhandled exception";
00184                   break;
00185             }
00186       }
00187       
00188       throw NNetworkException(msg, m_host.toString(), NException::NETWORK, 
00189             NNetworkException::SOCKET_INIT_FAILED);
00190 }
00191 
00192 
00193 void NTcpSocket::open(void) {
00194       NString port;
00195       struct addrinfo hints;
00196       int ret = 0;
00197       
00198       if (m_sock != INVALID_SOCKET) {
00199             return;
00200       }
00201 
00202       memset(&hints, 0, sizeof(hints));
00203       hints.ai_family = AF_INET;
00204       hints.ai_socktype = SOCK_STREAM;
00205       hints.ai_protocol = IPPROTO_TCP;
00206 
00207       port = NString::number(m_port);
00208       
00209       if (m_host.isNull()) {
00210             ret = getaddrinfo(NULL, port.toChar(), &hints, &m_addr);
00211       }
00212       else {
00213             ret = getaddrinfo(m_host.toString().toChar(), port.toChar(), &hints, &m_addr);
00214       }
00215 
00216       if (ret != 0) {
00217             NDebug::print() << "Getaddrinfo error!";
00218             throwSocketError(WSAGetLastError());
00219       }
00220       
00221       m_sock = socket(m_addr->ai_family, m_addr->ai_socktype, m_addr->ai_protocol);
00222       if (m_sock == INVALID_SOCKET) {
00223             NDebug::print() << "socket() error!";
00224             throwSocketError(WSAGetLastError());
00225       }
00226 }
00227 
00228 
00229 void NTcpSocket::closeDevice(void) {
00230       disconnectFromHost();
00231 }
00232 
00233 
00234 void NTcpSocket::disconnectFromHost(void) {
00235       if (m_sock > 0) {
00236             closesocket(m_sock);
00237             m_sock = 0;
00238       }
00239 }
00240 
00241 
00242 
00243 void NTcpSocket::connectToHost(void) {
00244       int ret = 0;
00245 
00246       ret = connect(m_sock, m_addr->ai_addr, (int) m_addr->ai_addrlen);
00247       if (ret == SOCKET_ERROR) {
00248             NString msg = "Unable to connect to ";
00249             disconnectFromHost();
00250             
00251             msg += m_host.toString() + NSTR(":") + NString::number(m_port);
00252             throw NNetworkException(msg, m_host.toString(), NException::NETWORK,
00253                   NNetworkException::CONNECTION_FAILED);
00254       }
00255 }
00256 
00257 
00258 void NTcpSocket::execBind(void) {
00259       if (bind(m_sock, m_addr->ai_addr, (int)m_addr->ai_addrlen) == SOCKET_ERROR) {
00260             throwSocketError(WSAGetLastError());
00261       }
00262 }
00263 
00264 
00265 void NTcpSocket::execListen(void) {
00266       execBind();
00267       if (listen(m_sock, m_maxPendingConn) == SOCKET_ERROR) {
00268             disconnectFromHost();
00269             throw NNetworkException("Unable to listen", "",
00270                   NException::NETWORK, NNetworkException::SOCKET_INIT_FAILED);
00271       }
00272 }
00273 
00274 
00275 NTcpSocket *NTcpSocket::waitForConnected(void) {
00276       SOCKET client = INVALID_SOCKET;
00277       NTcpSocket *ret = NULL;
00278 
00279       NDebug::print() << "Accepting ... ";
00280       client = accept(m_sock, NULL, NULL);
00281       if (client == INVALID_SOCKET) {
00282             NDebug::print() << "Unable to accept ...";
00283             throwSocketError(WSAGetLastError());
00284       }
00285 
00286       NDebug::print() << "Accepted";
00287       ret = new NTcpSocket(m_timeout, client);
00288       ret->setTimeout(m_timeout);
00289       
00290       return ret;
00291 }
00292 
00293 NHostAddress NTcpSocket::peerAddress(void) const {
00294       NHostAddress addr;
00295       int len = 0;
00296 
00297       getpeername(m_sock, m_addr->ai_addr, &len);           
00298       addr.setAddress(m_addr->ai_addr);
00299 
00300       return addr;
00301 }
00302 
00303 
00304 NString NTcpSocket::peerName(void) const {
00305       return peerAddress().toString();
00306 }
00307 
00308 
00309 nuint16 NTcpSocket::peerPort(void) const {
00310       struct sockaddr_in *tmp;
00311 
00312       tmp = reinterpret_cast<sockaddr_in *>(m_addr->ai_addr);
00313       return ntohs(tmp->sin_port);
00314 }
00315 
00316 
00317 
00318 nint32 NTcpSocket::read(NDataStream *buffer) {
00319       nint32 bread = 0;
00320       fd_set fd;
00321       timeval timeout;
00322       nint32 sel = 0;
00323       socklen_t len = 0;
00324       nint32 numRead = -1;
00325       char tmp[2048];
00326 
00327       FD_ZERO(&fd);
00328       FD_SET(m_sock, &fd);
00329       
00330       timeout.tv_sec = m_timeout;
00331       timeout.tv_usec = 0;
00332       
00333       sel = select(m_sock + 1, &fd, NULL, NULL, &timeout);
00334       if (sel < 0) {
00335             throw NNetworkException(nerror(errno), m_host.toString(), 
00336                   NException::NETWORK, NNetworkException::SOCK_ERROR);
00337       }
00338       
00339       if (sel == 0) {
00340             // timedout
00341             return 0;
00342       }
00343       
00344       *buffer = "";
00345       do { 
00346             memset(tmp, 0, sizeof(tmp));
00347 
00348             numRead = recvfrom(m_sock, tmp, sizeof(tmp), 0, m_addr->ai_addr, 
00349                   &len);
00350 
00351             if (numRead < 0) {
00352                   NDebug::print() << "I did not received an orderly shutdown: "
00353                                << WSAGetLastError();;
00354                   return -1;
00355             }
00356             else {
00357                   // There's action in a file descriptor but no data to read
00358                   // it's likely that the remote peer disconnected
00359                   if (sel == 1 && numRead == 0 && bread == 0) {
00360                         return -1;
00361                   }
00362             }
00363             
00364             bread += numRead;
00365             buffer->append(tmp, numRead);
00366       } while (numRead > 0);
00367       
00368       return bread;
00369 }
00370 
00371 
00372 nint32 NTcpSocket::read(NDataStream *buffer, nuint32 bytes) {
00373       nuint32 bread = 0;
00374       fd_set fd;
00375       timeval timeout;
00376       nint32 sel = 0;
00377       socklen_t len = 0;
00378       nint32 numRead = -1;
00379       char tmp[1];
00380 
00381       FD_ZERO(&fd);
00382       FD_SET(m_sock, &fd);
00383       
00384       timeout.tv_sec = m_timeout;
00385       timeout.tv_usec = 0;
00386       
00387       sel = select(m_sock + 1, &fd, NULL, NULL, &timeout);
00388       if (sel < 0) {
00389             throw NNetworkException(nerror(errno), m_host.toString(), 
00390                   NException::NETWORK, NNetworkException::SOCK_ERROR);
00391       }
00392       
00393       if (sel == 0) {
00394             // timedout
00395             return 0;
00396       }
00397       
00398       *buffer = "";
00399       do { 
00400             memset(tmp, 0, sizeof(tmp));
00401 
00402             numRead = recvfrom(m_sock, tmp, 1, 0, m_addr->ai_addr, &len);
00403 
00404             if (numRead < 0) {
00405                   NDebug::print() << "I did not received an orderly shutdown: "
00406                                << WSAGetLastError();;
00407                   return -1;
00408             }
00409             else {
00410                   // There's action in a file descriptor but no data to read
00411                   // it's likely that the remote peer disconnected
00412                   if (sel == 1 && numRead == 0 && bread == 0) {
00413                         return -1;
00414                   }
00415             }
00416             
00417             bread += numRead;
00418             buffer->append(tmp, numRead);
00419       } while (numRead > 0 && bread < bytes);
00420       
00421       return bread;
00422 }
00423 
00424 
00425 nint32 NTcpSocket::readLine(NDataStream *buffer) {
00426       nint32 bread = 0;
00427       fd_set fd;
00428       timeval timeout;
00429       nint32 sel = 0;
00430       socklen_t len = 0;
00431       nint32 numRead = -1;
00432       char tmp[1];
00433 
00434       FD_ZERO(&fd);
00435       FD_SET(m_sock, &fd);
00436       
00437       timeout.tv_sec = m_timeout;
00438       timeout.tv_usec = 0;
00439       
00440       sel = select(m_sock + 1, &fd, NULL, NULL, &timeout);
00441       if (sel == SOCKET_ERROR) {
00442             throwSocketError(WSAGetLastError());
00443       }
00444       
00445       if (sel == 0) {
00446             // timedout
00447             return -1;
00448       }
00449       
00450       *buffer = "";
00451       do { 
00452             memset(tmp, 0, sizeof(tmp));
00453 
00454             numRead = recvfrom(m_sock, tmp, sizeof(tmp), 0, m_addr->ai_addr, &len);
00455             if (numRead < 0) {
00456                   NDebug::print() << "I did not received an orderly shutdown: "
00457                                << WSAGetLastError();;
00458                   return -1;
00459             }
00460             else {
00461                   // There's action in a file descriptor but no data to read
00462                   // it's likely that the remote peer disconnected
00463                   if (sel == 1 && numRead == 0 && bread == 0) {
00464                         return -1;
00465                   }
00466             }
00467             
00468             bread += numRead;
00469             buffer->append(tmp, numRead);
00470             if (tmp[0] == '\n' || tmp[0] == '\0') {
00471                   break;
00472             }
00473       } while (numRead > 0);
00474       
00475       return bread;
00476 }
00477 
00478 
00479 nint32 NTcpSocket::write(const NDataStream &data, nuint32 bytes) {
00480       if (bytes == 0) {
00481             return send(m_sock, static_cast<const char *>(data.data()), data.size(), 0);
00482       }
00483             
00484       return send(m_sock, static_cast<const char *>(data.data()), bytes, 0);
00485 }
00486 
00487 
00488 nint32 NTcpSocket::writeLine(const NDataStream &data, nuint32 bytes) {
00489       NDataStream tmp = data;
00490 
00491       tmp += "\r\n";
00492 
00493       if (bytes == 0) {
00494             return send(m_sock, static_cast<const char *>(tmp.data()), tmp.size() + 2, 0);
00495       }
00496             
00497       return send(m_sock, static_cast<const char *>(tmp.data()), bytes, 0);
00498 }

Generated on Wed Mar 5 23:10:36 2008 for NemesisUtilitiesSystem by  doxygen 1.5.4