s4:socket: use a socket_wrapper aware function to auto close the fd event for sockets
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / socket.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Socket functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Tim Potter      2000-2001
6    Copyright (C) Stefan Metzmacher 2004
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/socket/socket.h"
24 #include "system/filesys.h"
25 #include "system/network.h"
26 #include "param/param.h"
27
28 /*
29   auto-close sockets on free
30 */
31 static int socket_destructor(struct socket_context *sock)
32 {
33         if (sock->ops->fn_close && 
34             !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
35                 sock->ops->fn_close(sock);
36         }
37         return 0;
38 }
39
40 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
41                                         struct tevent_fd *fde,
42                                         int fd,
43                                         void *private_data)
44 {
45         /* this might be the socket_wrapper swrap_close() */
46         close(fd);
47 }
48
49 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
50                                          struct socket_context **new_sock, 
51                                          enum socket_type type, uint32_t flags)
52 {
53         NTSTATUS status;
54
55         (*new_sock) = talloc(mem_ctx, struct socket_context);
56         if (!(*new_sock)) {
57                 return NT_STATUS_NO_MEMORY;
58         }
59
60         (*new_sock)->type = type;
61         (*new_sock)->state = SOCKET_STATE_UNDEFINED;
62         (*new_sock)->flags = flags;
63
64         (*new_sock)->fd = -1;
65
66         (*new_sock)->private_data = NULL;
67         (*new_sock)->ops = ops;
68         (*new_sock)->backend_name = NULL;
69
70         status = (*new_sock)->ops->fn_init((*new_sock));
71         if (!NT_STATUS_IS_OK(status)) {
72                 talloc_free(*new_sock);
73                 return status;
74         }
75
76         /* by enabling "testnonblock" mode, all socket receive and
77            send calls on non-blocking sockets will randomly recv/send
78            less data than requested */
79
80         if (!(flags & SOCKET_FLAG_BLOCK) &&
81             type == SOCKET_TYPE_STREAM &&
82                 getenv("SOCKET_TESTNONBLOCK") != NULL) {
83                 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
84         }
85
86         /* we don't do a connect() on dgram sockets, so need to set
87            non-blocking at socket create time */
88         if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
89                 set_blocking(socket_get_fd(*new_sock), false);
90         }
91
92         talloc_set_destructor(*new_sock, socket_destructor);
93
94         return NT_STATUS_OK;
95 }
96
97 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type, 
98                                 struct socket_context **new_sock, uint32_t flags)
99 {
100         const struct socket_ops *ops;
101
102         ops = socket_getops_byname(name, type);
103         if (!ops) {
104                 return NT_STATUS_INVALID_PARAMETER;
105         }
106
107         return socket_create_with_ops(NULL, ops, new_sock, type, flags);
108 }
109
110 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
111                                  const struct socket_address *my_address, 
112                                  const struct socket_address *server_address,
113                                  uint32_t flags)
114 {
115         if (sock == NULL) {
116                 return NT_STATUS_CONNECTION_DISCONNECTED;
117         }
118         if (sock->state != SOCKET_STATE_UNDEFINED) {
119                 return NT_STATUS_INVALID_PARAMETER;
120         }
121
122         if (!sock->ops->fn_connect) {
123                 return NT_STATUS_NOT_IMPLEMENTED;
124         }
125
126         return sock->ops->fn_connect(sock, my_address, server_address, flags);
127 }
128
129 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
130 {
131         if (!sock->ops->fn_connect_complete) {
132                 return NT_STATUS_NOT_IMPLEMENTED;
133         }
134         return sock->ops->fn_connect_complete(sock, flags);
135 }
136
137 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock, 
138                                 const struct socket_address *my_address, 
139                                 int queue_size, uint32_t flags)
140 {
141         if (sock == NULL) {
142                 return NT_STATUS_CONNECTION_DISCONNECTED;
143         }
144         if (sock->state != SOCKET_STATE_UNDEFINED) {
145                 return NT_STATUS_INVALID_PARAMETER;
146         }
147
148         if (!sock->ops->fn_listen) {
149                 return NT_STATUS_NOT_IMPLEMENTED;
150         }
151
152         return sock->ops->fn_listen(sock, my_address, queue_size, flags);
153 }
154
155 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
156 {
157         NTSTATUS status;
158
159         if (sock == NULL) {
160                 return NT_STATUS_CONNECTION_DISCONNECTED;
161         }
162         if (sock->type != SOCKET_TYPE_STREAM) {
163                 return NT_STATUS_INVALID_PARAMETER;
164         }
165
166         if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
167                 return NT_STATUS_INVALID_PARAMETER;
168         }
169
170         if (!sock->ops->fn_accept) {
171                 return NT_STATUS_NOT_IMPLEMENTED;
172         }
173
174         status = sock->ops->fn_accept(sock, new_sock);
175
176         if (NT_STATUS_IS_OK(status)) {
177                 talloc_set_destructor(*new_sock, socket_destructor);
178                 (*new_sock)->flags = 0;
179         }
180
181         return status;
182 }
183
184 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf, 
185                               size_t wantlen, size_t *nread)
186 {
187         if (sock == NULL) {
188                 return NT_STATUS_CONNECTION_DISCONNECTED;
189         }
190         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
191             sock->state != SOCKET_STATE_SERVER_CONNECTED &&
192             sock->type  != SOCKET_TYPE_DGRAM) {
193                 return NT_STATUS_INVALID_PARAMETER;
194         }
195
196         if (!sock->ops->fn_recv) {
197                 return NT_STATUS_NOT_IMPLEMENTED;
198         }
199
200         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) 
201             && wantlen > 1) {
202
203                 if (random() % 10 == 0) {
204                         *nread = 0;
205                         return STATUS_MORE_ENTRIES;
206                 }
207                 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
208         }
209         return sock->ops->fn_recv(sock, buf, wantlen, nread);
210 }
211
212 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf, 
213                                   size_t wantlen, size_t *nread, 
214                                   TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
215 {
216         if (sock == NULL) {
217                 return NT_STATUS_CONNECTION_DISCONNECTED;
218         }
219         if (sock->type != SOCKET_TYPE_DGRAM) {
220                 return NT_STATUS_INVALID_PARAMETER;
221         }
222
223         if (!sock->ops->fn_recvfrom) {
224                 return NT_STATUS_NOT_IMPLEMENTED;
225         }
226
227         return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, 
228                                       mem_ctx, src_addr);
229 }
230
231 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock, 
232                               const DATA_BLOB *blob, size_t *sendlen)
233 {
234         if (sock == NULL) {
235                 return NT_STATUS_CONNECTION_DISCONNECTED;
236         }
237         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
238             sock->state != SOCKET_STATE_SERVER_CONNECTED) {
239                 return NT_STATUS_INVALID_PARAMETER;
240         }
241
242         if (!sock->ops->fn_send) {
243                 return NT_STATUS_NOT_IMPLEMENTED;
244         }
245         
246         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
247             && blob->length > 1) {
248                 DATA_BLOB blob2 = *blob;
249                 if (random() % 10 == 0) {
250                         *sendlen = 0;
251                         return STATUS_MORE_ENTRIES;
252                 }
253                 /* The random size sends are incompatible with TLS and SASL
254                  * sockets, which require re-sends to be consistant */
255                 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
256                         blob2.length = 1+(random() % blob2.length);
257                 } else {
258                         /* This is particularly stressful on buggy
259                          * LDAP clients, that don't expect on LDAP
260                          * packet in many SASL packets */
261                         blob2.length = 1 + blob2.length/2;
262                 }
263                 return sock->ops->fn_send(sock, &blob2, sendlen);
264         }
265         return sock->ops->fn_send(sock, blob, sendlen);
266 }
267
268
269 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock, 
270                                 const DATA_BLOB *blob, size_t *sendlen, 
271                                 const struct socket_address *dest_addr)
272 {
273         if (sock == NULL) {
274                 return NT_STATUS_CONNECTION_DISCONNECTED;
275         }
276         if (sock->type != SOCKET_TYPE_DGRAM) {
277                 return NT_STATUS_INVALID_PARAMETER;
278         }
279
280         if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
281             sock->state == SOCKET_STATE_SERVER_CONNECTED) {
282                 return NT_STATUS_INVALID_PARAMETER;
283         }
284
285         if (!sock->ops->fn_sendto) {
286                 return NT_STATUS_NOT_IMPLEMENTED;
287         }
288
289         return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
290 }
291
292
293 /*
294   ask for the number of bytes in a pending incoming packet
295 */
296 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
297 {
298         if (sock == NULL) {
299                 return NT_STATUS_CONNECTION_DISCONNECTED;
300         }
301         if (!sock->ops->fn_pending) {
302                 return NT_STATUS_NOT_IMPLEMENTED;
303         }
304         return sock->ops->fn_pending(sock, npending);
305 }
306
307
308 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
309 {
310         if (sock == NULL) {
311                 return NT_STATUS_CONNECTION_DISCONNECTED;
312         }
313         if (!sock->ops->fn_set_option) {
314                 return NT_STATUS_NOT_IMPLEMENTED;
315         }
316
317         return sock->ops->fn_set_option(sock, option, val);
318 }
319
320 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
321 {
322         if (!sock->ops->fn_get_peer_name) {
323                 return NULL;
324         }
325
326         return sock->ops->fn_get_peer_name(sock, mem_ctx);
327 }
328
329 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
330 {
331         if (!sock->ops->fn_get_peer_addr) {
332                 return NULL;
333         }
334
335         return sock->ops->fn_get_peer_addr(sock, mem_ctx);
336 }
337
338 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
339 {
340         if (!sock->ops->fn_get_my_addr) {
341                 return NULL;
342         }
343
344         return sock->ops->fn_get_my_addr(sock, mem_ctx);
345 }
346
347 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
348 {
349         if (!sock->ops->fn_get_fd) {
350                 return -1;
351         }
352
353         return sock->ops->fn_get_fd(sock);
354 }
355
356 /*
357   call dup() on a socket, and close the old fd. This is used to change
358   the fd to the lowest available number, to make select() more
359   efficient (select speed depends on the maxiumum fd number passed to
360   it)
361 */
362 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
363 {
364         int fd;
365         if (sock->fd == -1) {
366                 return NT_STATUS_INVALID_HANDLE;
367         }
368         fd = dup(sock->fd);
369         if (fd == -1) {
370                 return map_nt_error_from_unix(errno);
371         }
372         close(sock->fd);
373         sock->fd = fd;
374         return NT_STATUS_OK;
375         
376 }
377
378 /* Create a new socket_address.  The type must match the socket type.
379  * The host parameter may be an IP or a hostname 
380  */
381
382 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
383                                                             const char *family,
384                                                             const char *host,
385                                                             int port)
386 {
387         struct socket_address *addr = talloc(mem_ctx, struct socket_address);
388         if (!addr) {
389                 return NULL;
390         }
391
392         addr->family = family;
393         addr->addr = talloc_strdup(addr, host);
394         if (!addr->addr) {
395                 talloc_free(addr);
396                 return NULL;
397         }
398         addr->port = port;
399         addr->sockaddr = NULL;
400         addr->sockaddrlen = 0;
401
402         return addr;
403 }
404
405 /* Create a new socket_address.  Copy the struct sockaddr into the new
406  * structure.  Used for hooks in the kerberos libraries, where they
407  * supply only a struct sockaddr */
408
409 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx, 
410                                                              struct sockaddr *sockaddr, 
411                                                              size_t sockaddrlen)
412 {
413         struct socket_address *addr = talloc(mem_ctx, struct socket_address);
414         if (!addr) {
415                 return NULL;
416         }
417         addr->family = NULL; 
418         addr->addr = NULL;
419         addr->port = 0;
420         addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
421         if (!addr->sockaddr) {
422                 talloc_free(addr);
423                 return NULL;
424         }
425         addr->sockaddrlen = sockaddrlen;
426         return addr;
427 }
428
429 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
430 {
431         extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
432         extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
433         extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
434
435         if (strcmp("ip", family) == 0 || 
436             strcmp("ipv4", family) == 0) {
437                 return socket_ipv4_ops(type);
438         }
439
440 #if HAVE_IPV6
441         if (strcmp("ipv6", family) == 0) {
442                 return socket_ipv6_ops(type);
443         }
444 #endif
445
446         if (strcmp("unix", family) == 0) {
447                 return socket_unixdom_ops(type);
448         }
449
450         return NULL;
451 }
452
453 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
454
455 static const struct {
456         const char *name;
457         int level;
458         int option;
459         int value;
460         int opttype;
461 } socket_options[] = {
462   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
463   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
464   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
465 #ifdef TCP_NODELAY
466   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
467 #endif
468 #ifdef IPTOS_LOWDELAY
469   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
470 #endif
471 #ifdef IPTOS_THROUGHPUT
472   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
473 #endif
474 #ifdef SO_REUSEPORT
475   {"SO_REUSEPORT",      SOL_SOCKET,    SO_REUSEPORT,    0,                 OPT_BOOL},
476 #endif
477 #ifdef SO_SNDBUF
478   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
479 #endif
480 #ifdef SO_RCVBUF
481   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
482 #endif
483 #ifdef SO_SNDLOWAT
484   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
485 #endif
486 #ifdef SO_RCVLOWAT
487   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
488 #endif
489 #ifdef SO_SNDTIMEO
490   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
491 #endif
492 #ifdef SO_RCVTIMEO
493   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
494 #endif
495   {NULL,0,0,0,0}};
496
497
498 /**
499  Set user socket options.
500 **/
501 _PUBLIC_ void set_socket_options(int fd, const char *options)
502 {
503         const char **options_list = (const char **)str_list_make(NULL, options, " \t,");
504         int j;
505
506         if (!options_list)
507                 return;
508
509         for (j = 0; options_list[j]; j++) {
510                 const char *tok = options_list[j];
511                 int ret=0,i;
512                 int value = 1;
513                 char *p;
514                 bool got_value = false;
515
516                 if ((p = strchr(tok,'='))) {
517                         *p = 0;
518                         value = atoi(p+1);
519                         got_value = true;
520                 }
521
522                 for (i=0;socket_options[i].name;i++)
523                         if (strequal(socket_options[i].name,tok))
524                                 break;
525
526                 if (!socket_options[i].name) {
527                         DEBUG(0,("Unknown socket option %s\n",tok));
528                         continue;
529                 }
530
531                 switch (socket_options[i].opttype) {
532                 case OPT_BOOL:
533                 case OPT_INT:
534                         ret = setsockopt(fd,socket_options[i].level,
535                                                 socket_options[i].option,(char *)&value,sizeof(int));
536                         break;
537
538                 case OPT_ON:
539                         if (got_value)
540                                 DEBUG(0,("syntax error - %s does not take a value\n",tok));
541
542                         {
543                                 int on = socket_options[i].value;
544                                 ret = setsockopt(fd,socket_options[i].level,
545                                                         socket_options[i].option,(char *)&on,sizeof(int));
546                         }
547                         break;    
548                 }
549       
550                 if (ret != 0)
551                         DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
552         }
553
554         talloc_free(options_list);
555 }
556
557 /*
558   set some flags on a socket 
559  */
560 void socket_set_flags(struct socket_context *sock, unsigned flags)
561 {
562         sock->flags |= flags;
563 }