Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Utilities around tsocket
4 : Copyright (C) Volker Lendecke 2009
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : #include "replace.h"
21 : #include "system/network.h"
22 : #include <tevent.h>
23 : #include "lib/util_tsock.h"
24 : #include "../lib/tsocket/tsocket.h"
25 : #include "../lib/util/tevent_unix.h"
26 :
27 : struct tstream_read_packet_state {
28 : struct tevent_context *ev;
29 : struct tstream_context *stream;
30 : ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
31 : void *private_data;
32 : uint8_t *buf;
33 : struct iovec iov;
34 : };
35 :
36 : static void tstream_read_packet_done(struct tevent_req *subreq);
37 :
38 5302 : struct tevent_req *tstream_read_packet_send(TALLOC_CTX *mem_ctx,
39 : struct tevent_context *ev,
40 : struct tstream_context *stream,
41 : size_t initial,
42 : ssize_t (*more)(uint8_t *buf,
43 : size_t buflen,
44 : void *private_data),
45 : void *private_data)
46 : {
47 0 : struct tevent_req *req, *subreq;
48 0 : struct tstream_read_packet_state *state;
49 :
50 5302 : req = tevent_req_create(mem_ctx, &state,
51 : struct tstream_read_packet_state);
52 5302 : if (req == NULL) {
53 0 : return NULL;
54 : }
55 5302 : state->buf = talloc_array(state, uint8_t, initial);
56 5302 : if (tevent_req_nomem(state->buf, req)) {
57 0 : return tevent_req_post(req, ev);
58 : }
59 5302 : state->iov.iov_base = (void *)state->buf;
60 5302 : state->iov.iov_len = initial;
61 :
62 5302 : state->ev = ev;
63 5302 : state->stream = stream;
64 5302 : state->more = more;
65 5302 : state->private_data = private_data;
66 :
67 5302 : subreq = tstream_readv_send(state, ev, stream, &state->iov, 1);
68 5302 : if (tevent_req_nomem(subreq, req)) {
69 0 : return tevent_req_post(req, ev);
70 : }
71 5302 : tevent_req_set_callback(subreq, tstream_read_packet_done, req);
72 :
73 5302 : return req;
74 : }
75 :
76 6041 : static void tstream_read_packet_done(struct tevent_req *subreq)
77 : {
78 6041 : struct tevent_req *req = tevent_req_callback_data(
79 : subreq, struct tevent_req);
80 6041 : struct tstream_read_packet_state *state = tevent_req_data(
81 : req, struct tstream_read_packet_state);
82 0 : int ret, err;
83 0 : size_t total;
84 0 : ssize_t more;
85 0 : uint8_t *tmp;
86 :
87 6041 : ret = tstream_readv_recv(subreq, &err);
88 6041 : TALLOC_FREE(subreq);
89 6041 : if (ret == 0) {
90 0 : err = EPIPE;
91 : }
92 6041 : if (ret <= 0) {
93 1967 : tevent_req_error(req, err);
94 4922 : return;
95 : }
96 :
97 4074 : if (state->more == NULL) {
98 : /* Nobody to ask, this is a async read_data */
99 385 : tevent_req_done(req);
100 385 : return;
101 : }
102 3689 : total = talloc_array_length(state->buf);
103 :
104 3689 : more = state->more(state->buf, total, state->private_data);
105 3689 : if (more == -1) {
106 : /* We got an invalid packet, tell the caller */
107 0 : tevent_req_error(req, EIO);
108 0 : return;
109 : }
110 3689 : if (more == 0) {
111 : /* We're done, full packet received */
112 2570 : tevent_req_done(req);
113 2570 : return;
114 : }
115 :
116 1119 : if (total + more < total) {
117 0 : tevent_req_error(req, EMSGSIZE);
118 0 : return;
119 : }
120 :
121 1119 : tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
122 1119 : if (tevent_req_nomem(tmp, req)) {
123 0 : return;
124 : }
125 1119 : state->buf = tmp;
126 :
127 1119 : state->iov.iov_base = (void *)(state->buf + total);
128 1119 : state->iov.iov_len = more;
129 :
130 1119 : subreq = tstream_readv_send(state, state->ev, state->stream,
131 : &state->iov, 1);
132 1119 : if (tevent_req_nomem(subreq, req)) {
133 0 : return;
134 : }
135 1119 : tevent_req_set_callback(subreq, tstream_read_packet_done, req);
136 : }
137 :
138 4922 : ssize_t tstream_read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
139 : uint8_t **pbuf, int *perrno)
140 : {
141 0 : struct tstream_read_packet_state *state =
142 4922 : tevent_req_data(req, struct tstream_read_packet_state);
143 :
144 4922 : if (tevent_req_is_unix_error(req, perrno)) {
145 1967 : return -1;
146 : }
147 2955 : *pbuf = talloc_move(mem_ctx, &state->buf);
148 2955 : return talloc_array_length(*pbuf);
149 : }
|