Пример #1
0
/* This is like socket_buffer_read, except that it blocks until it can read all
   size bytes. If fewer than size bytes are available, it reads them and returns
   -1. */
int socket_buffer_readcount(struct socket_buffer *buf, char *out, size_t size)
{
    size_t n = 0;
    int i;

    while (n < size) {
        /* Refill the buffer if necessary. */
        if (buf->p >= buf->end) {
            buf->p = buf->buffer;
            do {
                errno = 0;
                i = fdinfo_recv(&buf->fdn, buf->buffer, sizeof(buf->buffer));
            } while (i == -1 && errno == EINTR);
            if (i <= 0)
                return -1;
            buf->end = buf->buffer + i;
        }
        i = buf->end - buf->p;
        if (i < size - n) {
            memcpy(out + n, buf->p, i);
            buf->p += i;
            n += i;
        } else {
            memcpy(out + n, buf->p, size - n);
            buf->p += size - n;
            n += size - n;
        }
    }

    return n;
}
Пример #2
0
/* Read a line thorough a stateful socket buffer. The line, including its '\n',
   is returned in a dynamically allocated buffer. The length of the line is
   returned in *n. If the length of the line exceeds maxlen, then NULL is
   returned and *n is greater than or equal to maxlen. On error, NULL is
   returned and *n is less than maxlen. The returned buffer is always
   null-terminated if the return value is not NULL. */
char *socket_buffer_readline(struct socket_buffer *buf, size_t *n, size_t maxlen)
{
    char *line;
    char *newline;
    size_t count;

    line = NULL;
    *n = 0;

    do {
        /* Refill the buffer if necessary. */
        if (buf->p >= buf->end) {
            int i;

            buf->p = buf->buffer;
            do {
                errno = 0;
                i = fdinfo_recv(&buf->fdn, buf->buffer, sizeof(buf->buffer));
            } while (i == -1 && errno == EINTR);
            if (i <= 0) {
                free(line);
                return NULL;
            }
            buf->end = buf->buffer + i;
        }

        newline = (char *) memchr(buf->p, '\n', buf->end - buf->p);
        if (newline == NULL)
            count = buf->end - buf->p;
        else
            count = newline + 1 - buf->p;

        if (*n + count >= maxlen) {
            /* Line exceeds our maximum length. */
            free(line);
            *n += count;
            return NULL;
        }

        line = (char *) safe_realloc(line, *n + count + 1);
        memcpy(line + *n, buf->p, count);
        *n += count;
        buf->p += count;
    } while (newline == NULL);

    line[*n] = '\0';

    return line;
}
Пример #3
0
/* Read from a stateful socket buffer. If there is any data in the buffer it is
   returned, otherwise data is read with recv. Return value is as for recv. */
int socket_buffer_read(struct socket_buffer *buf, char *out, size_t size)
{
    int i;

    /* Refill the buffer if necessary. */
    if (buf->p >= buf->end) {
        buf->p = buf->buffer;
        do {
            errno = 0;
            i = fdinfo_recv(&buf->fdn, buf->buffer, sizeof(buf->buffer));
        } while (i == -1 && errno == EINTR);
        if (i <= 0)
            return i;
        buf->end = buf->buffer + i;
    }
    i = buf->end - buf->p;
    if (i > size)
        i = size;
    memcpy(out, buf->p, i);
    buf->p += i;

    return i;
}
Пример #4
0
/* Read from a client socket into buf, returning the number of bytes read, or -1
   on an error. This takes care of delays, Telnet negotiation, and logging.

   If there is more data pending that won't be noticed by select, a 1 is stored
   in *pending, otherwise 0 is stored there. The caller must loop, processing
   read data until *pending is false. The reason for this is the SSL_read
   function that this function may call, which takes data out of the socket
   buffer (so select may not indicate the socket is readable) and keeps it in
   its own buffer. *pending holds the result of calling SSL_pending. See
   http://www.mail-archive.com/[email protected]/msg24324.html. */
int ncat_recv(struct fdinfo *fdn, char *buf, size_t size, int *pending)
{
    int n;

    *pending = 0;

    n = fdinfo_recv(fdn, buf, size);

    if (n <= 0)
        return n;

    if (o.linedelay)
        ncat_delay_timer(o.linedelay);
    if (o.telnet)
        dotelnet(fdn->fd, (unsigned char *) buf, n);
    ncat_log_recv(buf, n);

    /* SSL can buffer our input, so doing another select() won't necessarily
       work for us. Indicate to the caller that this function must be called
       again to get more data. */
    *pending = fdinfo_pending(fdn);

    return n;
}
Пример #5
0
static int handle_connect(struct socket_buffer *client_sock,
    struct http_request *request)
{
    union sockaddr_u su;
    size_t sslen = sizeof(su.storage);
    int maxfd, s, rc;
    char *line;
    size_t len;
    fd_set m, r;

    if (request->uri.port == -1) {
        if (o.verbose)
            logdebug("No port number in CONNECT URI.\n");
        return 400;
    }
    if (o.debug > 1)
        logdebug("CONNECT to %s:%hu.\n", request->uri.host, request->uri.port);

    rc = resolve(request->uri.host, request->uri.port, &su.storage, &sslen, o.af);
    if (rc != 0) {
        if (o.debug) {
            logdebug("Can't resolve name \"%s\": %s.\n",
                request->uri.host, gai_strerror(rc));
        }
        return 504;
    }

    s = Socket(su.storage.ss_family, SOCK_STREAM, IPPROTO_TCP);

    if (connect(s, &su.sockaddr, sslen) == -1) {
        if (o.debug)
            logdebug("Can't connect to %s.\n", inet_socktop(&su));
        Close(s);
        return 504;
    }

    send_string(&client_sock->fdn, http_code2str(200));

    /* Clear out whatever is left in the socket buffer. The client may have
       already sent the first part of its request to the origin server. */
    line = socket_buffer_remainder(client_sock, &len);
    if (send(s, line, len, 0) < 0) {
        if (o.debug)
            logdebug("Error sending %lu leftover bytes: %s.\n", (unsigned long) len, strerror(errno));
        Close(s);
        return 0;
    }

    maxfd = client_sock->fdn.fd < s ? s : client_sock->fdn.fd;
    FD_ZERO(&m);
    FD_SET(client_sock->fdn.fd, &m);
    FD_SET(s, &m);

    errno = 0;

    while (!socket_errno() || socket_errno() == EINTR) {
        char buf[DEFAULT_TCP_BUF_LEN];
        int len, rc;

        r = m;

        fselect(maxfd + 1, &r, NULL, NULL, NULL);

        zmem(buf, sizeof(buf));

        if (FD_ISSET(client_sock->fdn.fd, &r)) {
            do {
                do {
                    len = fdinfo_recv(&client_sock->fdn, buf, sizeof(buf));
                } while (len == -1 && socket_errno() == EINTR);
                if (len <= 0)
                    goto end;

                do {
                    rc = send(s, buf, len, 0);
                } while (rc == -1 && socket_errno() == EINTR);
                if (rc == -1)
                    goto end;
            } while (fdinfo_pending(&client_sock->fdn));
        }

        if (FD_ISSET(s, &r)) {
            do {
                len = recv(s, buf, sizeof(buf), 0);
            } while (len == -1 && socket_errno() == EINTR);
            if (len <= 0)
                goto end;

            do {
                rc = fdinfo_send(&client_sock->fdn, buf, len);
            } while (rc == -1 && socket_errno() == EINTR);
            if (rc == -1)
                goto end;
        }
    }
end:

    close(s);

    return 0;
}