s4:scripting/python: always treat the highwatermark as opaque (bug #9508)
[Samba.git] / source4 / lib / socket / socket.c
blob42eb53abcef7874524436d4dc13e2f6aca13fc4d
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"
28 #include "lib/util/util_net.h"
31 auto-close sockets on free
33 static int socket_destructor(struct socket_context *sock)
35 if (sock->ops->fn_close &&
36 !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
37 sock->ops->fn_close(sock);
39 return 0;
42 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
43 struct tevent_fd *fde,
44 int fd,
45 void *private_data)
47 /* this might be the socket_wrapper swrap_close() */
48 close(fd);
51 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
52 struct socket_context **new_sock,
53 enum socket_type type, uint32_t flags)
55 NTSTATUS status;
57 (*new_sock) = talloc(mem_ctx, struct socket_context);
58 if (!(*new_sock)) {
59 return NT_STATUS_NO_MEMORY;
62 (*new_sock)->type = type;
63 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
64 (*new_sock)->flags = flags;
66 (*new_sock)->fd = -1;
68 (*new_sock)->private_data = NULL;
69 (*new_sock)->ops = ops;
70 (*new_sock)->backend_name = NULL;
72 status = (*new_sock)->ops->fn_init((*new_sock));
73 if (!NT_STATUS_IS_OK(status)) {
74 talloc_free(*new_sock);
75 return status;
78 /* by enabling "testnonblock" mode, all socket receive and
79 send calls on non-blocking sockets will randomly recv/send
80 less data than requested */
82 if (!(flags & SOCKET_FLAG_BLOCK) &&
83 type == SOCKET_TYPE_STREAM &&
84 getenv("SOCKET_TESTNONBLOCK") != NULL) {
85 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
88 /* we don't do a connect() on dgram sockets, so need to set
89 non-blocking at socket create time */
90 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
91 set_blocking(socket_get_fd(*new_sock), false);
94 talloc_set_destructor(*new_sock, socket_destructor);
96 return NT_STATUS_OK;
99 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
100 struct socket_context **new_sock, uint32_t flags)
102 const struct socket_ops *ops;
104 ops = socket_getops_byname(name, type);
105 if (!ops) {
106 return NT_STATUS_INVALID_PARAMETER;
109 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
112 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
113 const struct socket_address *my_address,
114 const struct socket_address *server_address,
115 uint32_t flags)
117 if (sock == NULL) {
118 return NT_STATUS_CONNECTION_DISCONNECTED;
120 if (sock->state != SOCKET_STATE_UNDEFINED) {
121 return NT_STATUS_INVALID_PARAMETER;
124 if (!sock->ops->fn_connect) {
125 return NT_STATUS_NOT_IMPLEMENTED;
128 return sock->ops->fn_connect(sock, my_address, server_address, flags);
131 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
133 if (!sock->ops->fn_connect_complete) {
134 return NT_STATUS_NOT_IMPLEMENTED;
136 return sock->ops->fn_connect_complete(sock, flags);
139 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
140 const struct socket_address *my_address,
141 int queue_size, uint32_t flags)
143 if (sock == NULL) {
144 return NT_STATUS_CONNECTION_DISCONNECTED;
146 if (sock->state != SOCKET_STATE_UNDEFINED) {
147 return NT_STATUS_INVALID_PARAMETER;
150 if (!sock->ops->fn_listen) {
151 return NT_STATUS_NOT_IMPLEMENTED;
154 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
157 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
159 NTSTATUS status;
161 if (sock == NULL) {
162 return NT_STATUS_CONNECTION_DISCONNECTED;
164 if (sock->type != SOCKET_TYPE_STREAM) {
165 return NT_STATUS_INVALID_PARAMETER;
168 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
169 return NT_STATUS_INVALID_PARAMETER;
172 if (!sock->ops->fn_accept) {
173 return NT_STATUS_NOT_IMPLEMENTED;
176 status = sock->ops->fn_accept(sock, new_sock);
178 if (NT_STATUS_IS_OK(status)) {
179 talloc_set_destructor(*new_sock, socket_destructor);
180 (*new_sock)->flags = 0;
183 return status;
186 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
187 size_t wantlen, size_t *nread)
189 if (sock == NULL) {
190 return NT_STATUS_CONNECTION_DISCONNECTED;
192 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
193 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
194 sock->type != SOCKET_TYPE_DGRAM) {
195 return NT_STATUS_INVALID_PARAMETER;
198 if (!sock->ops->fn_recv) {
199 return NT_STATUS_NOT_IMPLEMENTED;
202 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
203 && wantlen > 1) {
205 if (random() % 10 == 0) {
206 *nread = 0;
207 return STATUS_MORE_ENTRIES;
209 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
211 return sock->ops->fn_recv(sock, buf, wantlen, nread);
214 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
215 size_t wantlen, size_t *nread,
216 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
218 if (sock == NULL) {
219 return NT_STATUS_CONNECTION_DISCONNECTED;
221 if (sock->type != SOCKET_TYPE_DGRAM) {
222 return NT_STATUS_INVALID_PARAMETER;
225 if (!sock->ops->fn_recvfrom) {
226 return NT_STATUS_NOT_IMPLEMENTED;
229 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
230 mem_ctx, src_addr);
233 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
234 const DATA_BLOB *blob, size_t *sendlen)
236 if (sock == NULL) {
237 return NT_STATUS_CONNECTION_DISCONNECTED;
239 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
240 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
241 return NT_STATUS_INVALID_PARAMETER;
244 if (!sock->ops->fn_send) {
245 return NT_STATUS_NOT_IMPLEMENTED;
248 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
249 && blob->length > 1) {
250 DATA_BLOB blob2 = *blob;
251 if (random() % 10 == 0) {
252 *sendlen = 0;
253 return STATUS_MORE_ENTRIES;
255 /* The random size sends are incompatible with TLS and SASL
256 * sockets, which require re-sends to be consistant */
257 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
258 blob2.length = 1+(random() % blob2.length);
259 } else {
260 /* This is particularly stressful on buggy
261 * LDAP clients, that don't expect on LDAP
262 * packet in many SASL packets */
263 blob2.length = 1 + blob2.length/2;
265 return sock->ops->fn_send(sock, &blob2, sendlen);
267 return sock->ops->fn_send(sock, blob, sendlen);
271 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
272 const DATA_BLOB *blob, size_t *sendlen,
273 const struct socket_address *dest_addr)
275 if (sock == NULL) {
276 return NT_STATUS_CONNECTION_DISCONNECTED;
278 if (sock->type != SOCKET_TYPE_DGRAM) {
279 return NT_STATUS_INVALID_PARAMETER;
282 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
283 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
284 return NT_STATUS_INVALID_PARAMETER;
287 if (!sock->ops->fn_sendto) {
288 return NT_STATUS_NOT_IMPLEMENTED;
291 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
296 ask for the number of bytes in a pending incoming packet
298 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
300 if (sock == NULL) {
301 return NT_STATUS_CONNECTION_DISCONNECTED;
303 if (!sock->ops->fn_pending) {
304 return NT_STATUS_NOT_IMPLEMENTED;
306 return sock->ops->fn_pending(sock, npending);
310 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
312 if (sock == NULL) {
313 return NT_STATUS_CONNECTION_DISCONNECTED;
315 if (!sock->ops->fn_set_option) {
316 return NT_STATUS_NOT_IMPLEMENTED;
319 return sock->ops->fn_set_option(sock, option, val);
322 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
324 if (!sock->ops->fn_get_peer_name) {
325 return NULL;
328 return sock->ops->fn_get_peer_name(sock, mem_ctx);
331 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
333 if (!sock->ops->fn_get_peer_addr) {
334 return NULL;
337 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
340 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
342 if (!sock->ops->fn_get_my_addr) {
343 return NULL;
346 return sock->ops->fn_get_my_addr(sock, mem_ctx);
349 _PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
350 const struct socket_address *a)
352 struct tsocket_address *r;
353 int ret;
355 if (!a) {
356 return NULL;
358 if (a->sockaddr) {
359 ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
360 a->sockaddr,
361 a->sockaddrlen,
362 &r);
363 } else {
364 ret = tsocket_address_inet_from_strings(mem_ctx,
365 a->family,
366 a->addr,
367 a->port,
368 &r);
371 if (ret != 0) {
372 return NULL;
375 return r;
378 _PUBLIC_ void socket_address_set_port(struct socket_address *a,
379 uint16_t port)
381 if (a->sockaddr) {
382 set_sockaddr_port(a->sockaddr, port);
383 } else {
384 a->port = port;
389 _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
390 const struct tsocket_address *a)
392 ssize_t ret;
393 struct sockaddr_storage ss;
394 size_t sslen = sizeof(ss);
396 ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
397 if (ret < 0) {
398 return NULL;
401 return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
404 _PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
406 struct socket_address *a;
407 struct tsocket_address *r;
409 a = socket_get_peer_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_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
421 struct socket_address *a;
422 struct tsocket_address *r;
424 a = socket_get_my_addr(sock, mem_ctx);
425 if (a == NULL) {
426 return NULL;
429 r = socket_address_to_tsocket_address(mem_ctx, a);
430 talloc_free(a);
431 return r;
434 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
436 if (!sock->ops->fn_get_fd) {
437 return -1;
440 return sock->ops->fn_get_fd(sock);
444 call dup() on a socket, and close the old fd. This is used to change
445 the fd to the lowest available number, to make select() more
446 efficient (select speed depends on the maxiumum fd number passed to
449 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
451 int fd;
452 if (sock->fd == -1) {
453 return NT_STATUS_INVALID_HANDLE;
455 fd = dup(sock->fd);
456 if (fd == -1) {
457 return map_nt_error_from_unix_common(errno);
459 close(sock->fd);
460 sock->fd = fd;
461 return NT_STATUS_OK;
465 /* Create a new socket_address. The type must match the socket type.
466 * The host parameter may be an IP or a hostname
469 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
470 const char *family,
471 const char *host,
472 int port)
474 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
475 if (!addr) {
476 return NULL;
479 if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) {
480 /* leaving as "ip" would force IPv4 */
481 family = "ipv6";
484 addr->family = family;
485 addr->addr = talloc_strdup(addr, host);
486 if (!addr->addr) {
487 talloc_free(addr);
488 return NULL;
490 addr->port = port;
491 addr->sockaddr = NULL;
492 addr->sockaddrlen = 0;
494 return addr;
497 /* Create a new socket_address. Copy the struct sockaddr into the new
498 * structure. Used for hooks in the kerberos libraries, where they
499 * supply only a struct sockaddr */
501 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
502 struct sockaddr *sockaddr,
503 size_t sockaddrlen)
505 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
506 if (!addr) {
507 return NULL;
509 switch (sockaddr->sa_family) {
510 case AF_INET:
511 addr->family = "ipv4";
512 break;
513 #ifdef HAVE_IPV6
514 case AF_INET6:
515 addr->family = "ipv6";
516 break;
517 #endif
518 case AF_UNIX:
519 addr->family = "unix";
520 break;
522 addr->addr = NULL;
523 addr->port = 0;
524 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
525 if (!addr->sockaddr) {
526 talloc_free(addr);
527 return NULL;
529 addr->sockaddrlen = sockaddrlen;
530 return addr;
535 Create a new socket_address from sockaddr_storage
537 _PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx,
538 const struct sockaddr_storage *sockaddr,
539 uint16_t port)
541 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
542 char addr_str[INET6_ADDRSTRLEN+1];
543 const char *str;
545 if (!addr) {
546 return NULL;
548 addr->port = port;
549 switch (sockaddr->ss_family) {
550 case AF_INET:
551 addr->family = "ipv4";
552 break;
553 #ifdef HAVE_IPV6
554 case AF_INET6:
555 addr->family = "ipv6";
556 break;
557 #endif
558 default:
559 talloc_free(addr);
560 return NULL;
563 str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr);
564 if (str == NULL) {
565 talloc_free(addr);
566 return NULL;
568 addr->addr = talloc_strdup(addr, str);
569 if (addr->addr == NULL) {
570 talloc_free(addr);
571 return NULL;
574 return addr;
577 /* Copy a socket_address structure */
578 struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
579 const struct socket_address *oaddr)
581 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
582 if (!addr) {
583 return NULL;
585 addr->family = oaddr->family;
586 if (oaddr->addr) {
587 addr->addr = talloc_strdup(addr, oaddr->addr);
588 if (!addr->addr) {
589 goto nomem;
592 addr->port = oaddr->port;
593 if (oaddr->sockaddr) {
594 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
595 oaddr->sockaddr,
596 oaddr->sockaddrlen);
597 if (!addr->sockaddr) {
598 goto nomem;
600 addr->sockaddrlen = oaddr->sockaddrlen;
603 return addr;
605 nomem:
606 talloc_free(addr);
607 return NULL;
610 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
612 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
613 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
614 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
616 if (strcmp("ip", family) == 0 ||
617 strcmp("ipv4", family) == 0) {
618 return socket_ipv4_ops(type);
621 #if HAVE_IPV6
622 if (strcmp("ipv6", family) == 0) {
623 return socket_ipv6_ops(type);
625 #endif
627 if (strcmp("unix", family) == 0) {
628 return socket_unixdom_ops(type);
631 return NULL;
635 set some flags on a socket
637 void socket_set_flags(struct socket_context *sock, unsigned flags)
639 sock->flags |= flags;