Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

PracticalSocket.cpp

Go to the documentation of this file.
00001 /*
00002  *   C++ sockets on Unix and Windows
00003  *   Copyright (C) 2002
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "PracticalSocket.h"
00021 
00022 #ifdef WIN32
00023   #include <winsock.h>         // For socket(), connect(), send(), and recv()
00024   typedef int socklen_t;
00025   typedef char raw_type;       // Type used for raw data on this platform
00026 #else
00027   #include <sys/types.h>       // For data types
00028   #include <sys/socket.h>      // For socket(), connect(), send(), and recv()
00029   #include <netdb.h>           // For gethostbyname()
00030   #include <arpa/inet.h>       // For inet_addr()
00031   #include <unistd.h>          // For close()
00032   #include <netinet/in.h>      // For sockaddr_in
00033   typedef void raw_type;       // Type used for raw data on this platform
00034 #endif
00035 
00036 #include <errno.h>             // For errno
00037 
00038 using namespace std;
00039 
00040 #ifdef WIN32
00041 static bool initialized = false;
00042 #endif
00043 
00044 // SocketException Code
00045 
00046 SocketException::SocketException(const string &message, bool inclSysMsg)
00047   throw() : userMessage(message) {
00048   if (inclSysMsg) {
00049     userMessage.append(": ");
00050     userMessage.append(strerror(errno));
00051   }
00052 }
00053 
00054 SocketException::~SocketException() throw() {
00055 }
00056 
00057 const char *SocketException::what() const throw() {
00058   return userMessage.c_str();
00059 }
00060 
00061 // Function to fill in address structure given an address and port
00062 static void fillAddr(const string &address, unsigned short port, 
00063                      sockaddr_in &addr) {
00064   memset(&addr, 0, sizeof(addr));  // Zero out address structure
00065   addr.sin_family = AF_INET;       // Internet address
00066 
00067   hostent *host;  // Resolve name
00068   if ((host = gethostbyname(address.c_str())) == NULL) {
00069     // strerror() will not work for gethostbyname() and hstrerror() 
00070     // is supposedly obsolete
00071     throw SocketException("Failed to resolve name (gethostbyname())");
00072   }
00073   addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
00074 
00075   addr.sin_port = htons(port);     // Assign port in network byte order
00076 }
00077 
00078 // Socket Code
00079 
00080 Socket::Socket(int type, int protocol) throw(SocketException) {
00081   #ifdef WIN32
00082     if (!initialized) {
00083       WORD wVersionRequested;
00084       WSADATA wsaData;
00085 
00086       wVersionRequested = MAKEWORD(2, 0);              // Request WinSock v2.0
00087       if (WSAStartup(wVersionRequested, &wsaData) != 0) {  // Load WinSock DLL
00088         throw SocketException("Unable to load WinSock DLL");
00089       }
00090       initialized = true;
00091     }
00092   #endif
00093 
00094   // Make a new socket
00095   if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
00096     throw SocketException("Socket creation failed (socket())", true);
00097   }
00098 }
00099 
00100 Socket::Socket(int sockDesc) {
00101   this->sockDesc = sockDesc;
00102 }
00103 
00104 Socket::~Socket() {
00105   #ifdef WIN32
00106     ::closesocket(sockDesc);
00107   #else
00108     ::close(sockDesc);
00109   #endif
00110   sockDesc = -1;
00111 }
00112 
00113 string Socket::getLocalAddress() throw(SocketException) {
00114   sockaddr_in addr;
00115   unsigned int addr_len = sizeof(addr);
00116 
00117   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
00118     throw SocketException("Fetch of local address failed (getsockname())", true);
00119   }
00120   return inet_ntoa(addr.sin_addr);
00121 }
00122 
00123 unsigned short Socket::getLocalPort() throw(SocketException) {
00124   sockaddr_in addr;
00125   unsigned int addr_len = sizeof(addr);
00126 
00127   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
00128     throw SocketException("Fetch of local port failed (getsockname())", true);
00129   }
00130   return ntohs(addr.sin_port);
00131 }
00132 
00133 void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
00134   // Bind the socket to its port
00135   sockaddr_in localAddr;
00136   memset(&localAddr, 0, sizeof(localAddr));
00137   localAddr.sin_family = AF_INET;
00138   localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00139   localAddr.sin_port = htons(localPort);
00140 
00141   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
00142     throw SocketException("Set of local port failed (bind())", true);
00143   }
00144 }
00145 
00146 void Socket::setLocalAddressAndPort(const string &localAddress,
00147     unsigned short localPort) throw(SocketException) {
00148   // Get the address of the requested host
00149   sockaddr_in localAddr;
00150   fillAddr(localAddress, localPort, localAddr);
00151 
00152   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
00153     throw SocketException("Set of local address and port failed (bind())", true);
00154   }
00155 }
00156 
00157 void Socket::cleanUp() throw(SocketException) {
00158   #ifdef WIN32
00159     if (WSACleanup() != 0) {
00160       throw SocketException("WSACleanup() failed");
00161     }
00162   #endif
00163 }
00164 
00165 unsigned short Socket::resolveService(const string &service,
00166                                       const string &protocol) {
00167   struct servent *serv;        /* Structure containing service information */
00168 
00169   if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
00170     return atoi(service.c_str());  /* Service is port number */
00171   else 
00172     return ntohs(serv->s_port);    /* Found port (network byte order) by name */
00173 }
00174 
00175 // CommunicatingSocket Code
00176 
00177 CommunicatingSocket::CommunicatingSocket(int type, int protocol)  
00178     throw(SocketException) : Socket(type, protocol) {
00179 }
00180 
00181 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
00182 }
00183 
00184 void CommunicatingSocket::connect(const string &foreignAddress,
00185     unsigned short foreignPort) throw(SocketException) {
00186   // Get the address of the requested host
00187   sockaddr_in destAddr;
00188   fillAddr(foreignAddress, foreignPort, destAddr);
00189 
00190   // Try to connect to the given port
00191   if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
00192     throw SocketException("Connect failed (connect())", true);
00193   }
00194 }
00195 
00196 void CommunicatingSocket::send(const void *buffer, int bufferLen) 
00197     throw(SocketException) {
00198 #ifdef WIN32
00199   if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
00200 #else
00201   if (::send(sockDesc, (raw_type *) buffer, bufferLen, MSG_NOSIGNAL) < 0) {
00202 #endif
00203     throw SocketException("Send failed (send())", true);
00204   }
00205 }
00206 
00207 int CommunicatingSocket::recv(void *buffer, int bufferLen) 
00208     throw(SocketException) {
00209   int rtn;
00210   if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
00211     throw SocketException("Received failed (recv())", true);
00212   }
00213 
00214   return rtn;
00215 }
00216 
00217 string CommunicatingSocket::getForeignAddress() 
00218     throw(SocketException) {
00219   sockaddr_in addr;
00220   unsigned int addr_len = sizeof(addr);
00221 
00222   if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
00223     throw SocketException("Fetch of foreign address failed (getpeername())", true);
00224   }
00225   return inet_ntoa(addr.sin_addr);
00226 }
00227 
00228 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
00229   sockaddr_in addr;
00230   unsigned int addr_len = sizeof(addr);
00231 
00232   if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
00233     throw SocketException("Fetch of foreign port failed (getpeername())", true);
00234   }
00235   return ntohs(addr.sin_port);
00236 }
00237 
00238 // TCPSocket Code
00239 
00240 TCPSocket::TCPSocket() 
00241     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, 
00242     IPPROTO_TCP) {
00243 }
00244 
00245 TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort)
00246     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
00247   connect(foreignAddress, foreignPort);
00248 }
00249 
00250 TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
00251 }
00252 
00253 // TCPServerSocket Code
00254 
00255 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen) 
00256     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
00257   setLocalPort(localPort);
00258   setListen(queueLen);
00259 }
00260 
00261 TCPServerSocket::TCPServerSocket(const string &localAddress, 
00262     unsigned short localPort, int queueLen) 
00263     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
00264   setLocalAddressAndPort(localAddress, localPort);
00265   setListen(queueLen);
00266 }
00267 
00268 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
00269   int newConnSD;
00270   if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
00271     throw SocketException("Accept failed (accept())", true);
00272   }
00273 
00274   return new TCPSocket(newConnSD);
00275 }
00276 
00277 void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
00278   if (listen(sockDesc, queueLen) < 0) {
00279     throw SocketException("Set listening socket failed (listen())", true);
00280   }
00281 }
00282 
00283 // UDPSocket Code
00284 
00285 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
00286     IPPROTO_UDP) {
00287   setBroadcast();
00288 }
00289 
00290 UDPSocket::UDPSocket(unsigned short localPort)  throw(SocketException) : 
00291     CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
00292   setLocalPort(localPort);
00293   setBroadcast();
00294 }
00295 
00296 UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort) 
00297      throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
00298   setLocalAddressAndPort(localAddress, localPort);
00299   setBroadcast();
00300 }
00301 
00302 void UDPSocket::setBroadcast() {
00303   // If this fails, we'll hear about it when we try to send.  This will allow 
00304   // system that cannot broadcast to continue if they don't plan to broadcast
00305   int broadcastPermission = 1;
00306   setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST, 
00307              (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
00308 }
00309 
00310 void UDPSocket::disconnect() throw(SocketException) {
00311   sockaddr_in nullAddr;
00312   memset(&nullAddr, 0, sizeof(nullAddr));
00313   nullAddr.sin_family = AF_UNSPEC;
00314 
00315   // Try to disconnect
00316   if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
00317    #ifdef WIN32
00318     if (errno != WSAEAFNOSUPPORT) {
00319    #else
00320     if (errno != EAFNOSUPPORT) {
00321    #endif
00322       throw SocketException("Disconnect failed (connect())", true);
00323     }
00324   }
00325 }
00326 
00327 void UDPSocket::sendTo(const void *buffer, int bufferLen, 
00328     const string &foreignAddress, unsigned short foreignPort) 
00329     throw(SocketException) {
00330   sockaddr_in destAddr;
00331   fillAddr(foreignAddress, foreignPort, destAddr);
00332 
00333   // Write out the whole buffer as a single message.
00334   if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
00335              (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
00336     throw SocketException("Send failed (sendto())", true);
00337   }
00338 }
00339 
00340 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
00341     unsigned short &sourcePort) throw(SocketException) {
00342   sockaddr_in clntAddr;
00343   socklen_t addrLen = sizeof(clntAddr);
00344   int rtn;
00345   if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0, 
00346                       (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
00347     throw SocketException("Receive failed (recvfrom())", true);
00348   }
00349   sourceAddress = inet_ntoa(clntAddr.sin_addr);
00350   sourcePort = ntohs(clntAddr.sin_port);
00351 
00352   return rtn;
00353 }
00354 
00355 #ifndef WIN32
00356 // these functions magically stopped compiling... exclude them on Windows
00357 void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
00358   if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL, 
00359                  (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
00360     throw SocketException("Multicast TTL set failed (setsockopt())", true);
00361   }
00362 }
00363 
00364 void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
00365   struct ip_mreq multicastRequest;
00366 
00367   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
00368   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
00369   if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
00370                  (raw_type *) &multicastRequest, 
00371                  sizeof(multicastRequest)) < 0) {
00372     throw SocketException("Multicast group join failed (setsockopt())", true);
00373   }
00374 }
00375 
00376 void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
00377   struct ip_mreq multicastRequest;
00378 
00379   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
00380   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
00381   if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
00382                  (raw_type *) &multicastRequest, 
00383                  sizeof(multicastRequest)) < 0) {
00384     throw SocketException("Multicast group leave failed (setsockopt())", true);
00385   }
00386 }
00387 #endif

Generated on Fri Mar 19 09:30:41 2010 for ImpalaSrc by  doxygen 1.5.1