The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 46 | using 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 | */ |
| 65 | static 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 | */ |
| 112 | Socket::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 | */ |
| 122 | Socket::~Socket(void) |
| 123 | { |
| 124 | close(); |
| 125 | } |
| 126 | |
| 127 | |
| 128 | /* |
| 129 | * Create a socket and connect to the specified host and port. |
| 130 | */ |
| 131 | int 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 | */ |
| 151 | int 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 | */ |
| 170 | int 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 | */ |
| 222 | bool 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 | */ |
| 246 | int 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 | */ |
| 275 | int 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 | */ |
| 313 | static 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 | */ |
| 357 | void 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 | |
| 384 | bail: |
| 385 | sock.close(); |
| 386 | free(buf); |
| 387 | } |
| 388 | |