r2100: rework the dcerpc client side library so that it is async. We now
[abartlet/samba.git/.git] / source4 / librpc / rpc / dcerpc_tcp.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc over TCP transport
5
6    Copyright (C) Andrew Tridgell 2003
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24
25 #define MIN_HDR_SIZE 16
26
27 struct tcp_blob {
28         struct tcp_blob *next, *prev;
29         DATA_BLOB data;
30 };
31
32 /* transport private information used by TCP pipe transport */
33 struct tcp_private {
34         struct event_context *event_ctx;
35         struct fd_event *fde;
36         int fd;
37         char *server_name;
38         uint32_t port;
39
40         struct tcp_blob *pending_send;
41
42         struct {
43                 size_t received;
44                 DATA_BLOB data;
45                 uint_t pending_count;
46         } recv;
47 };
48
49
50 /*
51   mark the socket dead
52 */
53 static void tcp_sock_dead(struct dcerpc_pipe *p, NTSTATUS status)
54 {
55         struct tcp_private *tcp = p->transport.private;
56
57         if (tcp && tcp->fd != -1) {
58                 close(tcp->fd);
59                 tcp->fd = -1;
60         }
61
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);
66                 talloc_free(blob);
67         }
68
69         if (!NT_STATUS_IS_OK(status)) {
70                 p->transport.recv_data(p, NULL, status);
71         }
72 }
73
74 /*
75   process send requests
76 */
77 static void tcp_process_send(struct dcerpc_pipe *p)
78 {
79         struct tcp_private *tcp = p->transport.private;
80
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);
84                 if (ret == -1) {
85                         if (errno != EAGAIN && errno != EINTR) {
86                                 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
87                         }
88                         break;
89                 }
90
91                 blob->data.data += ret;
92                 blob->data.length -= ret;
93
94                 if (blob->data.length != 0) {
95                         break;
96                 }
97
98                 DLIST_REMOVE(tcp->pending_send, blob);
99                 talloc_free(blob);
100         }
101
102         if (tcp->pending_send == NULL) {
103                 tcp->fde->flags &= ~EVENT_FD_WRITE;
104         }
105 }
106
107
108 /*
109   process recv requests
110 */
111 static void tcp_process_recv(struct dcerpc_pipe *p)
112 {
113         struct tcp_private *tcp = p->transport.private;
114         ssize_t ret;
115
116         /* read in the base header to get the fragment length */
117         if (tcp->recv.received < MIN_HDR_SIZE) {
118                 uint32_t frag_length;
119
120                 ret = read(tcp->fd, tcp->recv.data.data, 
121                            MIN_HDR_SIZE - tcp->recv.received);
122                 if (ret == -1) {
123                         if (errno != EAGAIN && errno != EINTR) {
124                                 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
125                         }
126                         return;
127                 }
128                 if (ret == 0) {
129                         tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
130                         return;
131                 }
132
133                 tcp->recv.received += ret;
134
135                 if (tcp->recv.received != MIN_HDR_SIZE) {
136                         return;
137                 }
138                 frag_length = dcerpc_get_frag_length(&tcp->recv.data);
139
140                 tcp->recv.data.data = talloc_realloc(tcp->recv.data.data,
141                                                      frag_length);
142                 if (tcp->recv.data.data == NULL) {
143                         tcp_sock_dead(p, NT_STATUS_NO_MEMORY);
144                         return;
145                 }
146                 tcp->recv.data.length = frag_length;
147         }
148
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);
152         if (ret == -1) {
153                 if (errno != EAGAIN && errno != EINTR) {
154                         tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
155                 }
156                 return;
157         }
158         if (ret == 0) {
159                 tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
160                 return;
161         }
162
163         tcp->recv.received += ret;
164
165         if (tcp->recv.received != tcp->recv.data.length) {
166                 return;
167         }
168
169         /* we have a full packet */
170         p->transport.recv_data(p, &tcp->recv.data, NT_STATUS_OK);
171
172         tcp->recv.received = 0;
173         tcp->recv.pending_count--;
174         if (tcp->recv.pending_count == 0) {
175                 tcp->fde->flags &= ~EVENT_FD_READ;
176         }
177 }
178
179 /*
180   called when a IO is triggered by the events system
181 */
182 static void tcp_io_handler(struct event_context *ev, struct fd_event *fde, 
183                            time_t t, uint16_t flags)
184 {
185         struct dcerpc_pipe *p = fde->private;
186         struct tcp_private *tcp = p->transport.private;
187
188         if (flags & EVENT_FD_WRITE) {
189                 tcp_process_send(p);
190         }
191
192         if (tcp->fd == -1) {
193                 return;
194         }
195
196         if (flags & EVENT_FD_READ) {
197                 tcp_process_recv(p);
198         }
199 }
200
201 /* 
202    send an initial pdu in a multi-pdu sequence
203 */
204 static NTSTATUS tcp_send_request(struct dcerpc_pipe *p, 
205                                  DATA_BLOB *data)
206 {
207         struct tcp_private *tcp = p->transport.private;
208         struct tcp_blob *blob;
209
210         blob = talloc_p(tcp, struct tcp_blob);
211         if (blob == NULL) {
212                 return NT_STATUS_NO_MEMORY;
213         }
214
215         blob->data = data_blob_talloc(blob, data->data, data->length);
216         if (blob->data.data == NULL) {
217                 talloc_free(blob);
218                 return NT_STATUS_NO_MEMORY;
219         }
220
221         DLIST_ADD_END(tcp->pending_send, blob, struct tcp_blob *);
222
223         tcp->fde->flags |= EVENT_FD_WRITE;
224
225         return NT_STATUS_OK;
226 }
227
228 /* 
229    initiate a read request 
230 */
231 static NTSTATUS tcp_send_read(struct dcerpc_pipe *p)
232 {
233         struct tcp_private *tcp = p->transport.private;
234
235         tcp->recv.pending_count++;
236         if (tcp->recv.pending_count == 1) {
237                 tcp->fde->flags |= EVENT_FD_READ;
238         }
239         return NT_STATUS_OK;
240 }
241
242 /* 
243    return the event context so the caller can process asynchronously
244 */
245 static struct event_context *tcp_event_context(struct dcerpc_pipe *p)
246 {
247         struct tcp_private *tcp = p->transport.private;
248
249         return tcp->event_ctx;
250 }
251
252 /* 
253    shutdown TCP pipe connection
254 */
255 static NTSTATUS tcp_shutdown_pipe(struct dcerpc_pipe *p)
256 {
257         tcp_sock_dead(p, NT_STATUS_OK);
258
259         return NT_STATUS_OK;
260 }
261
262 /*
263   return TCP server name
264 */
265 static const char *tcp_peer_name(struct dcerpc_pipe *p)
266 {
267         struct tcp_private *tcp = p->transport.private;
268         return tcp->server_name;
269 }
270
271
272 /* 
273    open a rpc connection to a named pipe 
274 */
275 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, 
276                               const char *server,
277                               uint32_t port)
278 {
279         struct tcp_private *tcp;
280         int fd;
281         struct in_addr addr;
282         struct fd_event fde;
283
284         if (port == 0) {
285                 port = EPMAPPER_PORT;
286         }
287
288         addr.s_addr = interpret_addr(server);
289         if (addr.s_addr == 0) {
290                 return NT_STATUS_BAD_NETWORK_NAME;
291         }
292
293         fd = open_socket_out(SOCK_STREAM, &addr, port, 30000);
294         if (fd == -1) {
295                 return NT_STATUS_PORT_CONNECTION_REFUSED;
296         }
297
298         set_blocking(fd, False);
299
300         if (!(*p = dcerpc_pipe_init())) {
301                 return NT_STATUS_NO_MEMORY;
302         }
303  
304         /*
305           fill in the transport methods
306         */
307         (*p)->transport.transport = NCACN_IP_TCP;
308         (*p)->transport.private = NULL;
309
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;
314
315         (*p)->transport.shutdown_pipe = tcp_shutdown_pipe;
316         (*p)->transport.peer_name = tcp_peer_name;
317         
318         tcp = talloc((*p), sizeof(*tcp));
319         if (!tcp) {
320                 dcerpc_pipe_close(*p);
321                 return NT_STATUS_NO_MEMORY;
322         }
323
324         tcp->fd = fd;
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;
331
332         fde.fd = fd;
333         fde.flags = 0;
334         fde.handler = tcp_io_handler;
335         fde.private = *p;
336
337         tcp->fde = event_add_fd(tcp->event_ctx, &fde);
338
339         (*p)->transport.private = tcp;
340
341         return NT_STATUS_OK;
342 }