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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "lib/socket/socket.h"
25 #include "system/filesys.h"
26 #include "system/network.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(-1, "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);
174 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
175 size_t wantlen, size_t *nread)
178 return NT_STATUS_CONNECTION_DISCONNECTED;
180 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
181 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
182 sock->type != SOCKET_TYPE_DGRAM) {
183 return NT_STATUS_INVALID_PARAMETER;
186 if (!sock->ops->fn_recv) {
187 return NT_STATUS_NOT_IMPLEMENTED;
190 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
193 if (random() % 10 == 0) {
195 return STATUS_MORE_ENTRIES;
197 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
199 return sock->ops->fn_recv(sock, buf, wantlen, nread);
202 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
203 size_t wantlen, size_t *nread,
204 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
207 return NT_STATUS_CONNECTION_DISCONNECTED;
209 if (sock->type != SOCKET_TYPE_DGRAM) {
210 return NT_STATUS_INVALID_PARAMETER;
213 if (!sock->ops->fn_recvfrom) {
214 return NT_STATUS_NOT_IMPLEMENTED;
217 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
221 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
222 const DATA_BLOB *blob, size_t *sendlen)
225 return NT_STATUS_CONNECTION_DISCONNECTED;
227 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
228 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
229 return NT_STATUS_INVALID_PARAMETER;
232 if (!sock->ops->fn_send) {
233 return NT_STATUS_NOT_IMPLEMENTED;
236 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
237 && blob->length > 1) {
238 DATA_BLOB blob2 = *blob;
239 if (random() % 10 == 0) {
241 return STATUS_MORE_ENTRIES;
243 /* The random size sends are incompatible with TLS and SASL
244 * sockets, which require re-sends to be consistant */
245 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
246 blob2.length = 1+(random() % blob2.length);
248 /* This is particularly stressful on buggy
249 * LDAP clients, that don't expect on LDAP
250 * packet in many SASL packets */
251 blob2.length = 1 + blob2.length/2;
253 return sock->ops->fn_send(sock, &blob2, sendlen);
255 return sock->ops->fn_send(sock, blob, sendlen);
259 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
260 const DATA_BLOB *blob, size_t *sendlen,
261 const struct socket_address *dest_addr)
264 return NT_STATUS_CONNECTION_DISCONNECTED;
266 if (sock->type != SOCKET_TYPE_DGRAM) {
267 return NT_STATUS_INVALID_PARAMETER;
270 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
271 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
272 return NT_STATUS_INVALID_PARAMETER;
275 if (!sock->ops->fn_sendto) {
276 return NT_STATUS_NOT_IMPLEMENTED;
279 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
284 ask for the number of bytes in a pending incoming packet
286 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
289 return NT_STATUS_CONNECTION_DISCONNECTED;
291 if (!sock->ops->fn_pending) {
292 return NT_STATUS_NOT_IMPLEMENTED;
294 return sock->ops->fn_pending(sock, npending);
298 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
301 return NT_STATUS_CONNECTION_DISCONNECTED;
303 if (!sock->ops->fn_set_option) {
304 return NT_STATUS_NOT_IMPLEMENTED;
307 return sock->ops->fn_set_option(sock, option, val);
310 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
312 if (!sock->ops->fn_get_peer_name) {
316 return sock->ops->fn_get_peer_name(sock, mem_ctx);
319 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
321 if (!sock->ops->fn_get_peer_addr) {
325 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
328 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
330 if (!sock->ops->fn_get_my_addr) {
334 return sock->ops->fn_get_my_addr(sock, mem_ctx);
337 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
339 if (!sock->ops->fn_get_fd) {
343 return sock->ops->fn_get_fd(sock);
347 call dup() on a socket, and close the old fd. This is used to change
348 the fd to the lowest available number, to make select() more
349 efficient (select speed depends on the maxiumum fd number passed to
352 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
355 if (sock->fd == -1) {
356 return NT_STATUS_INVALID_HANDLE;
360 return map_nt_error_from_unix(errno);
368 /* Create a new socket_address. The type must match the socket type.
369 * The host parameter may be an IP or a hostname
372 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
377 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
382 addr->family = family;
383 addr->addr = talloc_strdup(addr, host);
389 addr->sockaddr = NULL;
390 addr->sockaddrlen = 0;
395 /* Create a new socket_address. Copy the struct sockaddr into the new
396 * structure. Used for hooks in the kerberos libraries, where they
397 * supply only a struct sockaddr */
399 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
400 struct sockaddr *sockaddr,
403 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
410 addr->sockaddr = talloc_memdup(addr, sockaddr, sockaddrlen);
411 if (!addr->sockaddr) {
415 addr->sockaddrlen = sockaddrlen;
419 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
421 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
422 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
423 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
425 if (strcmp("ip", family) == 0 ||
426 strcmp("ipv4", family) == 0) {
427 return socket_ipv4_ops(type);
431 if (strcmp("ipv6", family) == 0) {
432 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
433 DEBUG(3, ("IPv6 support was disabled in smb.conf"));
436 return socket_ipv6_ops(type);
440 if (strcmp("unix", family) == 0) {
441 return socket_unixdom_ops(type);
447 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
449 static const struct {
455 } socket_options[] = {
456 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
457 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
458 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
460 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
462 #ifdef IPTOS_LOWDELAY
463 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
465 #ifdef IPTOS_THROUGHPUT
466 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
469 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
472 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
475 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
478 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
481 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
484 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
487 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
493 Set user socket options.
495 _PUBLIC_ void set_socket_options(int fd, const char *options)
497 const char **options_list = str_list_make(NULL, options, " \t,");
503 for (j = 0; options_list[j]; j++) {
504 const char *tok = options_list[j];
508 BOOL got_value = False;
510 if ((p = strchr(tok,'='))) {
516 for (i=0;socket_options[i].name;i++)
517 if (strequal(socket_options[i].name,tok))
520 if (!socket_options[i].name) {
521 DEBUG(0,("Unknown socket option %s\n",tok));
525 switch (socket_options[i].opttype) {
528 ret = setsockopt(fd,socket_options[i].level,
529 socket_options[i].option,(char *)&value,sizeof(int));
534 DEBUG(0,("syntax error - %s does not take a value\n",tok));
537 int on = socket_options[i].value;
538 ret = setsockopt(fd,socket_options[i].level,
539 socket_options[i].option,(char *)&on,sizeof(int));
545 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
548 talloc_free(options_list);
552 set some flags on a socket
554 void socket_set_flags(struct socket_context *sock, unsigned flags)
556 sock->flags |= flags;