blob: 51509a30480d3a04eff0784cc3d89be2d6c10cec [file] [log] [blame]
The Android Open Source Projectd245d1d2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2005 The Android Open Source Project
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
17//
18// Internet address class.
19//
20
21#ifdef HAVE_WINSOCK
22// This needs to come first, or Cygwin gets concerned about a potential
23// clash between WinSock and <sys/types.h>.
24# include <winsock2.h>
25#endif
26
27#include <utils/Socket.h>
28#include <utils/inet_address.h>
29#include <utils/Log.h>
30#include <utils/Timers.h>
31
32#ifndef HAVE_WINSOCK
33# include <sys/types.h>
34# include <sys/socket.h>
35# include <netinet/in.h>
36# include <arpa/inet.h>
37#endif
38
39#include <stdlib.h>
40#include <stdio.h>
41#include <unistd.h>
42#include <string.h>
43#include <errno.h>
44#include <assert.h>
45
46using namespace android;
47
48
49/*
50 * ===========================================================================
51 * Socket
52 * ===========================================================================
53 */
54
55#ifndef INVALID_SOCKET
56# define INVALID_SOCKET (-1)
57#endif
58#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
59
60/*static*/ bool Socket::mBootInitialized = false;
61
62/*
63 * Extract system-dependent error code.
64 */
65static inline int getSocketError(void) {
66#ifdef HAVE_WINSOCK
67 return WSAGetLastError();
68#else
69 return errno;
70#endif
71}
72
73/*
74 * One-time initialization for socket code.
75 */
76/*static*/ bool Socket::bootInit(void)
77{
78#ifdef HAVE_WINSOCK
79 WSADATA wsaData;
80 int err;
81
82 err = WSAStartup(MAKEWORD(2, 0), &wsaData);
83 if (err != 0) {
84 LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
85 return false;
86 }
87
88 LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
89 LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
90#endif
91
92 mBootInitialized = true;
93 return true;
94}
95
96/*
97 * One-time shutdown for socket code.
98 */
99/*static*/ void Socket::finalShutdown(void)
100{
101#ifdef HAVE_WINSOCK
102 WSACleanup();
103#endif
104 mBootInitialized = false;
105}
106
107
108/*
109 * Simple constructor. Allow the application to create us and then make
110 * bind/connect calls.
111 */
112Socket::Socket(void)
113 : mSock(UNDEF_SOCKET)
114{
115 if (!mBootInitialized)
116 LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
117}
118
119/*
120 * Destructor. Closes the socket and resets our storage.
121 */
122Socket::~Socket(void)
123{
124 close();
125}
126
127
128/*
129 * Create a socket and connect to the specified host and port.
130 */
131int Socket::connect(const char* host, int port)
132{
133 if (mSock != UNDEF_SOCKET) {
134 LOG(LOG_WARN, "socket", "Socket already connected\n");
135 return -1;
136 }
137
138 InetSocketAddress sockAddr;
139 if (!sockAddr.create(host, port))
140 return -1;
141
142 //return doConnect(sockAddr);
143 int foo;
144 foo = doConnect(sockAddr);
145 return foo;
146}
147
148/*
149 * Create a socket and connect to the specified host and port.
150 */
151int Socket::connect(const InetAddress* addr, int port)
152{
153 if (mSock != UNDEF_SOCKET) {
154 LOG(LOG_WARN, "socket", "Socket already connected\n");
155 return -1;
156 }
157
158 InetSocketAddress sockAddr;
159 if (!sockAddr.create(addr, port))
160 return -1;
161
162 return doConnect(sockAddr);
163}
164
165/*
166 * Finish creating a socket by connecting to the remote host.
167 *
168 * Returns 0 on success.
169 */
170int Socket::doConnect(const InetSocketAddress& sockAddr)
171{
172#ifdef HAVE_WINSOCK
173 SOCKET sock;
174#else
175 int sock;
176#endif
177 const InetAddress* addr = sockAddr.getAddress();
178 int port = sockAddr.getPort();
179 struct sockaddr_in inaddr;
180 DurationTimer connectTimer;
181
182 assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
183 memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
184 inaddr.sin_port = htons(port);
185
186 //fprintf(stderr, "--- connecting to %s:%d\n",
187 // sockAddr.getHostName(), port);
188
189 sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
190 if (sock == INVALID_SOCKET) {
191 int err = getSocketError();
192 LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
193 return (err != 0) ? err : -1;
194 }
195
196 connectTimer.start();
197
198 if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
199 int err = getSocketError();
200 LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
201 sockAddr.getHostName(), port, err);
202 return (err != 0) ? err : -1;
203 }
204
205 connectTimer.stop();
206 if ((long) connectTimer.durationUsecs() > 100000) {
207 LOG(LOG_INFO, "socket",
208 "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
209 port, ((long) connectTimer.durationUsecs()) / 1000000.0);
210 }
211
212 mSock = (unsigned long) sock;
213 LOG(LOG_VERBOSE, "socket",
214 "--- connected to %s:%d\n", sockAddr.getHostName(), port);
215 return 0;
216}
217
218
219/*
220 * Close the socket if it needs closing.
221 */
222bool Socket::close(void)
223{
224 if (mSock != UNDEF_SOCKET) {
225 //fprintf(stderr, "--- closing socket %lu\n", mSock);
226#ifdef HAVE_WINSOCK
227 if (::closesocket((SOCKET) mSock) != 0)
228 return false;
229#else
230 if (::close((int) mSock) != 0)
231 return false;
232#endif
233 }
234
235 mSock = UNDEF_SOCKET;
236
237 return true;
238}
239
240/*
241 * Read data from socket.
242 *
243 * Standard semantics: read up to "len" bytes into "buf". Returns the
244 * number of bytes read, or less than zero on error.
245 */
246int Socket::read(void* buf, ssize_t len) const
247{
248 if (mSock == UNDEF_SOCKET) {
249 LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
250 return -500;
251 }
252
253#ifdef HAVE_WINSOCK
254 SOCKET sock = (SOCKET) mSock;
255#else
256 int sock = (int) mSock;
257#endif
258 int cc;
259
260 cc = recv(sock, (char*)buf, len, 0);
261 if (cc < 0) {
262 int err = getSocketError();
263 return (err > 0) ? -err : -1;
264 }
265
266 return cc;
267}
268
269/*
270 * Write data to a socket.
271 *
272 * Standard semantics: write up to "len" bytes into "buf". Returns the
273 * number of bytes written, or less than zero on error.
274 */
275int Socket::write(const void* buf, ssize_t len) const
276{
277 if (mSock == UNDEF_SOCKET) {
278 LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
279 return -500;
280 }
281
282#ifdef HAVE_WINSOCK
283 SOCKET sock = (SOCKET) mSock;
284#else
285 int sock = (int) mSock;
286#endif
287 int cc;
288
289 cc = send(sock, (const char*)buf, len, 0);
290 if (cc < 0) {
291 int err = getSocketError();
292 return (err > 0) ? -err : -1;
293 }
294
295 return cc;
296}
297
298
299/*
300 * ===========================================================================
301 * Socket tests
302 * ===========================================================================
303 */
304
305/*
306 * Read all data from the socket. The data is read into a buffer that
307 * expands as needed.
308 *
309 * On exit, the buffer is returned, and the length of the data is stored
310 * in "*sz". A null byte is added to the end, but is not included in
311 * the length.
312 */
313static char* socketReadAll(const Socket& s, int *sz)
314{
315 int max, r;
316 char *data, *ptr, *tmp;
317
318 data = (char*) malloc(max = 32768);
319 if (data == NULL)
320 return NULL;
321
322 ptr = data;
323
324 for (;;) {
325 if ((ptr - data) == max) {
326 tmp = (char*) realloc(data, max *= 2);
327 if(tmp == 0) {
328 free(data);
329 return 0;
330 }
331 }
332 r = s.read(ptr, max - (ptr - data));
333 if (r == 0)
334 break;
335 if (r < 0) {
336 LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
337 break;
338 }
339 ptr += r;
340 }
341
342 if ((ptr - data) == max) {
343 tmp = (char*) realloc(data, max + 1);
344 if (tmp == NULL) {
345 free(data);
346 return NULL;
347 }
348 }
349 *ptr = '\0';
350 *sz = (ptr - data);
351 return data;
352}
353
354/*
355 * Exercise the Socket class.
356 */
357void android::TestSockets(void)
358{
359 printf("----- SOCKET TEST ------\n");
360 Socket::bootInit();
361
362 char* buf = NULL;
363 int len, cc;
364 const char* kTestStr =
365 "GET / HTTP/1.0\n"
366 "Connection: close\n"
367 "\n";
368
369 Socket sock;
370 if (sock.connect("www.google.com", 80) != 0) {
371 fprintf(stderr, "socket connected failed\n");
372 goto bail;
373 }
374
375 cc = sock.write(kTestStr, strlen(kTestStr));
376 if (cc != (int) strlen(kTestStr)) {
377 fprintf(stderr, "write failed, res=%d\n", cc);
378 goto bail;
379 }
380 buf = socketReadAll(sock, &len);
381
382 printf("GOT '%s'\n", buf);
383
384bail:
385 sock.close();
386 free(buf);
387}
388