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