s4:torture: FinderInfo conversion test with AppleDouble without xattr data
[Samba.git] / ctdb / common / pkt_read.c
blob212ace54bbd824450a7fd9f05ee78dc150ae758d
1 /*
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.
24 #include "replace.h"
25 #include "system/network.h"
27 #include <talloc.h>
28 #include <tevent.h>
30 #include "lib/util/tevent_unix.h"
32 #include "pkt_read.h"
35 * Read a packet using fixed buffer
38 struct pkt_read_state {
39 int fd;
40 uint8_t *buf;
41 size_t buflen;
42 size_t nread, total;
43 bool use_fixed;
44 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
45 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,
53 size_t buflen,
54 void *private_data),
55 void *private_data)
57 struct tevent_req *req;
58 struct pkt_read_state *state;
60 req = tevent_req_create(mem_ctx, &state, struct pkt_read_state);
61 if (req == NULL) {
62 return NULL;
65 state->fd = fd;
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) {
71 talloc_free(req);
72 return NULL;
74 state->buflen = initial;
75 } else {
76 state->use_fixed = true;
77 state->buf = buf;
78 state->buflen = buflen;
81 state->nread = 0;
82 state->total = initial;
84 state->more = more;
85 state->private_data = private_data;
87 return req;
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);
95 ssize_t nread, more;
96 uint8_t *tmp;
98 nread = read(state->fd, state->buf + state->nread,
99 state->total - state->nread);
100 if ((nread == -1) && (errno == EINTR)) {
101 /* retry */
102 return;
104 if (nread == -1) {
105 tevent_req_error(req, errno);
106 return;
108 if (nread == 0) {
109 /* fd closed */
110 tevent_req_error(req, EPIPE);
111 return;
114 state->nread += nread;
115 if (state->nread < state->total) {
116 /* come back later */
117 return;
120 /* Check if "more" asks for more data */
121 if (state->more == NULL) {
122 tevent_req_done(req);
123 return;
126 more = state->more(state->buf, state->nread, state->private_data);
127 if (more == -1) {
128 /* invalid packet */
129 tevent_req_error(req, EIO);
130 return;
132 if (more == 0) {
133 tevent_req_done(req);
134 return;
137 if (state->total + more < state->total) {
138 /* int wrapped */
139 tevent_req_error(req, EMSGSIZE);
140 return;
143 if (state->total + more < state->buflen) {
144 /* continue using fixed buffer */
145 state->total += more;
146 return;
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)) {
153 return;
156 memcpy(tmp, state->buf, state->total);
157 state->use_fixed = false;
158 } else {
159 tmp = talloc_realloc(state, state->buf, uint8_t,
160 state->total + more);
161 if (tevent_req_nomem(tmp, req)) {
162 return;
166 state->buf = tmp;
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)) {
178 return -1;
181 if (state->use_fixed) {
182 *pbuf = state->buf;
183 *free_buf = false;
184 } else {
185 *pbuf = talloc_steal(mem_ctx, state->buf);
186 *free_buf = true;
189 return state->total;