2 Reading packets using fixed and dynamic buffer
4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 /* This is similar to read_packet abstraction. The main different is that
21 * tevent fd event is created only once.
25 #include "system/network.h"
30 #include "lib/util/tevent_unix.h"
35 * Read a packet using fixed buffer
38 struct pkt_read_state {
44 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
48 struct tevent_req *pkt_read_send(TALLOC_CTX *mem_ctx,
49 struct tevent_context *ev,
50 int fd, size_t initial,
51 uint8_t *buf, size_t buflen,
52 ssize_t (*more)(uint8_t *buf,
57 struct tevent_req *req;
58 struct pkt_read_state *state;
60 req = tevent_req_create(mem_ctx, &state, struct pkt_read_state);
67 if (buf == NULL || buflen == 0) {
68 state->use_fixed = false;
69 state->buf = talloc_array(state, uint8_t, initial);
70 if (state->buf == NULL) {
74 state->buflen = initial;
76 state->use_fixed = true;
78 state->buflen = buflen;
82 state->total = initial;
85 state->private_data = private_data;
90 void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde,
91 uint16_t flags, struct tevent_req *req)
93 struct pkt_read_state *state = tevent_req_data(
94 req, struct pkt_read_state);
98 nread = read(state->fd, state->buf + state->nread,
99 state->total - state->nread);
100 if ((nread == -1) && (errno == EINTR)) {
105 tevent_req_error(req, errno);
110 tevent_req_error(req, EPIPE);
114 state->nread += nread;
115 if (state->nread < state->total) {
116 /* come back later */
120 /* Check if "more" asks for more data */
121 if (state->more == NULL) {
122 tevent_req_done(req);
126 more = state->more(state->buf, state->nread, state->private_data);
129 tevent_req_error(req, EIO);
133 tevent_req_done(req);
137 if (state->total + more < state->total) {
139 tevent_req_error(req, EMSGSIZE);
143 if (state->total + more < state->buflen) {
144 /* continue using fixed buffer */
145 state->total += more;
149 if (state->use_fixed) {
150 /* switch to dynamic buffer */
151 tmp = talloc_array(state, uint8_t, state->total + more);
152 if (tevent_req_nomem(tmp, req)) {
156 memcpy(tmp, state->buf, state->total);
157 state->use_fixed = false;
159 tmp = talloc_realloc(state, state->buf, uint8_t,
160 state->total + more);
161 if (tevent_req_nomem(tmp, req)) {
167 state->buflen = state->total + more;
168 state->total += more;
171 ssize_t pkt_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
172 uint8_t **pbuf, bool *free_buf, int *perrno)
174 struct pkt_read_state *state = tevent_req_data(
175 req, struct pkt_read_state);
177 if (tevent_req_is_unix_error(req, perrno)) {
181 if (state->use_fixed) {
185 *pbuf = talloc_steal(mem_ctx, state->buf);