build: fixed LOAD_ENVIRONMENT for out of tree builds
[kai/samba.git] / source3 / lib / util_tsock.c
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 "includes.h"
21
22 struct tstream_read_packet_state {
23         struct tevent_context *ev;
24         struct tstream_context *stream;
25         ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
26         void *private_data;
27         uint8_t *buf;
28         struct iovec iov;
29 };
30
31 static void tstream_read_packet_done(struct tevent_req *subreq);
32
33 struct tevent_req *tstream_read_packet_send(TALLOC_CTX *mem_ctx,
34                                             struct tevent_context *ev,
35                                             struct tstream_context *stream,
36                                             size_t initial,
37                                             ssize_t (*more)(uint8_t *buf,
38                                                             size_t buflen,
39                                                             void *private_data),
40                                             void *private_data)
41 {
42         struct tevent_req *req, *subreq;
43         struct tstream_read_packet_state *state;
44
45         req = tevent_req_create(mem_ctx, &state,
46                                 struct tstream_read_packet_state);
47         if (req == NULL) {
48                 return NULL;
49         }
50         state->buf = talloc_array(state, uint8_t, initial);
51         if (tevent_req_nomem(state->buf, req)) {
52                 return tevent_req_post(req, ev);
53         }
54         state->iov.iov_base = state->buf;
55         state->iov.iov_len = initial;
56
57         state->ev = ev;
58         state->stream = stream;
59         state->more = more;
60         state->private_data = private_data;
61
62         subreq = tstream_readv_send(state, ev, stream, &state->iov, 1);
63         if (tevent_req_nomem(subreq, req)) {
64                 return tevent_req_post(req, ev);
65         }
66         tevent_req_set_callback(subreq, tstream_read_packet_done, req);
67
68         return req;
69 }
70
71 static void tstream_read_packet_done(struct tevent_req *subreq)
72 {
73         struct tevent_req *req = tevent_req_callback_data(
74                 subreq, struct tevent_req);
75         struct tstream_read_packet_state *state = tevent_req_data(
76                 req, struct tstream_read_packet_state);
77         int ret, err;
78         size_t total;
79         ssize_t more;
80         uint8_t *tmp;
81
82         ret = tstream_readv_recv(subreq, &err);
83         TALLOC_FREE(subreq);
84         if (ret == 0) {
85                 err = EPIPE;
86         }
87         if (ret <= 0) {
88                 tevent_req_error(req, err);
89                 return;
90         }
91
92         if (state->more == NULL) {
93                 /* Nobody to ask, this is a async read_data */
94                 tevent_req_done(req);
95                 return;
96         }
97         total = talloc_array_length(state->buf);
98
99         more = state->more(state->buf, total, state->private_data);
100         if (more == -1) {
101                 /* We got an invalid packet, tell the caller */
102                 tevent_req_error(req, EIO);
103                 return;
104         }
105         if (more == 0) {
106                 /* We're done, full packet received */
107                 tevent_req_done(req);
108                 return;
109         }
110
111         tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
112         if (tevent_req_nomem(tmp, req)) {
113                 return;
114         }
115         state->buf = tmp;
116
117         state->iov.iov_base = state->buf + total;
118         state->iov.iov_len = more;
119
120         subreq = tstream_readv_send(state, state->ev, state->stream,
121                                     &state->iov, 1);
122         if (tevent_req_nomem(subreq, req)) {
123                 return;
124         }
125         tevent_req_set_callback(subreq, tstream_read_packet_done, req);
126 }
127
128 ssize_t tstream_read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
129                                  uint8_t **pbuf, int *perrno)
130 {
131         struct tstream_read_packet_state *state =
132                 tevent_req_data(req, struct tstream_read_packet_state);
133
134         if (tevent_req_is_unix_error(req, perrno)) {
135                 return -1;
136         }
137         *pbuf = talloc_move(mem_ctx, &state->buf);
138         return talloc_array_length(*pbuf);
139 }