1/* 2** Copyright 2006, 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#include <errno.h> 18#include <fcntl.h> 19#include <stddef.h> 20#include <stdlib.h> 21#include <string.h> 22#include <unistd.h> 23 24#include <sys/socket.h> 25#include <sys/select.h> 26#include <sys/types.h> 27#include <netinet/in.h> 28#include <netdb.h> 29 30#include <cutils/sockets.h> 31 32/* Connect to port on the IP interface. type is 33 * SOCK_STREAM or SOCK_DGRAM. 34 * return is a file descriptor or -1 on error 35 */ 36int socket_network_client(const char *host, int port, int type) 37{ 38 return socket_network_client_timeout(host, port, type, 0); 39} 40 41/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM. 42 * timeout in seconds return is a file descriptor or -1 on error 43 */ 44int socket_network_client_timeout(const char *host, int port, int type, int timeout) 45{ 46 struct hostent *hp; 47 struct sockaddr_in addr; 48 int s; 49 int flags = 0, error = 0, ret = 0; 50 fd_set rset, wset; 51 socklen_t len = sizeof(error); 52 struct timeval ts; 53 54 ts.tv_sec = timeout; 55 ts.tv_usec = 0; 56 57 hp = gethostbyname(host); 58 if (hp == 0) return -1; 59 60 memset(&addr, 0, sizeof(addr)); 61 addr.sin_family = hp->h_addrtype; 62 addr.sin_port = htons(port); 63 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); 64 65 s = socket(hp->h_addrtype, type, 0); 66 if (s < 0) return -1; 67 68 if ((flags = fcntl(s, F_GETFL, 0)) < 0) { 69 close(s); 70 return -1; 71 } 72 73 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { 74 close(s); 75 return -1; 76 } 77 78 if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { 79 if (errno != EINPROGRESS) { 80 close(s); 81 return -1; 82 } 83 } 84 85 if (ret == 0) 86 goto done; 87 88 FD_ZERO(&rset); 89 FD_SET(s, &rset); 90 wset = rset; 91 92 if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) { 93 close(s); 94 return -1; 95 } 96 if (ret == 0) { // we had a timeout 97 errno = ETIMEDOUT; 98 close(s); 99 return -1; 100 } 101 102 if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) { 103 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 104 close(s); 105 return -1; 106 } 107 } else { 108 close(s); 109 return -1; 110 } 111 112 if (error) { // check if we had a socket error 113 errno = error; 114 close(s); 115 return -1; 116 } 117 118done: 119 if (fcntl(s, F_SETFL, flags) < 0) { 120 close(s); 121 return -1; 122 } 123 124 return s; 125} 126