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"
29 auto-close sockets on free
31 static int socket_destructor(struct socket_context *sock)
33 if (sock->ops->fn_close &&
34 !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
35 sock->ops->fn_close(sock);
40 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
41 struct socket_context **new_sock,
42 enum socket_type type, uint32_t flags)
46 (*new_sock) = talloc(mem_ctx, struct socket_context);
48 return NT_STATUS_NO_MEMORY;
51 (*new_sock)->type = type;
52 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
53 (*new_sock)->flags = flags;
57 (*new_sock)->private_data = NULL;
58 (*new_sock)->ops = ops;
59 (*new_sock)->backend_name = NULL;
61 status = (*new_sock)->ops->fn_init((*new_sock));
62 if (!NT_STATUS_IS_OK(status)) {
63 talloc_free(*new_sock);
67 /* by enabling "testnonblock" mode, all socket receive and
68 send calls on non-blocking sockets will randomly recv/send
69 less data than requested */
71 if (!(flags & SOCKET_FLAG_BLOCK) &&
72 type == SOCKET_TYPE_STREAM &&
73 lp_parm_bool(global_loadparm, NULL, "socket", "testnonblock", false)) {
74 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
77 /* we don't do a connect() on dgram sockets, so need to set
78 non-blocking at socket create time */
79 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
80 set_blocking(socket_get_fd(*new_sock), false);
83 talloc_set_destructor(*new_sock, socket_destructor);
88 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
89 struct socket_context **new_sock, uint32_t flags)
91 const struct socket_ops *ops;
93 ops = socket_getops_byname(name, type);
95 return NT_STATUS_INVALID_PARAMETER;
98 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
101 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
102 const struct socket_address *my_address,
103 const struct socket_address *server_address,
107 return NT_STATUS_CONNECTION_DISCONNECTED;
109 if (sock->state != SOCKET_STATE_UNDEFINED) {
110 return NT_STATUS_INVALID_PARAMETER;
113 if (!sock->ops->fn_connect) {
114 return NT_STATUS_NOT_IMPLEMENTED;
117 return sock->ops->fn_connect(sock, my_address, server_address, flags);
120 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
122 if (!sock->ops->fn_connect_complete) {
123 return NT_STATUS_NOT_IMPLEMENTED;
125 return sock->ops->fn_connect_complete(sock, flags);
128 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
129 const struct socket_address *my_address,
130 int queue_size, uint32_t flags)
133 return NT_STATUS_CONNECTION_DISCONNECTED;
135 if (sock->state != SOCKET_STATE_UNDEFINED) {
136 return NT_STATUS_INVALID_PARAMETER;
139 if (!sock->ops->fn_listen) {
140 return NT_STATUS_NOT_IMPLEMENTED;
143 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
146 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
151 return NT_STATUS_CONNECTION_DISCONNECTED;
153 if (sock->type != SOCKET_TYPE_STREAM) {
154 return NT_STATUS_INVALID_PARAMETER;
157 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
158 return NT_STATUS_INVALID_PARAMETER;
161 if (!sock->ops->fn_accept) {
162 return NT_STATUS_NOT_IMPLEMENTED;
165 status = sock->ops->fn_accept(sock, new_sock);
167 if (NT_STATUS_IS_OK(status)) {
168 talloc_set_destructor(*new_sock, socket_destructor);
169 (*new_sock)->flags = 0;
175 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
176 size_t wantlen, size_t *nread)
179 return NT_STATUS_CONNECTION_DISCONNECTED;
181 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
182 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
183 sock->type != SOCKET_TYPE_DGRAM) {
184 return NT_STATUS_INVALID_PARAMETER;
187 if (!sock->ops->fn_recv) {
188 return NT_STATUS_NOT_IMPLEMENTED;
191 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
194 if (random() % 10 == 0) {
196 return STATUS_MORE_ENTRIES;
198 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
200 return sock->ops->fn_recv(sock, buf, wantlen, nread);
203 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
204 size_t wantlen, size_t *nread,
205 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
208 return NT_STATUS_CONNECTION_DISCONNECTED;
210 if (sock->type != SOCKET_TYPE_DGRAM) {
211 return NT_STATUS_INVALID_PARAMETER;
214 if (!sock->ops->fn_recvfrom) {
215 return NT_STATUS_NOT_IMPLEMENTED;
218 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
222 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
223 const DATA_BLOB *blob, size_t *sendlen)
226 return NT_STATUS_CONNECTION_DISCONNECTED;
228 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
229 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
230 return NT_STATUS_INVALID_PARAMETER;
233 if (!sock->ops->fn_send) {
234 return NT_STATUS_NOT_IMPLEMENTED;
237 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
238 && blob->length > 1) {
239 DATA_BLOB blob2 = *blob;
240 if (random() % 10 == 0) {
242 return STATUS_MORE_ENTRIES;
244 /* The random size sends are incompatible with TLS and SASL
245 * sockets, which require re-sends to be consistant */
246 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
247 blob2.length = 1+(random() % blob2.length);
249 /* This is particularly stressful on buggy
250 * LDAP clients, that don't expect on LDAP
251 * packet in many SASL packets */
252 blob2.length = 1 + blob2.length/2;
254 return sock->ops->fn_send(sock, &blob2, sendlen);
256 return sock->ops->fn_send(sock, blob, sendlen);
260 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
261 const DATA_BLOB *blob, size_t *sendlen,
262 const struct socket_address *dest_addr)
265 return NT_STATUS_CONNECTION_DISCONNECTED;
267 if (sock->type != SOCKET_TYPE_DGRAM) {
268 return NT_STATUS_INVALID_PARAMETER;
271 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
272 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
273 return NT_STATUS_INVALID_PARAMETER;
276 if (!sock->ops->fn_sendto) {
277 return NT_STATUS_NOT_IMPLEMENTED;
280 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
285 ask for the number of bytes in a pending incoming packet
287 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
290 return NT_STATUS_CONNECTION_DISCONNECTED;
292 if (!sock->ops->fn_pending) {
293 return NT_STATUS_NOT_IMPLEMENTED;
295 return sock->ops->fn_pending(sock, npending);
299 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
302 return NT_STATUS_CONNECTION_DISCONNECTED;
304 if (!sock->ops->fn_set_option) {
305 return NT_STATUS_NOT_IMPLEMENTED;
308 return sock->ops->fn_set_option(sock, option, val);
311 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
313 if (!sock->ops->fn_get_peer_name) {
317 return sock->ops->fn_get_peer_name(sock, mem_ctx);
320 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
322 if (!sock->ops->fn_get_peer_addr) {
326 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
329 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
331 if (!sock->ops->fn_get_my_addr) {
335 return sock->ops->fn_get_my_addr(sock, mem_ctx);
338 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
340 if (!sock->ops->fn_get_fd) {
344 return sock->ops->fn_get_fd(sock);
348 call dup() on a socket, and close the old fd. This is used to change
349 the fd to the lowest available number, to make select() more
350 efficient (select speed depends on the maxiumum fd number passed to
353 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
356 if (sock->fd == -1) {
357 return NT_STATUS_INVALID_HANDLE;
361 return map_nt_error_from_unix(errno);
369 /* Create a new socket_address. The type must match the socket type.
370 * The host parameter may be an IP or a hostname
373 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
378 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
383 addr->family = family;
384 addr->addr = talloc_strdup(addr, host);
390 addr->sockaddr = NULL;
391 addr->sockaddrlen = 0;
396 /* Create a new socket_address. Copy the struct sockaddr into the new
397 * structure. Used for hooks in the kerberos libraries, where they
398 * supply only a struct sockaddr */
400 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
401 struct sockaddr *sockaddr,
404 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
411 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
412 if (!addr->sockaddr) {
416 addr->sockaddrlen = sockaddrlen;
420 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
422 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
423 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
424 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
426 if (strcmp("ip", family) == 0 ||
427 strcmp("ipv4", family) == 0) {
428 return socket_ipv4_ops(type);
432 if (strcmp("ipv6", family) == 0) {
433 return socket_ipv6_ops(type);
437 if (strcmp("unix", family) == 0) {
438 return socket_unixdom_ops(type);
444 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
446 static const struct {
452 } socket_options[] = {
453 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
454 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
455 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
457 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
459 #ifdef IPTOS_LOWDELAY
460 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
462 #ifdef IPTOS_THROUGHPUT
463 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
466 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
469 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
472 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
475 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
478 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
481 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
484 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
490 Set user socket options.
492 _PUBLIC_ void set_socket_options(int fd, const char *options)
494 const char **options_list = (const char **)str_list_make(NULL, options, " \t,");
500 for (j = 0; options_list[j]; j++) {
501 const char *tok = options_list[j];
505 bool got_value = false;
507 if ((p = strchr(tok,'='))) {
513 for (i=0;socket_options[i].name;i++)
514 if (strequal(socket_options[i].name,tok))
517 if (!socket_options[i].name) {
518 DEBUG(0,("Unknown socket option %s\n",tok));
522 switch (socket_options[i].opttype) {
525 ret = setsockopt(fd,socket_options[i].level,
526 socket_options[i].option,(char *)&value,sizeof(int));
531 DEBUG(0,("syntax error - %s does not take a value\n",tok));
534 int on = socket_options[i].value;
535 ret = setsockopt(fd,socket_options[i].level,
536 socket_options[i].option,(char *)&on,sizeof(int));
542 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
545 talloc_free(options_list);
549 set some flags on a socket
551 void socket_set_flags(struct socket_context *sock, unsigned flags)
553 sock->flags |= flags;