ngx_wsarecv_chain.c revision e18a033b
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11
12
13#define NGX_WSABUFS  8
14
15
16ssize_t
17ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
18{
19    int           rc;
20    u_char       *prev;
21    u_long        bytes, flags;
22    size_t        n, size;
23    ngx_err_t     err;
24    ngx_array_t   vec;
25    ngx_event_t  *rev;
26    LPWSABUF      wsabuf;
27    WSABUF        wsabufs[NGX_WSABUFS];
28
29    prev = NULL;
30    wsabuf = NULL;
31    flags = 0;
32    size = 0;
33    bytes = 0;
34
35    vec.elts = wsabufs;
36    vec.nelts = 0;
37    vec.size = sizeof(WSABUF);
38    vec.nalloc = NGX_WSABUFS;
39    vec.pool = c->pool;
40
41    /* coalesce the neighbouring bufs */
42
43    while (chain) {
44        n = chain->buf->end - chain->buf->last;
45
46        if (limit) {
47            if (size >= (size_t) limit) {
48                break;
49            }
50
51            if (size + n > (size_t) limit) {
52                n = (size_t) limit - size;
53            }
54        }
55
56        if (prev == chain->buf->last) {
57            wsabuf->len += n;
58
59        } else {
60            wsabuf = ngx_array_push(&vec);
61            if (wsabuf == NULL) {
62                return NGX_ERROR;
63            }
64
65            wsabuf->buf = (char *) chain->buf->last;
66            wsabuf->len = n;
67        }
68
69        size += n;
70        prev = chain->buf->end;
71        chain = chain->next;
72    }
73
74    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
75                   "WSARecv: %d:%d", vec.nelts, wsabuf->len);
76
77
78    rc = WSARecv(c->fd, vec.elts, vec.nelts, &bytes, &flags, NULL, NULL);
79
80    rev = c->read;
81
82    if (rc == -1) {
83        rev->ready = 0;
84        err = ngx_socket_errno;
85
86        if (err == WSAEWOULDBLOCK) {
87            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
88                           "WSARecv() not ready");
89            return NGX_AGAIN;
90        }
91
92        rev->error = 1;
93        ngx_connection_error(c, err, "WSARecv() failed");
94        return NGX_ERROR;
95    }
96
97    if (bytes < size) {
98        rev->ready = 0;
99    }
100
101    if (bytes == 0) {
102        rev->eof = 1;
103    }
104
105    return bytes;
106}
107