2 Unix SMB/CIFS implementation.
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/>.
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);
41 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
42 struct tevent_fd *fde,
46 /* this might be the socket_wrapper swrap_close() */
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)
56 (*new_sock) = talloc(mem_ctx, struct socket_context);
58 return NT_STATUS_NO_MEMORY;
61 (*new_sock)->type = type;
62 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
63 (*new_sock)->flags = flags;
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);
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);
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);
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,
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)
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)
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;
185 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
186 size_t wantlen, size_t *nread)
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)
204 if (random() % 10 == 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)
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,
232 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
233 const DATA_BLOB *blob, size_t *sendlen)
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) {
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);
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)
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)
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)
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) {
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) {
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) {
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;
355 ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
360 ret = tsocket_address_inet_from_strings(mem_ctx,
374 _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
375 const struct tsocket_address *a)
378 struct sockaddr_storage ss;
379 size_t sslen = sizeof(ss);
381 ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
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);
399 r = socket_address_to_tsocket_address(mem_ctx, a);
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);
414 r = socket_address_to_tsocket_address(mem_ctx, a);
419 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
421 if (!sock->ops->fn_get_fd) {
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)
437 if (sock->fd == -1) {
438 return NT_STATUS_INVALID_HANDLE;
442 return map_nt_error_from_unix(errno);
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,
459 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
464 addr->family = family;
465 addr->addr = talloc_strdup(addr, host);
471 addr->sockaddr = NULL;
472 addr->sockaddrlen = 0;
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,
485 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
492 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
493 if (!addr->sockaddr) {
497 addr->sockaddrlen = sockaddrlen;
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);
509 addr->family = oaddr->family;
511 addr->addr = talloc_strdup(addr, oaddr->addr);
516 addr->port = oaddr->port;
517 if (oaddr->sockaddr) {
518 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
521 if (!addr->sockaddr) {
524 addr->sockaddrlen = oaddr->sockaddrlen;
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);
546 if (strcmp("ipv6", family) == 0) {
547 return socket_ipv6_ops(type);
551 if (strcmp("unix", family) == 0) {
552 return socket_unixdom_ops(type);
558 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
560 static const struct {
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},
571 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
573 #ifdef IPTOS_LOWDELAY
574 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
576 #ifdef IPTOS_THROUGHPUT
577 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
580 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
583 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
586 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
589 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
592 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
595 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
598 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
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,");
614 for (j = 0; options_list[j]; j++) {
615 const char *tok = options_list[j];
619 bool got_value = false;
621 if ((p = strchr(tok,'='))) {
627 for (i=0;socket_options[i].name;i++)
628 if (strequal(socket_options[i].name,tok))
631 if (!socket_options[i].name) {
632 DEBUG(0,("Unknown socket option %s\n",tok));
636 switch (socket_options[i].opttype) {
639 ret = setsockopt(fd,socket_options[i].level,
640 socket_options[i].option,(char *)&value,sizeof(int));
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));
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;