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
);