1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 //#include "stdafx.h"
17 
18 #include "debugger/socket.h"
19 
20 #include <sstream>
21 
22 
23 #if defined WIN32 || defined WINCE
24 #include <winsock2.h>
25   typedef int socklen_t;
26   typedef char raw_type;
27 
28 #ifdef WIN32
29 static bool initialized = false;
30 #endif
31 #else
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netdb.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37 #include <netinet/in.h>
38 
39 #include <cstring>
40 #include <cstdlib>
41 
42   typedef void raw_type;
43 #endif
44 
45 #include <errno.h>
46 
47 #include "zorbautils/lock.h"
48 
49 namespace zorba {
50 
51 // Function to fill in address structure given an address and port
fillAddr(const std::string & address,unsigned short port,sockaddr_in & addr)52 static void fillAddr(const std::string &address, unsigned short port,
53                      sockaddr_in &addr) {
54   // we have to lock calls to gethostbyname because
55   // it's not thread-safe
56   static zorba::Lock theLock;
57   memset(&addr, 0, sizeof(addr));  // Zero out address structure
58   addr.sin_family = AF_INET;       // Internet address
59 
60   theLock.rlock();
61   hostent *host;  // Resolve name
62   if ((host = gethostbyname(address.c_str())) == NULL) {
63     // strerror() will not work for gethostbyname() and hstrerror()
64     // is supposedly obsolete
65     theLock.unlock();
66     throw DebuggerSocketException("Failed to resolve name (gethostbyname())");
67   }
68   addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
69 
70   addr.sin_port = htons(port);     // Assign port in network byte order
71   theLock.unlock();
72 }
73 
74 // Socket Code
75 
Socket(int aType,int aProtocol)76 Socket::Socket(int aType, int aProtocol)
77 {
78 #ifdef WIN32
79   if (!initialized) {
80     WORD wVersionRequested;
81     WSADATA wsaData;
82 
83     wVersionRequested = MAKEWORD(2, 0);              // Request WinSock v2.0
84     if (WSAStartup(wVersionRequested, &wsaData) != 0) {  // Load WinSock DLL
85       throw DebuggerSocketException("Unable to load WinSock DLL");
86     }
87     initialized = true;
88   }
89 #endif
90 
91   // Make a new socket
92   theDescriptor = socket(PF_INET, aType, aProtocol);
93   if (theDescriptor == INVALID_SOCKET) {
94       throw DebuggerSocketException("Socket creation failed (socket())", true);
95   }
96 }
97 
Socket(SOCKET aDescriptor)98 Socket::Socket(SOCKET aDescriptor)
99 {
100   this->theDescriptor = aDescriptor;
101 }
102 
~Socket()103 Socket::~Socket() {
104   close();
105 }
106 
107 void
close()108 Socket::close() {
109 #ifdef WIN32
110   ::closesocket(theDescriptor);
111 #else
112   ::close(theDescriptor);
113 #endif
114 }
115 
getLocalAddress()116 std::string Socket::getLocalAddress() {
117   sockaddr_in addr;
118   unsigned int addr_len = sizeof(addr);
119 
120   if (getsockname(theDescriptor, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
121     throw DebuggerSocketException("Fetch of local address failed (getsockname())", true);
122   }
123   return inet_ntoa(addr.sin_addr);
124 }
125 
getLocalPort()126 unsigned short Socket::getLocalPort() {
127   sockaddr_in addr;
128   unsigned int addr_len = sizeof(addr);
129 
130   if (getsockname(theDescriptor, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
131     throw DebuggerSocketException("Fetch of local port failed (getsockname())", true);
132   }
133   return ntohs(addr.sin_port);
134 }
135 
setLocalPort(unsigned short localPort)136 void Socket::setLocalPort(unsigned short localPort) {
137   // Bind the socket to its port
138   sockaddr_in localAddr;
139   memset(&localAddr, 0, sizeof(localAddr));
140   localAddr.sin_family = AF_INET;
141   localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
142   localAddr.sin_port = htons(localPort);
143   int opt = 1;
144   setsockopt(theDescriptor, SOL_SOCKET,SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
145   if (bind(theDescriptor, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
146     std::stringstream lMsg;
147     lMsg << "Set of local port failed: " << localPort;
148     throw DebuggerSocketException(lMsg.str(), true);
149   }
150 }
151 
setLocalAddressAndPort(const std::string & localAddress,unsigned short localPort)152 void Socket::setLocalAddressAndPort(const std::string &localAddress,
153     unsigned short localPort) {
154   // Get the address of the requested host
155   sockaddr_in localAddr;
156   fillAddr(localAddress, localPort, localAddr);
157   int opt = 1;
158   setsockopt(theDescriptor, SOL_SOCKET,SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
159   if (bind(theDescriptor, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
160     throw DebuggerSocketException("Set of local address and port failed (bind())", true);
161   }
162 }
163 
cleanUp()164 void Socket::cleanUp() {
165 #ifdef WIN32
166     if (WSACleanup() != 0) {
167       throw DebuggerSocketException("WSACleanup() failed");
168     }
169 #endif
170 }
171 
resolveService(const std::string & service,const std::string & protocol)172 unsigned short Socket::resolveService(const std::string &service,
173                                       const std::string &protocol) {
174   struct servent *serv;        /* Structure containing service information */
175 
176   if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
177     return atoi(service.c_str());  /* Service is port number */
178   else
179     return ntohs(serv->s_port);    /* Found port (network byte order) by name */
180 }
181 
182 // CommunicatingSocket Code
183 
CommunicatingSocket(int type,int protocol)184 CommunicatingSocket::CommunicatingSocket(int type, int protocol):
185   Socket(type, protocol) {
186 }
187 
CommunicatingSocket(SOCKET newConnSD)188 CommunicatingSocket::CommunicatingSocket(SOCKET newConnSD) : Socket(newConnSD) {
189 }
190 
connect(const std::string & foreignAddress,unsigned short foreignPort)191 void CommunicatingSocket::connect(const std::string &foreignAddress,
192     unsigned short foreignPort) {
193   // Get the address of the requested host
194   sockaddr_in destAddr;
195   fillAddr(foreignAddress, foreignPort, destAddr);
196 
197   // Try to connect to the given port
198   if (::connect(theDescriptor, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
199     std::stringstream lMsg;
200     lMsg << "Connection @" << foreignAddress << ":" << foreignPort << " failed.";
201     throw DebuggerSocketException( lMsg.str(), true);
202   }
203 }
204 
send(const void * buffer,int bufferLen)205 void CommunicatingSocket::send(const void *buffer, int bufferLen)
206 {
207   if (::send(theDescriptor, (raw_type *) buffer, bufferLen, 0) < 0) {
208     throw DebuggerSocketException("Send failed (send())", true);
209   }
210 }
211 
recv(void * buffer,int bufferLen)212 int CommunicatingSocket::recv(void *buffer, int bufferLen) {
213   int rtn;
214   if ((rtn = ::recv(theDescriptor, (raw_type *) buffer, bufferLen, 0)) < 0) {
215     throw DebuggerSocketException("Received failed (recv())", true);
216   }
217 
218   return rtn;
219 }
220 
getForeignAddress()221 std::string CommunicatingSocket::getForeignAddress() {
222   sockaddr_in addr;
223   unsigned int addr_len = sizeof(addr);
224 
225   if (getpeername(theDescriptor, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
226     throw DebuggerSocketException("Fetch of foreign address failed (getpeername())", true);
227   }
228   return inet_ntoa(addr.sin_addr);
229 }
230 
getForeignPort()231 unsigned short CommunicatingSocket::getForeignPort() {
232   sockaddr_in addr;
233   unsigned int addr_len = sizeof(addr);
234 
235   if (getpeername(theDescriptor, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
236     throw DebuggerSocketException("Fetch of foreign port failed (getpeername())", true);
237   }
238   return ntohs(addr.sin_port);
239 }
240 
241 // TCPSocket Code
242 
TCPSocket()243 TCPSocket::TCPSocket(): CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
244 }
245 
TCPSocket(const std::string & foreignAddress,unsigned short foreignPort)246 TCPSocket::TCPSocket(const std::string &foreignAddress, unsigned short foreignPort): CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
247   connect(foreignAddress, foreignPort);
248 }
249 
TCPSocket(SOCKET newConnSD)250 TCPSocket::TCPSocket(SOCKET newConnSD) : CommunicatingSocket(newConnSD) {
251 }
252 
253 // TCPServerSocket Code
254 
TCPServerSocket(unsigned short localPort,int queueLen)255 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen): Socket(SOCK_STREAM, IPPROTO_TCP) {
256   setLocalPort(localPort);
257   setListen(queueLen);
258 }
259 
TCPServerSocket(const std::string & localAddress,unsigned short localPort,int queueLen)260 TCPServerSocket::TCPServerSocket(const std::string &localAddress,
261     unsigned short localPort, int queueLen): Socket(SOCK_STREAM, IPPROTO_TCP) {
262   setLocalAddressAndPort(localAddress, localPort);
263   setListen(queueLen);
264 }
265 
accept()266 TCPSocket *TCPServerSocket::accept() {
267   SOCKET newConnSD = ::accept(theDescriptor, NULL, 0);
268   if (newConnSD == INVALID_SOCKET) {
269     throw DebuggerSocketException("Accept failed (accept())", true);
270   }
271 
272   return new TCPSocket(newConnSD);
273 }
274 
setListen(int queueLen)275 void TCPServerSocket::setListen(int queueLen) {
276   if (listen(theDescriptor, queueLen) < 0) {
277     throw DebuggerSocketException("Set listening socket failed (listen())", true);
278   }
279 }
280 
281 }//end of namespace
282