s3: Make adt_tree data definitions private to adt_tree.c
[Samba/gebeck_regimport.git] / source4 / lib / socket / socket.c
blob30db03fd97cb0d4d6ad5484111283f3bc66b0081
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
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.
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, see <http://www.gnu.org/licenses/>.
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 #include "../lib/tsocket/tsocket.h"
30 auto-close sockets on free
32 static int socket_destructor(struct socket_context *sock)
34 if (sock->ops->fn_close &&
35 !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
36 sock->ops->fn_close(sock);
38 return 0;
41 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
42 struct tevent_fd *fde,
43 int fd,
44 void *private_data)
46 /* this might be the socket_wrapper swrap_close() */
47 close(fd);
50 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
51 struct socket_context **new_sock,
52 enum socket_type type, uint32_t flags)
54 NTSTATUS status;
56 (*new_sock) = talloc(mem_ctx, struct socket_context);
57 if (!(*new_sock)) {
58 return NT_STATUS_NO_MEMORY;
61 (*new_sock)->type = type;
62 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
63 (*new_sock)->flags = flags;
65 (*new_sock)->fd = -1;
67 (*new_sock)->private_data = NULL;
68 (*new_sock)->ops = ops;
69 (*new_sock)->backend_name = NULL;
71 status = (*new_sock)->ops->fn_init((*new_sock));
72 if (!NT_STATUS_IS_OK(status)) {
73 talloc_free(*new_sock);
74 return status;
77 /* by enabling "testnonblock" mode, all socket receive and
78 send calls on non-blocking sockets will randomly recv/send
79 less data than requested */
81 if (!(flags & SOCKET_FLAG_BLOCK) &&
82 type == SOCKET_TYPE_STREAM &&
83 getenv("SOCKET_TESTNONBLOCK") != NULL) {
84 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
87 /* we don't do a connect() on dgram sockets, so need to set
88 non-blocking at socket create time */
89 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
90 set_blocking(socket_get_fd(*new_sock), false);
93 talloc_set_destructor(*new_sock, socket_destructor);
95 return NT_STATUS_OK;
98 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
99 struct socket_context **new_sock, uint32_t flags)
101 const struct socket_ops *ops;
103 ops = socket_getops_byname(name, type);
104 if (!ops) {
105 return NT_STATUS_INVALID_PARAMETER;
108 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
111 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
112 const struct socket_address *my_address,
113 const struct socket_address *server_address,
114 uint32_t flags)
116 if (sock == NULL) {
117 return NT_STATUS_CONNECTION_DISCONNECTED;
119 if (sock->state != SOCKET_STATE_UNDEFINED) {
120 return NT_STATUS_INVALID_PARAMETER;
123 if (!sock->ops->fn_connect) {
124 return NT_STATUS_NOT_IMPLEMENTED;
127 return sock->ops->fn_connect(sock, my_address, server_address, flags);
130 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
132 if (!sock->ops->fn_connect_complete) {
133 return NT_STATUS_NOT_IMPLEMENTED;
135 return sock->ops->fn_connect_complete(sock, flags);
138 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
139 const struct socket_address *my_address,
140 int queue_size, uint32_t flags)
142 if (sock == NULL) {
143 return NT_STATUS_CONNECTION_DISCONNECTED;
145 if (sock->state != SOCKET_STATE_UNDEFINED) {
146 return NT_STATUS_INVALID_PARAMETER;
149 if (!sock->ops->fn_listen) {
150 return NT_STATUS_NOT_IMPLEMENTED;
153 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
156 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
158 NTSTATUS status;
160 if (sock == NULL) {
161 return NT_STATUS_CONNECTION_DISCONNECTED;
163 if (sock->type != SOCKET_TYPE_STREAM) {
164 return NT_STATUS_INVALID_PARAMETER;
167 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
168 return NT_STATUS_INVALID_PARAMETER;
171 if (!sock->ops->fn_accept) {
172 return NT_STATUS_NOT_IMPLEMENTED;
175 status = sock->ops->fn_accept(sock, new_sock);
177 if (NT_STATUS_IS_OK(status)) {
178 talloc_set_destructor(*new_sock, socket_destructor);
179 (*new_sock)->flags = 0;
182 return status;
185 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
186 size_t wantlen, size_t *nread)
188 if (sock == NULL) {
189 return NT_STATUS_CONNECTION_DISCONNECTED;
191 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
192 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
193 sock->type != SOCKET_TYPE_DGRAM) {
194 return NT_STATUS_INVALID_PARAMETER;
197 if (!sock->ops->fn_recv) {
198 return NT_STATUS_NOT_IMPLEMENTED;
201 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
202 && wantlen > 1) {
204 if (random() % 10 == 0) {
205 *nread = 0;
206 return STATUS_MORE_ENTRIES;
208 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
210 return sock->ops->fn_recv(sock, buf, wantlen, nread);
213 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
214 size_t wantlen, size_t *nread,
215 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
217 if (sock == NULL) {
218 return NT_STATUS_CONNECTION_DISCONNECTED;
220 if (sock->type != SOCKET_TYPE_DGRAM) {
221 return NT_STATUS_INVALID_PARAMETER;
224 if (!sock->ops->fn_recvfrom) {
225 return NT_STATUS_NOT_IMPLEMENTED;
228 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
229 mem_ctx, src_addr);
232 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
233 const DATA_BLOB *blob, size_t *sendlen)
235 if (sock == NULL) {
236 return NT_STATUS_CONNECTION_DISCONNECTED;
238 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
239 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
240 return NT_STATUS_INVALID_PARAMETER;
243 if (!sock->ops->fn_send) {
244 return NT_STATUS_NOT_IMPLEMENTED;
247 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
248 && blob->length > 1) {
249 DATA_BLOB blob2 = *blob;
250 if (random() % 10 == 0) {
251 *sendlen = 0;
252 return STATUS_MORE_ENTRIES;
254 /* The random size sends are incompatible with TLS and SASL
255 * sockets, which require re-sends to be consistant */
256 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
257 blob2.length = 1+(random() % blob2.length);
258 } else {
259 /* This is particularly stressful on buggy
260 * LDAP clients, that don't expect on LDAP
261 * packet in many SASL packets */
262 blob2.length = 1 + blob2.length/2;
264 return sock->ops->fn_send(sock, &blob2, sendlen);
266 return sock->ops->fn_send(sock, blob, sendlen);
270 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
271 const DATA_BLOB *blob, size_t *sendlen,
272 const struct socket_address *dest_addr)
274 if (sock == NULL) {
275 return NT_STATUS_CONNECTION_DISCONNECTED;
277 if (sock->type != SOCKET_TYPE_DGRAM) {
278 return NT_STATUS_INVALID_PARAMETER;
281 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
282 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
283 return NT_STATUS_INVALID_PARAMETER;
286 if (!sock->ops->fn_sendto) {
287 return NT_STATUS_NOT_IMPLEMENTED;
290 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
295 ask for the number of bytes in a pending incoming packet
297 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
299 if (sock == NULL) {
300 return NT_STATUS_CONNECTION_DISCONNECTED;
302 if (!sock->ops->fn_pending) {
303 return NT_STATUS_NOT_IMPLEMENTED;
305 return sock->ops->fn_pending(sock, npending);
309 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
311 if (sock == NULL) {
312 return NT_STATUS_CONNECTION_DISCONNECTED;
314 if (!sock->ops->fn_set_option) {
315 return NT_STATUS_NOT_IMPLEMENTED;
318 return sock->ops->fn_set_option(sock, option, val);
321 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
323 if (!sock->ops->fn_get_peer_name) {
324 return NULL;
327 return sock->ops->fn_get_peer_name(sock, mem_ctx);
330 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
332 if (!sock->ops->fn_get_peer_addr) {
333 return NULL;
336 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
339 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
341 if (!sock->ops->fn_get_my_addr) {
342 return NULL;
345 return sock->ops->fn_get_my_addr(sock, mem_ctx);
348 _PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
349 const struct socket_address *a)
351 struct tsocket_address *r;
352 int ret;
354 if (a->sockaddr) {
355 ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
356 a->sockaddr,
357 a->sockaddrlen,
358 &r);
359 } else {
360 ret = tsocket_address_inet_from_strings(mem_ctx,
361 a->family,
362 a->addr,
363 a->port,
364 &r);
367 if (ret != 0) {
368 return NULL;
371 return r;
374 _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
375 const struct tsocket_address *a)
377 ssize_t ret;
378 struct sockaddr_storage ss;
379 size_t sslen = sizeof(ss);
381 ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
382 if (ret < 0) {
383 return NULL;
386 return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
389 _PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
391 struct socket_address *a;
392 struct tsocket_address *r;
394 a = socket_get_peer_addr(sock, mem_ctx);
395 if (a == NULL) {
396 return NULL;
399 r = socket_address_to_tsocket_address(mem_ctx, a);
400 talloc_free(a);
401 return r;
404 _PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
406 struct socket_address *a;
407 struct tsocket_address *r;
409 a = socket_get_my_addr(sock, mem_ctx);
410 if (a == NULL) {
411 return NULL;
414 r = socket_address_to_tsocket_address(mem_ctx, a);
415 talloc_free(a);
416 return r;
419 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
421 if (!sock->ops->fn_get_fd) {
422 return -1;
425 return sock->ops->fn_get_fd(sock);
429 call dup() on a socket, and close the old fd. This is used to change
430 the fd to the lowest available number, to make select() more
431 efficient (select speed depends on the maxiumum fd number passed to
434 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
436 int fd;
437 if (sock->fd == -1) {
438 return NT_STATUS_INVALID_HANDLE;
440 fd = dup(sock->fd);
441 if (fd == -1) {
442 return map_nt_error_from_unix(errno);
444 close(sock->fd);
445 sock->fd = fd;
446 return NT_STATUS_OK;
450 /* Create a new socket_address. The type must match the socket type.
451 * The host parameter may be an IP or a hostname
454 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
455 const char *family,
456 const char *host,
457 int port)
459 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
460 if (!addr) {
461 return NULL;
464 addr->family = family;
465 addr->addr = talloc_strdup(addr, host);
466 if (!addr->addr) {
467 talloc_free(addr);
468 return NULL;
470 addr->port = port;
471 addr->sockaddr = NULL;
472 addr->sockaddrlen = 0;
474 return addr;
477 /* Create a new socket_address. Copy the struct sockaddr into the new
478 * structure. Used for hooks in the kerberos libraries, where they
479 * supply only a struct sockaddr */
481 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
482 struct sockaddr *sockaddr,
483 size_t sockaddrlen)
485 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
486 if (!addr) {
487 return NULL;
489 addr->family = NULL;
490 addr->addr = NULL;
491 addr->port = 0;
492 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
493 if (!addr->sockaddr) {
494 talloc_free(addr);
495 return NULL;
497 addr->sockaddrlen = sockaddrlen;
498 return addr;
501 /* Copy a socket_address structure */
502 struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
503 const struct socket_address *oaddr)
505 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
506 if (!addr) {
507 return NULL;
509 addr->family = oaddr->family;
510 if (oaddr->addr) {
511 addr->addr = talloc_strdup(addr, oaddr->addr);
512 if (!addr->addr) {
513 goto nomem;
516 addr->port = oaddr->port;
517 if (oaddr->sockaddr) {
518 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
519 oaddr->sockaddr,
520 oaddr->sockaddrlen);
521 if (!addr->sockaddr) {
522 goto nomem;
524 addr->sockaddrlen = oaddr->sockaddrlen;
527 return addr;
529 nomem:
530 talloc_free(addr);
531 return NULL;
534 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
536 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
537 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
538 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
540 if (strcmp("ip", family) == 0 ||
541 strcmp("ipv4", family) == 0) {
542 return socket_ipv4_ops(type);
545 #if HAVE_IPV6
546 if (strcmp("ipv6", family) == 0) {
547 return socket_ipv6_ops(type);
549 #endif
551 if (strcmp("unix", family) == 0) {
552 return socket_unixdom_ops(type);
555 return NULL;
558 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
560 static const struct {
561 const char *name;
562 int level;
563 int option;
564 int value;
565 int opttype;
566 } socket_options[] = {
567 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
568 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
569 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
570 #ifdef TCP_NODELAY
571 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
572 #endif
573 #ifdef IPTOS_LOWDELAY
574 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
575 #endif
576 #ifdef IPTOS_THROUGHPUT
577 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
578 #endif
579 #ifdef SO_REUSEPORT
580 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
581 #endif
582 #ifdef SO_SNDBUF
583 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
584 #endif
585 #ifdef SO_RCVBUF
586 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
587 #endif
588 #ifdef SO_SNDLOWAT
589 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
590 #endif
591 #ifdef SO_RCVLOWAT
592 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
593 #endif
594 #ifdef SO_SNDTIMEO
595 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
596 #endif
597 #ifdef SO_RCVTIMEO
598 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
599 #endif
600 {NULL,0,0,0,0}};
604 Set user socket options.
606 _PUBLIC_ void set_socket_options(int fd, const char *options)
608 const char **options_list = (const char **)str_list_make(NULL, options, " \t,");
609 int j;
611 if (!options_list)
612 return;
614 for (j = 0; options_list[j]; j++) {
615 const char *tok = options_list[j];
616 int ret=0,i;
617 int value = 1;
618 char *p;
619 bool got_value = false;
621 if ((p = strchr(tok,'='))) {
622 *p = 0;
623 value = atoi(p+1);
624 got_value = true;
627 for (i=0;socket_options[i].name;i++)
628 if (strequal(socket_options[i].name,tok))
629 break;
631 if (!socket_options[i].name) {
632 DEBUG(0,("Unknown socket option %s\n",tok));
633 continue;
636 switch (socket_options[i].opttype) {
637 case OPT_BOOL:
638 case OPT_INT:
639 ret = setsockopt(fd,socket_options[i].level,
640 socket_options[i].option,(char *)&value,sizeof(int));
641 break;
643 case OPT_ON:
644 if (got_value)
645 DEBUG(0,("syntax error - %s does not take a value\n",tok));
648 int on = socket_options[i].value;
649 ret = setsockopt(fd,socket_options[i].level,
650 socket_options[i].option,(char *)&on,sizeof(int));
652 break;
655 if (ret != 0)
656 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
659 talloc_free(options_list);
663 set some flags on a socket
665 void socket_set_flags(struct socket_context *sock, unsigned flags)
667 sock->flags |= flags;