src/sock_tcp.c
author Tero Marttila <terom@fixme.fi>
Sun, 22 Feb 2009 05:27:29 +0200
changeset 2 a834f0559939
parent 1 cf0e1bb6bcab
child 3 cc94ae754e2a
permissions -rw-r--r--
working SSL using gnutls - a bit of a painful process

#include "sock_tcp.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <err.h>

/*
 * Our sock_stream_type.methods.read implementation
 */
static int sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len)
{
    struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);

    return read(sock->fd, buf, len);
}

/*
 * Our sock_stream_type.methods.write implementation
 */
static int sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len)
{
    struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);

    return write(sock->fd, buf, len);
}

/*
 * Our sock_stream_type
 *
 * XXX: move to sock_tcp.h
 */
struct sock_stream_type sock_tcp_type = {
    .methods.read   = &sock_tcp_read,
    .methods.write  = &sock_tcp_write,
};

struct sock_tcp* sock_tcp_alloc (void)
{
    struct sock_tcp *sock;

    // alloc
    if ((sock = calloc(1, sizeof(*sock))) == NULL)
        errx(1, "calloc");
    
    // initialize base
    sock->base.type = &sock_tcp_type;

    // done
    return sock;
}

int sock_tcp_init_fd (struct sock_tcp *sock, int fd)
{
    // initialize
    sock->fd = fd;

    // done
    return 0;
}

int sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service)
{
    struct addrinfo hints, *res, *r;
    int _err;
    
    // hints
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    // resolve
    if ((_err = getaddrinfo(hostname, service, &hints, &res)))
        errx(1, "getaddrinfo: %s", gai_strerror(_err));

    // use
    for (r = res; r; r = r->ai_next) {
        // XXX: wrong
        if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0)
            err(1, "socket");

        if (connect(sock->fd, r->ai_addr, r->ai_addrlen))
            err(1, "connect");

        break;
    }
    
    // ensure we got some valid socket
    if (sock->fd < 0)
        errx(1, "no valid socket");
    
    // ok, done
    return 0;    
}

// XXX: error handling
struct sock_stream* sock_tcp_connect (const char *host, const char *service) 
{
    struct sock_tcp *sock;
    
    // allocate
    sock = sock_tcp_alloc();

    // connect
    sock_tcp_init_connect(sock, host, service);

    // done
    return SOCK_TCP_BASE(sock);
}