2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2007
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/>.
21 #include "../lib/util/select.h"
22 #include "system/filesys.h"
23 #include "ctdb_packet.h"
25 struct ctdb_packet_context
{
31 * Close the underlying fd
33 static int ctdb_packet_context_destructor(struct ctdb_packet_context
*ctx
)
35 return close(ctx
->fd
);
39 * Initialize a ctdb_packet context. The fd is given to the ctdb_packet context, meaning
40 * that it is automatically closed when the ctdb_packet context is freed.
42 struct ctdb_packet_context
*ctdb_packet_init(TALLOC_CTX
*mem_ctx
, int fd
)
44 struct ctdb_packet_context
*result
;
46 if (!(result
= talloc_zero(mem_ctx
, struct ctdb_packet_context
))) {
51 talloc_set_destructor(result
, ctdb_packet_context_destructor
);
56 * Pull data from the fd
58 NTSTATUS
ctdb_packet_fd_read(struct ctdb_packet_context
*ctx
)
64 res
= ioctl(ctx
->fd
, FIONREAD
, &available
);
67 DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", strerror(errno
)));
68 return map_nt_error_from_unix(errno
);
71 SMB_ASSERT(available
>= 0);
74 return NT_STATUS_END_OF_FILE
;
77 new_size
= ctx
->in
.length
+ available
;
79 if (new_size
< ctx
->in
.length
) {
80 DEBUG(0, ("integer wrap\n"));
81 return NT_STATUS_NO_MEMORY
;
84 if (!(in
= talloc_realloc(ctx
, ctx
->in
.data
, uint8
, new_size
))) {
85 DEBUG(10, ("talloc failed\n"));
86 return NT_STATUS_NO_MEMORY
;
91 res
= recv(ctx
->fd
, in
+ ctx
->in
.length
, available
, 0);
94 DEBUG(10, ("recv failed: %s\n", strerror(errno
)));
95 return map_nt_error_from_unix(errno
);
99 return NT_STATUS_END_OF_FILE
;
102 ctx
->in
.length
+= res
;
107 NTSTATUS
ctdb_packet_fd_read_sync_timeout(struct ctdb_packet_context
*ctx
, int timeout
)
111 res
= poll_one_fd(ctx
->fd
, POLLIN
|POLLHUP
, timeout
, &revents
);
113 DEBUG(10, ("poll timed out\n"));
114 return NT_STATUS_IO_TIMEOUT
;
118 DEBUG(10, ("poll returned %s\n", strerror(errno
)));
119 return map_nt_error_from_unix(errno
);
121 if ((revents
& (POLLIN
|POLLHUP
|POLLERR
)) == 0) {
122 DEBUG(10, ("socket not readable\n"));
123 return NT_STATUS_IO_TIMEOUT
;
126 return ctdb_packet_fd_read(ctx
);
129 bool ctdb_packet_handler(struct ctdb_packet_context
*ctx
,
130 bool (*full_req
)(const uint8_t *buf
,
134 NTSTATUS (*callback
)(uint8_t *buf
, size_t length
,
136 void *priv
, NTSTATUS
*status
)
141 if (!full_req(ctx
->in
.data
, ctx
->in
.length
, &length
, priv
)) {
145 if (length
> ctx
->in
.length
) {
146 *status
= NT_STATUS_INTERNAL_ERROR
;
150 if (length
== ctx
->in
.length
) {
155 buf
= (uint8_t *)talloc_memdup(ctx
, ctx
->in
.data
, length
);
157 *status
= NT_STATUS_NO_MEMORY
;
161 memmove(ctx
->in
.data
, ctx
->in
.data
+ length
,
162 ctx
->in
.length
- length
);
163 ctx
->in
.length
-= length
;
166 *status
= callback(buf
, length
, priv
);
171 * How many bytes of outgoing data do we have pending?
173 size_t ctdb_packet_outgoing_bytes(struct ctdb_packet_context
*ctx
)
175 return ctx
->out
.length
;
179 * Push data to the fd
181 NTSTATUS
ctdb_packet_fd_write(struct ctdb_packet_context
*ctx
)
185 sent
= sys_send(ctx
->fd
, ctx
->out
.data
, ctx
->out
.length
, 0);
188 DEBUG(0, ("send failed: %s\n", strerror(errno
)));
189 return map_nt_error_from_unix(errno
);
192 memmove(ctx
->out
.data
, ctx
->out
.data
+ sent
,
193 ctx
->out
.length
- sent
);
194 ctx
->out
.length
-= sent
;
200 * Sync flush all outgoing bytes
202 NTSTATUS
ctdb_packet_flush(struct ctdb_packet_context
*ctx
)
204 while (ctx
->out
.length
!= 0) {
205 NTSTATUS status
= ctdb_packet_fd_write(ctx
);
206 if (!NT_STATUS_IS_OK(status
)) {
214 * Send a list of DATA_BLOBs
216 * Example: ctdb_packet_send(ctx, 2, data_blob_const(&size, sizeof(size)),
217 * data_blob_const(buf, size));
219 NTSTATUS
ctdb_packet_send(struct ctdb_packet_context
*ctx
, int num_blobs
, ...)
226 len
= ctx
->out
.length
;
228 va_start(ap
, num_blobs
);
229 for (i
=0; i
<num_blobs
; i
++) {
231 DATA_BLOB blob
= va_arg(ap
, DATA_BLOB
);
233 tmp
= len
+ blob
.length
;
235 DEBUG(0, ("integer overflow\n"));
237 return NT_STATUS_NO_MEMORY
;
247 if (!(out
= talloc_realloc(ctx
, ctx
->out
.data
, uint8
, len
))) {
248 DEBUG(0, ("talloc failed\n"));
249 return NT_STATUS_NO_MEMORY
;
254 va_start(ap
, num_blobs
);
255 for (i
=0; i
<num_blobs
; i
++) {
256 DATA_BLOB blob
= va_arg(ap
, DATA_BLOB
);
258 memcpy(ctx
->out
.data
+ctx
->out
.length
, blob
.data
, blob
.length
);
259 ctx
->out
.length
+= blob
.length
;
263 SMB_ASSERT(ctx
->out
.length
== len
);
268 * Get the ctdb_packet context's file descriptor
270 int ctdb_packet_get_fd(struct ctdb_packet_context
*ctx
)