2 Unix SMB/CIFS implementation.
4 dcerpc over TCP transport
6 Copyright (C) Andrew Tridgell 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define MIN_HDR_SIZE 16
28 struct tcp_blob *next, *prev;
32 /* transport private information used by TCP pipe transport */
34 struct event_context *event_ctx;
40 struct tcp_blob *pending_send;
53 static void tcp_sock_dead(struct dcerpc_pipe *p, NTSTATUS status)
55 struct tcp_private *tcp = p->transport.private;
57 if (tcp && tcp->fd != -1) {
62 /* wipe any pending sends */
63 while (tcp->pending_send) {
64 struct tcp_blob *blob = tcp->pending_send;
65 DLIST_REMOVE(tcp->pending_send, blob);
69 if (!NT_STATUS_IS_OK(status)) {
70 p->transport.recv_data(p, NULL, status);
77 static void tcp_process_send(struct dcerpc_pipe *p)
79 struct tcp_private *tcp = p->transport.private;
81 while (tcp->pending_send) {
82 struct tcp_blob *blob = tcp->pending_send;
83 ssize_t ret = write(tcp->fd, blob->data.data, blob->data.length);
85 if (errno != EAGAIN && errno != EINTR) {
86 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
91 blob->data.data += ret;
92 blob->data.length -= ret;
94 if (blob->data.length != 0) {
98 DLIST_REMOVE(tcp->pending_send, blob);
102 if (tcp->pending_send == NULL) {
103 tcp->fde->flags &= ~EVENT_FD_WRITE;
109 process recv requests
111 static void tcp_process_recv(struct dcerpc_pipe *p)
113 struct tcp_private *tcp = p->transport.private;
116 /* read in the base header to get the fragment length */
117 if (tcp->recv.received < MIN_HDR_SIZE) {
118 uint32_t frag_length;
120 ret = read(tcp->fd, tcp->recv.data.data,
121 MIN_HDR_SIZE - tcp->recv.received);
123 if (errno != EAGAIN && errno != EINTR) {
124 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
129 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
133 tcp->recv.received += ret;
135 if (tcp->recv.received != MIN_HDR_SIZE) {
138 frag_length = dcerpc_get_frag_length(&tcp->recv.data);
140 tcp->recv.data.data = talloc_realloc(tcp->recv.data.data,
142 if (tcp->recv.data.data == NULL) {
143 tcp_sock_dead(p, NT_STATUS_NO_MEMORY);
146 tcp->recv.data.length = frag_length;
149 /* read in the rest of the packet */
150 ret = read(tcp->fd, tcp->recv.data.data + tcp->recv.received,
151 tcp->recv.data.length - tcp->recv.received);
153 if (errno != EAGAIN && errno != EINTR) {
154 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
159 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
163 tcp->recv.received += ret;
165 if (tcp->recv.received != tcp->recv.data.length) {
169 /* we have a full packet */
170 p->transport.recv_data(p, &tcp->recv.data, NT_STATUS_OK);
172 tcp->recv.received = 0;
173 tcp->recv.pending_count--;
174 if (tcp->recv.pending_count == 0) {
175 tcp->fde->flags &= ~EVENT_FD_READ;
180 called when a IO is triggered by the events system
182 static void tcp_io_handler(struct event_context *ev, struct fd_event *fde,
183 time_t t, uint16_t flags)
185 struct dcerpc_pipe *p = fde->private;
186 struct tcp_private *tcp = p->transport.private;
188 if (flags & EVENT_FD_WRITE) {
196 if (flags & EVENT_FD_READ) {
202 send an initial pdu in a multi-pdu sequence
204 static NTSTATUS tcp_send_request(struct dcerpc_pipe *p,
207 struct tcp_private *tcp = p->transport.private;
208 struct tcp_blob *blob;
210 blob = talloc_p(tcp, struct tcp_blob);
212 return NT_STATUS_NO_MEMORY;
215 blob->data = data_blob_talloc(blob, data->data, data->length);
216 if (blob->data.data == NULL) {
218 return NT_STATUS_NO_MEMORY;
221 DLIST_ADD_END(tcp->pending_send, blob, struct tcp_blob *);
223 tcp->fde->flags |= EVENT_FD_WRITE;
229 initiate a read request
231 static NTSTATUS tcp_send_read(struct dcerpc_pipe *p)
233 struct tcp_private *tcp = p->transport.private;
235 tcp->recv.pending_count++;
236 if (tcp->recv.pending_count == 1) {
237 tcp->fde->flags |= EVENT_FD_READ;
243 return the event context so the caller can process asynchronously
245 static struct event_context *tcp_event_context(struct dcerpc_pipe *p)
247 struct tcp_private *tcp = p->transport.private;
249 return tcp->event_ctx;
253 shutdown TCP pipe connection
255 static NTSTATUS tcp_shutdown_pipe(struct dcerpc_pipe *p)
257 tcp_sock_dead(p, NT_STATUS_OK);
263 return TCP server name
265 static const char *tcp_peer_name(struct dcerpc_pipe *p)
267 struct tcp_private *tcp = p->transport.private;
268 return tcp->server_name;
273 open a rpc connection to a named pipe
275 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
279 struct tcp_private *tcp;
285 port = EPMAPPER_PORT;
288 addr.s_addr = interpret_addr(server);
289 if (addr.s_addr == 0) {
290 return NT_STATUS_BAD_NETWORK_NAME;
293 fd = open_socket_out(SOCK_STREAM, &addr, port, 30000);
295 return NT_STATUS_PORT_CONNECTION_REFUSED;
298 set_blocking(fd, False);
300 if (!(*p = dcerpc_pipe_init())) {
301 return NT_STATUS_NO_MEMORY;
305 fill in the transport methods
307 (*p)->transport.transport = NCACN_IP_TCP;
308 (*p)->transport.private = NULL;
310 (*p)->transport.send_request = tcp_send_request;
311 (*p)->transport.send_read = tcp_send_read;
312 (*p)->transport.event_context = tcp_event_context;
313 (*p)->transport.recv_data = NULL;
315 (*p)->transport.shutdown_pipe = tcp_shutdown_pipe;
316 (*p)->transport.peer_name = tcp_peer_name;
318 tcp = talloc((*p), sizeof(*tcp));
320 dcerpc_pipe_close(*p);
321 return NT_STATUS_NO_MEMORY;
325 tcp->server_name = talloc_strdup((*p), server);
326 tcp->event_ctx = event_context_init();
327 tcp->pending_send = NULL;
328 tcp->recv.received = 0;
329 tcp->recv.data = data_blob_talloc(tcp, NULL, MIN_HDR_SIZE);
330 tcp->recv.pending_count = 0;
334 fde.handler = tcp_io_handler;
337 tcp->fde = event_add_fd(tcp->event_ctx, &fde);
339 (*p)->transport.private = tcp;