socket_network_client.c revision 0bff5bd95268184a34ae69c062584a8d1f4d87fb
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    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
119done:
120    if (fcntl(s, F_SETFL, flags) < 0) {
121        close(s);
122        return -1;
123    }
124
125    return s;
126}
127