Home | History | Annotate | Download | only in libcutils
      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