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_
void socket_tevent_fd_close_fn(struct tevent_context
*ev
,
41 struct tevent_fd
*fde
,
45 /* this might be the socket_wrapper swrap_close() */
49 _PUBLIC_ NTSTATUS
socket_create_with_ops(TALLOC_CTX
*mem_ctx
, const struct socket_ops
*ops
,
50 struct socket_context
**new_sock
,
51 enum socket_type type
, uint32_t flags
)
55 (*new_sock
) = talloc(mem_ctx
, struct socket_context
);
57 return NT_STATUS_NO_MEMORY
;
60 (*new_sock
)->type
= type
;
61 (*new_sock
)->state
= SOCKET_STATE_UNDEFINED
;
62 (*new_sock
)->flags
= flags
;
66 (*new_sock
)->private_data
= NULL
;
67 (*new_sock
)->ops
= ops
;
68 (*new_sock
)->backend_name
= NULL
;
70 status
= (*new_sock
)->ops
->fn_init((*new_sock
));
71 if (!NT_STATUS_IS_OK(status
)) {
72 talloc_free(*new_sock
);
76 /* by enabling "testnonblock" mode, all socket receive and
77 send calls on non-blocking sockets will randomly recv/send
78 less data than requested */
80 if (!(flags
& SOCKET_FLAG_BLOCK
) &&
81 type
== SOCKET_TYPE_STREAM
&&
82 getenv("SOCKET_TESTNONBLOCK") != NULL
) {
83 (*new_sock
)->flags
|= SOCKET_FLAG_TESTNONBLOCK
;
86 /* we don't do a connect() on dgram sockets, so need to set
87 non-blocking at socket create time */
88 if (!(flags
& SOCKET_FLAG_BLOCK
) && type
== SOCKET_TYPE_DGRAM
) {
89 set_blocking(socket_get_fd(*new_sock
), false);
92 talloc_set_destructor(*new_sock
, socket_destructor
);
97 _PUBLIC_ NTSTATUS
socket_create(const char *name
, enum socket_type type
,
98 struct socket_context
**new_sock
, uint32_t flags
)
100 const struct socket_ops
*ops
;
102 ops
= socket_getops_byname(name
, type
);
104 return NT_STATUS_INVALID_PARAMETER
;
107 return socket_create_with_ops(NULL
, ops
, new_sock
, type
, flags
);
110 _PUBLIC_ NTSTATUS
socket_connect(struct socket_context
*sock
,
111 const struct socket_address
*my_address
,
112 const struct socket_address
*server_address
,
116 return NT_STATUS_CONNECTION_DISCONNECTED
;
118 if (sock
->state
!= SOCKET_STATE_UNDEFINED
) {
119 return NT_STATUS_INVALID_PARAMETER
;
122 if (!sock
->ops
->fn_connect
) {
123 return NT_STATUS_NOT_IMPLEMENTED
;
126 return sock
->ops
->fn_connect(sock
, my_address
, server_address
, flags
);
129 _PUBLIC_ NTSTATUS
socket_connect_complete(struct socket_context
*sock
, uint32_t flags
)
131 if (!sock
->ops
->fn_connect_complete
) {
132 return NT_STATUS_NOT_IMPLEMENTED
;
134 return sock
->ops
->fn_connect_complete(sock
, flags
);
137 _PUBLIC_ NTSTATUS
socket_listen(struct socket_context
*sock
,
138 const struct socket_address
*my_address
,
139 int queue_size
, uint32_t flags
)
142 return NT_STATUS_CONNECTION_DISCONNECTED
;
144 if (sock
->state
!= SOCKET_STATE_UNDEFINED
) {
145 return NT_STATUS_INVALID_PARAMETER
;
148 if (!sock
->ops
->fn_listen
) {
149 return NT_STATUS_NOT_IMPLEMENTED
;
152 return sock
->ops
->fn_listen(sock
, my_address
, queue_size
, flags
);
155 _PUBLIC_ NTSTATUS
socket_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
160 return NT_STATUS_CONNECTION_DISCONNECTED
;
162 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
163 return NT_STATUS_INVALID_PARAMETER
;
166 if (sock
->state
!= SOCKET_STATE_SERVER_LISTEN
) {
167 return NT_STATUS_INVALID_PARAMETER
;
170 if (!sock
->ops
->fn_accept
) {
171 return NT_STATUS_NOT_IMPLEMENTED
;
174 status
= sock
->ops
->fn_accept(sock
, new_sock
);
176 if (NT_STATUS_IS_OK(status
)) {
177 talloc_set_destructor(*new_sock
, socket_destructor
);
178 (*new_sock
)->flags
= 0;
184 _PUBLIC_ NTSTATUS
socket_recv(struct socket_context
*sock
, void *buf
,
185 size_t wantlen
, size_t *nread
)
188 return NT_STATUS_CONNECTION_DISCONNECTED
;
190 if (sock
->state
!= SOCKET_STATE_CLIENT_CONNECTED
&&
191 sock
->state
!= SOCKET_STATE_SERVER_CONNECTED
&&
192 sock
->type
!= SOCKET_TYPE_DGRAM
) {
193 return NT_STATUS_INVALID_PARAMETER
;
196 if (!sock
->ops
->fn_recv
) {
197 return NT_STATUS_NOT_IMPLEMENTED
;
200 if ((sock
->flags
& SOCKET_FLAG_TESTNONBLOCK
)
203 if (random() % 10 == 0) {
205 return STATUS_MORE_ENTRIES
;
207 return sock
->ops
->fn_recv(sock
, buf
, 1+(random() % wantlen
), nread
);
209 return sock
->ops
->fn_recv(sock
, buf
, wantlen
, nread
);
212 _PUBLIC_ NTSTATUS
socket_recvfrom(struct socket_context
*sock
, void *buf
,
213 size_t wantlen
, size_t *nread
,
214 TALLOC_CTX
*mem_ctx
, struct socket_address
**src_addr
)
217 return NT_STATUS_CONNECTION_DISCONNECTED
;
219 if (sock
->type
!= SOCKET_TYPE_DGRAM
) {
220 return NT_STATUS_INVALID_PARAMETER
;
223 if (!sock
->ops
->fn_recvfrom
) {
224 return NT_STATUS_NOT_IMPLEMENTED
;
227 return sock
->ops
->fn_recvfrom(sock
, buf
, wantlen
, nread
,
231 _PUBLIC_ NTSTATUS
socket_send(struct socket_context
*sock
,
232 const DATA_BLOB
*blob
, size_t *sendlen
)
235 return NT_STATUS_CONNECTION_DISCONNECTED
;
237 if (sock
->state
!= SOCKET_STATE_CLIENT_CONNECTED
&&
238 sock
->state
!= SOCKET_STATE_SERVER_CONNECTED
) {
239 return NT_STATUS_INVALID_PARAMETER
;
242 if (!sock
->ops
->fn_send
) {
243 return NT_STATUS_NOT_IMPLEMENTED
;
246 if ((sock
->flags
& SOCKET_FLAG_TESTNONBLOCK
)
247 && blob
->length
> 1) {
248 DATA_BLOB blob2
= *blob
;
249 if (random() % 10 == 0) {
251 return STATUS_MORE_ENTRIES
;
253 /* The random size sends are incompatible with TLS and SASL
254 * sockets, which require re-sends to be consistant */
255 if (!(sock
->flags
& SOCKET_FLAG_ENCRYPT
)) {
256 blob2
.length
= 1+(random() % blob2
.length
);
258 /* This is particularly stressful on buggy
259 * LDAP clients, that don't expect on LDAP
260 * packet in many SASL packets */
261 blob2
.length
= 1 + blob2
.length
/2;
263 return sock
->ops
->fn_send(sock
, &blob2
, sendlen
);
265 return sock
->ops
->fn_send(sock
, blob
, sendlen
);
269 _PUBLIC_ NTSTATUS
socket_sendto(struct socket_context
*sock
,
270 const DATA_BLOB
*blob
, size_t *sendlen
,
271 const struct socket_address
*dest_addr
)
274 return NT_STATUS_CONNECTION_DISCONNECTED
;
276 if (sock
->type
!= SOCKET_TYPE_DGRAM
) {
277 return NT_STATUS_INVALID_PARAMETER
;
280 if (sock
->state
== SOCKET_STATE_CLIENT_CONNECTED
||
281 sock
->state
== SOCKET_STATE_SERVER_CONNECTED
) {
282 return NT_STATUS_INVALID_PARAMETER
;
285 if (!sock
->ops
->fn_sendto
) {
286 return NT_STATUS_NOT_IMPLEMENTED
;
289 return sock
->ops
->fn_sendto(sock
, blob
, sendlen
, dest_addr
);
294 ask for the number of bytes in a pending incoming packet
296 _PUBLIC_ NTSTATUS
socket_pending(struct socket_context
*sock
, size_t *npending
)
299 return NT_STATUS_CONNECTION_DISCONNECTED
;
301 if (!sock
->ops
->fn_pending
) {
302 return NT_STATUS_NOT_IMPLEMENTED
;
304 return sock
->ops
->fn_pending(sock
, npending
);
308 _PUBLIC_ NTSTATUS
socket_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
311 return NT_STATUS_CONNECTION_DISCONNECTED
;
313 if (!sock
->ops
->fn_set_option
) {
314 return NT_STATUS_NOT_IMPLEMENTED
;
317 return sock
->ops
->fn_set_option(sock
, option
, val
);
320 _PUBLIC_
char *socket_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
322 if (!sock
->ops
->fn_get_peer_name
) {
326 return sock
->ops
->fn_get_peer_name(sock
, mem_ctx
);
329 _PUBLIC_
struct socket_address
*socket_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
331 if (!sock
->ops
->fn_get_peer_addr
) {
335 return sock
->ops
->fn_get_peer_addr(sock
, mem_ctx
);
338 _PUBLIC_
struct socket_address
*socket_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
340 if (!sock
->ops
->fn_get_my_addr
) {
344 return sock
->ops
->fn_get_my_addr(sock
, mem_ctx
);
347 _PUBLIC_
int socket_get_fd(struct socket_context
*sock
)
349 if (!sock
->ops
->fn_get_fd
) {
353 return sock
->ops
->fn_get_fd(sock
);
357 call dup() on a socket, and close the old fd. This is used to change
358 the fd to the lowest available number, to make select() more
359 efficient (select speed depends on the maxiumum fd number passed to
362 _PUBLIC_ NTSTATUS
socket_dup(struct socket_context
*sock
)
365 if (sock
->fd
== -1) {
366 return NT_STATUS_INVALID_HANDLE
;
370 return map_nt_error_from_unix(errno
);
378 /* Create a new socket_address. The type must match the socket type.
379 * The host parameter may be an IP or a hostname
382 _PUBLIC_
struct socket_address
*socket_address_from_strings(TALLOC_CTX
*mem_ctx
,
387 struct socket_address
*addr
= talloc(mem_ctx
, struct socket_address
);
392 addr
->family
= family
;
393 addr
->addr
= talloc_strdup(addr
, host
);
399 addr
->sockaddr
= NULL
;
400 addr
->sockaddrlen
= 0;
405 /* Create a new socket_address. Copy the struct sockaddr into the new
406 * structure. Used for hooks in the kerberos libraries, where they
407 * supply only a struct sockaddr */
409 _PUBLIC_
struct socket_address
*socket_address_from_sockaddr(TALLOC_CTX
*mem_ctx
,
410 struct sockaddr
*sockaddr
,
413 struct socket_address
*addr
= talloc(mem_ctx
, struct socket_address
);
420 addr
->sockaddr
= (struct sockaddr
*)talloc_memdup(addr
, sockaddr
, sockaddrlen
);
421 if (!addr
->sockaddr
) {
425 addr
->sockaddrlen
= sockaddrlen
;
429 /* Copy a socket_address structure */
430 struct socket_address
*socket_address_copy(TALLOC_CTX
*mem_ctx
,
431 const struct socket_address
*oaddr
)
433 struct socket_address
*addr
= talloc_zero(mem_ctx
, struct socket_address
);
437 addr
->family
= oaddr
->family
;
439 addr
->addr
= talloc_strdup(addr
, oaddr
->addr
);
444 addr
->port
= oaddr
->port
;
445 if (oaddr
->sockaddr
) {
446 addr
->sockaddr
= (struct sockaddr
*)talloc_memdup(addr
,
449 if (!addr
->sockaddr
) {
452 addr
->sockaddrlen
= oaddr
->sockaddrlen
;
462 _PUBLIC_
const struct socket_ops
*socket_getops_byname(const char *family
, enum socket_type type
)
464 extern const struct socket_ops
*socket_ipv4_ops(enum socket_type
);
465 extern const struct socket_ops
*socket_ipv6_ops(enum socket_type
);
466 extern const struct socket_ops
*socket_unixdom_ops(enum socket_type
);
468 if (strcmp("ip", family
) == 0 ||
469 strcmp("ipv4", family
) == 0) {
470 return socket_ipv4_ops(type
);
474 if (strcmp("ipv6", family
) == 0) {
475 return socket_ipv6_ops(type
);
479 if (strcmp("unix", family
) == 0) {
480 return socket_unixdom_ops(type
);
486 enum SOCK_OPT_TYPES
{OPT_BOOL
,OPT_INT
,OPT_ON
};
488 static const struct {
494 } socket_options
[] = {
495 {"SO_KEEPALIVE", SOL_SOCKET
, SO_KEEPALIVE
, 0, OPT_BOOL
},
496 {"SO_REUSEADDR", SOL_SOCKET
, SO_REUSEADDR
, 0, OPT_BOOL
},
497 {"SO_BROADCAST", SOL_SOCKET
, SO_BROADCAST
, 0, OPT_BOOL
},
499 {"TCP_NODELAY", IPPROTO_TCP
, TCP_NODELAY
, 0, OPT_BOOL
},
501 #ifdef IPTOS_LOWDELAY
502 {"IPTOS_LOWDELAY", IPPROTO_IP
, IP_TOS
, IPTOS_LOWDELAY
, OPT_ON
},
504 #ifdef IPTOS_THROUGHPUT
505 {"IPTOS_THROUGHPUT", IPPROTO_IP
, IP_TOS
, IPTOS_THROUGHPUT
, OPT_ON
},
508 {"SO_REUSEPORT", SOL_SOCKET
, SO_REUSEPORT
, 0, OPT_BOOL
},
511 {"SO_SNDBUF", SOL_SOCKET
, SO_SNDBUF
, 0, OPT_INT
},
514 {"SO_RCVBUF", SOL_SOCKET
, SO_RCVBUF
, 0, OPT_INT
},
517 {"SO_SNDLOWAT", SOL_SOCKET
, SO_SNDLOWAT
, 0, OPT_INT
},
520 {"SO_RCVLOWAT", SOL_SOCKET
, SO_RCVLOWAT
, 0, OPT_INT
},
523 {"SO_SNDTIMEO", SOL_SOCKET
, SO_SNDTIMEO
, 0, OPT_INT
},
526 {"SO_RCVTIMEO", SOL_SOCKET
, SO_RCVTIMEO
, 0, OPT_INT
},
532 Set user socket options.
534 _PUBLIC_
void set_socket_options(int fd
, const char *options
)
536 const char **options_list
= (const char **)str_list_make(NULL
, options
, " \t,");
542 for (j
= 0; options_list
[j
]; j
++) {
543 const char *tok
= options_list
[j
];
547 bool got_value
= false;
549 if ((p
= strchr(tok
,'='))) {
555 for (i
=0;socket_options
[i
].name
;i
++)
556 if (strequal(socket_options
[i
].name
,tok
))
559 if (!socket_options
[i
].name
) {
560 DEBUG(0,("Unknown socket option %s\n",tok
));
564 switch (socket_options
[i
].opttype
) {
567 ret
= setsockopt(fd
,socket_options
[i
].level
,
568 socket_options
[i
].option
,(char *)&value
,sizeof(int));
573 DEBUG(0,("syntax error - %s does not take a value\n",tok
));
576 int on
= socket_options
[i
].value
;
577 ret
= setsockopt(fd
,socket_options
[i
].level
,
578 socket_options
[i
].option
,(char *)&on
,sizeof(int));
584 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok
, strerror(errno
) ));
587 talloc_free(options_list
);
591 set some flags on a socket
593 void socket_set_flags(struct socket_context
*sock
, unsigned flags
)
595 sock
->flags
|= flags
;