• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
socket_network_client(const char * host,int port,int type)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  */
socket_network_client_timeout(const char * host,int port,int type,int timeout)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     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 
118 done:
119     if (fcntl(s, F_SETFL, flags) < 0) {
120         close(s);
121         return -1;
122     }
123 
124     return s;
125 }
126