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 */ 36 int 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 */ 44 int socket_network_client_timeout(const char *host, int port, int type, int timeout) 45 { 46 struct hostent *hp; 47 struct sockaddr_in addr; 48 socklen_t alen; 49 int s; 50 int flags = 0, error = 0, ret = 0; 51 fd_set rset, wset; 52 socklen_t len = sizeof(error); 53 struct timeval ts; 54 55 ts.tv_sec = timeout; 56 ts.tv_usec = 0; 57 58 hp = gethostbyname(host); 59 if (hp == 0) return -1; 60 61 memset(&addr, 0, sizeof(addr)); 62 addr.sin_family = hp->h_addrtype; 63 addr.sin_port = htons(port); 64 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); 65 66 s = socket(hp->h_addrtype, type, 0); 67 if (s < 0) return -1; 68 69 if ((flags = fcntl(s, F_GETFL, 0)) < 0) { 70 close(s); 71 return -1; 72 } 73 74 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { 75 close(s); 76 return -1; 77 } 78 79 if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { 80 if (errno != EINPROGRESS) { 81 close(s); 82 return -1; 83 } 84 } 85 86 if (ret == 0) 87 goto done; 88 89 FD_ZERO(&rset); 90 FD_SET(s, &rset); 91 wset = rset; 92 93 if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) { 94 close(s); 95 return -1; 96 } 97 if (ret == 0) { // we had a timeout 98 errno = ETIMEDOUT; 99 close(s); 100 return -1; 101 } 102 103 if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) { 104 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 105 close(s); 106 return -1; 107 } 108 } else { 109 close(s); 110 return -1; 111 } 112 113 if (error) { // check if we had a socket error 114 errno = error; 115 close(s); 116 return -1; 117 } 118 119 done: 120 if (fcntl(s, F_SETFL, flags) < 0) { 121 close(s); 122 return -1; 123 } 124 125 return s; 126 } 127