terom@1: terom@1: #include "sock_tcp.h" terom@1: terom@1: #include terom@1: #include terom@1: #include terom@1: #include terom@1: #include terom@1: #include terom@3: #include terom@1: terom@1: /* terom@3: * Our sock_stream_methods.read method terom@1: */ terom@3: static err_t sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len) terom@1: { terom@1: struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); terom@3: int ret; terom@3: terom@3: // map directly to read(2) terom@3: if ((ret = read(sock->fd, buf, len)) < 0) terom@3: // errno terom@3: RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_READ); terom@1: terom@3: else terom@3: // bytes read terom@3: return ret; terom@1: } terom@1: terom@1: /* terom@3: * Our sock_stream_methods.write method terom@1: */ terom@3: static err_t sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len) terom@1: { terom@1: struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); terom@3: int ret; terom@3: terom@3: // map directly to write(2) terom@3: if ((ret = write(sock->fd, buf, len)) < 0) terom@3: // errno terom@3: RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_WRITE); terom@1: terom@3: else terom@3: // bytes read terom@3: return ret; terom@1: } terom@1: terom@1: /* terom@2: * Our sock_stream_type terom@1: */ terom@1: struct sock_stream_type sock_tcp_type = { terom@1: .methods.read = &sock_tcp_read, terom@1: .methods.write = &sock_tcp_write, terom@1: }; terom@1: terom@3: err_t sock_tcp_alloc (struct sock_tcp **sock_ptr) terom@1: { terom@1: // alloc terom@3: if ((*sock_ptr = calloc(1, sizeof(**sock_ptr))) == NULL) terom@3: return ERR_CALLOC; terom@2: terom@3: // initialize base with sock_tcp_type terom@3: sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type); terom@1: terom@2: // done terom@3: return SUCCESS; terom@2: } terom@2: terom@3: err_t sock_tcp_init_fd (struct sock_tcp *sock, int fd) terom@2: { terom@3: // valid fd -XXX: err instead? terom@3: assert(fd >= 0); terom@3: terom@1: // initialize terom@1: sock->fd = fd; terom@1: terom@1: // done terom@3: return SUCCESS; terom@1: } terom@1: terom@3: err_t sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service) terom@1: { terom@1: struct addrinfo hints, *res, *r; terom@3: int err; terom@3: RESET_ERROR(SOCK_TCP_ERR(sock)); terom@1: terom@1: // hints terom@1: memset(&hints, 0, sizeof(hints)); terom@1: hints.ai_family = AF_UNSPEC; terom@1: hints.ai_socktype = SOCK_STREAM; terom@1: terom@1: // resolve terom@3: if ((err = getaddrinfo(hostname, service, &hints, &res))) terom@3: RETURN_SET_ERROR_EXTRA(SOCK_TCP_ERR(sock), ERR_GETADDRINFO, err); terom@1: terom@3: // try each result in turn terom@1: for (r = res; r; r = r->ai_next) { terom@3: // create the socket terom@3: if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) { terom@3: // remember error terom@3: SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_SOCKET); terom@1: terom@3: // skip to next one terom@3: continue; terom@3: } terom@3: terom@3: // connect to remote address terom@3: if (connect(sock->fd, r->ai_addr, r->ai_addrlen)) { terom@3: // remember error terom@3: SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_CONNECT); terom@3: terom@3: // close/invalidate socket terom@3: close(sock->fd); terom@3: sock->fd = -1; terom@1: terom@3: // skip to next one terom@3: continue; terom@3: } terom@3: terom@3: // valid socket, use this terom@1: break; terom@1: } terom@1: terom@3: // ensure we got some valid socket, else return last error code terom@3: if (sock->fd < 0) { terom@3: // did we hit some error? terom@3: if (IS_ERROR(SOCK_TCP_ERR(sock))) terom@3: // return last error terom@3: return ERROR_CODE(SOCK_TCP_ERR(sock)); terom@3: terom@3: else terom@3: // no results terom@3: return SET_ERROR(SOCK_TCP_ERR(sock), ERR_GETADDRINFO_EMPTY); terom@3: } terom@1: terom@2: // ok, done terom@2: return 0; terom@1: } terom@1: terom@3: err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err_info) terom@2: { terom@2: struct sock_tcp *sock; terom@3: err_t err; terom@2: terom@2: // allocate terom@3: if ((err = sock_tcp_alloc(&sock))) terom@3: return err; terom@2: terom@2: // connect terom@3: if ((err = sock_tcp_init_connect(sock, host, service))) { terom@8: // copy error_info terom@8: SET_ERROR_INFO(err_info, sock_stream_error(SOCK_TCP_BASE(sock))); terom@2: terom@3: // cleanup terom@3: sock_tcp_release(sock); terom@3: terom@3: // return error code terom@3: return err; terom@3: } terom@3: terom@3: // good terom@3: *sock_ptr = SOCK_TCP_BASE(sock); terom@3: terom@3: return 0; terom@2: } terom@3: terom@3: void sock_tcp_release (struct sock_tcp *sock) terom@3: { terom@3: // must not be connected terom@3: assert(sock->fd < 0); terom@3: terom@3: // free terom@3: free(sock); terom@3: }