src/sock_tcp.c
changeset 3 cc94ae754e2a
parent 2 a834f0559939
child 4 a3ca0f97a075
equal deleted inserted replaced
2:a834f0559939 3:cc94ae754e2a
     5 #include <sys/types.h>
     5 #include <sys/types.h>
     6 #include <sys/socket.h>
     6 #include <sys/socket.h>
     7 #include <netdb.h>
     7 #include <netdb.h>
     8 #include <unistd.h>
     8 #include <unistd.h>
     9 #include <string.h>
     9 #include <string.h>
    10 #include <err.h>
    10 #include <assert.h>
    11 
    11 
    12 /*
    12 /*
    13  * Our sock_stream_type.methods.read implementation
    13  * Our sock_stream_methods.read method
    14  */
    14  */
    15 static int sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len)
    15 static err_t sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len)
    16 {
    16 {
    17     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
    17     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
       
    18     int ret;
       
    19     
       
    20     // map directly to read(2)
       
    21     if ((ret = read(sock->fd, buf, len)) < 0)
       
    22         // errno
       
    23         RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_READ);
    18 
    24 
    19     return read(sock->fd, buf, len);
    25     else 
       
    26         // bytes read
       
    27         return ret;
    20 }
    28 }
    21 
    29 
    22 /*
    30 /*
    23  * Our sock_stream_type.methods.write implementation
    31  * Our sock_stream_methods.write method
    24  */
    32  */
    25 static int sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len)
    33 static err_t sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len)
    26 {
    34 {
    27     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
    35     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
       
    36     int ret;
       
    37     
       
    38     // map directly to write(2)
       
    39     if ((ret = write(sock->fd, buf, len)) < 0)
       
    40         // errno
       
    41         RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_WRITE);
    28 
    42 
    29     return write(sock->fd, buf, len);
    43     else
       
    44         // bytes read
       
    45         return ret;
    30 }
    46 }
    31 
    47 
    32 /*
    48 /*
    33  * Our sock_stream_type
    49  * Our sock_stream_type
    34  *
       
    35  * XXX: move to sock_tcp.h
       
    36  */
    50  */
    37 struct sock_stream_type sock_tcp_type = {
    51 struct sock_stream_type sock_tcp_type = {
    38     .methods.read   = &sock_tcp_read,
    52     .methods.read   = &sock_tcp_read,
    39     .methods.write  = &sock_tcp_write,
    53     .methods.write  = &sock_tcp_write,
    40 };
    54 };
    41 
    55 
    42 struct sock_tcp* sock_tcp_alloc (void)
    56 err_t sock_tcp_alloc (struct sock_tcp **sock_ptr)
    43 {
    57 {
    44     struct sock_tcp *sock;
       
    45 
       
    46     // alloc
    58     // alloc
    47     if ((sock = calloc(1, sizeof(*sock))) == NULL)
    59     if ((*sock_ptr = calloc(1, sizeof(**sock_ptr))) == NULL)
    48         errx(1, "calloc");
    60         return ERR_CALLOC;
    49     
    61     
    50     // initialize base
    62     // initialize base with sock_tcp_type
    51     sock->base.type = &sock_tcp_type;
    63     sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type);
    52 
    64 
    53     // done
    65     // done
    54     return sock;
    66     return SUCCESS;
    55 }
    67 }
    56 
    68 
    57 int sock_tcp_init_fd (struct sock_tcp *sock, int fd)
    69 err_t sock_tcp_init_fd (struct sock_tcp *sock, int fd)
    58 {
    70 {
       
    71     // valid fd -XXX: err instead?
       
    72     assert(fd >= 0);
       
    73 
    59     // initialize
    74     // initialize
    60     sock->fd = fd;
    75     sock->fd = fd;
    61 
    76 
    62     // done
    77     // done
    63     return 0;
    78     return SUCCESS;
    64 }
    79 }
    65 
    80 
    66 int sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service)
    81 err_t sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service)
    67 {
    82 {
    68     struct addrinfo hints, *res, *r;
    83     struct addrinfo hints, *res, *r;
    69     int _err;
    84     int err;
       
    85     RESET_ERROR(SOCK_TCP_ERR(sock));
    70     
    86     
    71     // hints
    87     // hints
    72     memset(&hints, 0, sizeof(hints));
    88     memset(&hints, 0, sizeof(hints));
    73     hints.ai_family = AF_UNSPEC;
    89     hints.ai_family = AF_UNSPEC;
    74     hints.ai_socktype = SOCK_STREAM;
    90     hints.ai_socktype = SOCK_STREAM;
    75 
    91 
    76     // resolve
    92     // resolve
    77     if ((_err = getaddrinfo(hostname, service, &hints, &res)))
    93     if ((err = getaddrinfo(hostname, service, &hints, &res)))
    78         errx(1, "getaddrinfo: %s", gai_strerror(_err));
    94         RETURN_SET_ERROR_EXTRA(SOCK_TCP_ERR(sock), ERR_GETADDRINFO, err);
    79 
    95 
    80     // use
    96     // try each result in turn
    81     for (r = res; r; r = r->ai_next) {
    97     for (r = res; r; r = r->ai_next) {
    82         // XXX: wrong
    98         // create the socket
    83         if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0)
    99         if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) {
    84             err(1, "socket");
   100             // remember error
       
   101             SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_SOCKET);
    85 
   102 
    86         if (connect(sock->fd, r->ai_addr, r->ai_addrlen))
   103             // skip to next one
    87             err(1, "connect");
   104             continue;
       
   105         }
       
   106         
       
   107         // connect to remote address
       
   108         if (connect(sock->fd, r->ai_addr, r->ai_addrlen)) {
       
   109             // remember error
       
   110             SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_CONNECT);
       
   111             
       
   112             // close/invalidate socket
       
   113             close(sock->fd);
       
   114             sock->fd = -1;
    88 
   115 
       
   116             // skip to next one
       
   117             continue;
       
   118         }
       
   119         
       
   120         // valid socket, use this
    89         break;
   121         break;
    90     }
   122     }
    91     
   123     
    92     // ensure we got some valid socket
   124     // ensure we got some valid socket, else return last error code
    93     if (sock->fd < 0)
   125     if (sock->fd < 0) {
    94         errx(1, "no valid socket");
   126         // did we hit some error?
       
   127         if (IS_ERROR(SOCK_TCP_ERR(sock)))
       
   128             // return last error
       
   129             return ERROR_CODE(SOCK_TCP_ERR(sock));
       
   130         
       
   131         else
       
   132             // no results
       
   133             return SET_ERROR(SOCK_TCP_ERR(sock), ERR_GETADDRINFO_EMPTY);
       
   134     }
    95     
   135     
    96     // ok, done
   136     // ok, done
    97     return 0;    
   137     return 0;    
    98 }
   138 }
    99 
   139 
   100 // XXX: error handling
   140 err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err_info)
   101 struct sock_stream* sock_tcp_connect (const char *host, const char *service) 
       
   102 {
   141 {
   103     struct sock_tcp *sock;
   142     struct sock_tcp *sock;
       
   143     err_t err;
   104     
   144     
   105     // allocate
   145     // allocate
   106     sock = sock_tcp_alloc();
   146     if ((err = sock_tcp_alloc(&sock)))
       
   147         return err;
   107 
   148 
   108     // connect
   149     // connect
   109     sock_tcp_init_connect(sock, host, service);
   150     if ((err = sock_tcp_init_connect(sock, host, service))) {
       
   151         // set *err_info
       
   152         *err_info = SOCK_TCP_ERR(sock);
   110 
   153 
   111     // done
   154         // cleanup
   112     return SOCK_TCP_BASE(sock);
   155         sock_tcp_release(sock);
       
   156         
       
   157         // return error code
       
   158         return err;
       
   159     }
       
   160 
       
   161     // good
       
   162     *sock_ptr = SOCK_TCP_BASE(sock);
       
   163 
       
   164     return 0;
   113 }
   165 }
       
   166 
       
   167 void sock_tcp_release (struct sock_tcp *sock)
       
   168 {
       
   169     // must not be connected
       
   170     assert(sock->fd < 0);
       
   171 
       
   172     // free
       
   173     free(sock);
       
   174 }