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(void *ptr)
33 struct socket_context *sock = ptr;
34 if (sock->ops->fn_close) {
35 sock->ops->fn_close(sock);
40 static 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 */
70 if (!(flags & SOCKET_FLAG_BLOCK) &&
71 type == SOCKET_TYPE_STREAM &&
72 lp_parm_bool(-1, "socket", "testnonblock", False)) {
73 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
76 /* we don't do a connect() on dgram sockets, so need to set
77 non-blocking at socket create time */
78 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
79 set_blocking(socket_get_fd(*new_sock), False);
82 talloc_set_destructor(*new_sock, socket_destructor);
87 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
88 struct socket_context **new_sock, uint32_t flags)
90 const struct socket_ops *ops;
92 ops = socket_getops_byname(name, type);
94 return NT_STATUS_INVALID_PARAMETER;
97 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
100 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
101 const struct socket_address *my_address,
102 const struct socket_address *server_address,
106 return NT_STATUS_CONNECTION_DISCONNECTED;
108 if (sock->state != SOCKET_STATE_UNDEFINED) {
109 return NT_STATUS_INVALID_PARAMETER;
112 if (!sock->ops->fn_connect) {
113 return NT_STATUS_NOT_IMPLEMENTED;
116 return sock->ops->fn_connect(sock, my_address, server_address, flags);
119 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
121 if (!sock->ops->fn_connect_complete) {
122 return NT_STATUS_NOT_IMPLEMENTED;
124 return sock->ops->fn_connect_complete(sock, flags);
127 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
128 const struct socket_address *my_address,
129 int queue_size, uint32_t flags)
132 return NT_STATUS_CONNECTION_DISCONNECTED;
134 if (sock->state != SOCKET_STATE_UNDEFINED) {
135 return NT_STATUS_INVALID_PARAMETER;
138 if (!sock->ops->fn_listen) {
139 return NT_STATUS_NOT_IMPLEMENTED;
142 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
145 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
150 return NT_STATUS_CONNECTION_DISCONNECTED;
152 if (sock->type != SOCKET_TYPE_STREAM) {
153 return NT_STATUS_INVALID_PARAMETER;
156 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
157 return NT_STATUS_INVALID_PARAMETER;
160 if (!sock->ops->fn_accept) {
161 return NT_STATUS_NOT_IMPLEMENTED;
164 status = sock->ops->fn_accept(sock, new_sock);
166 if (NT_STATUS_IS_OK(status)) {
167 talloc_set_destructor(*new_sock, socket_destructor);
173 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
174 size_t wantlen, size_t *nread, uint32_t flags)
177 return NT_STATUS_CONNECTION_DISCONNECTED;
179 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
180 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
181 sock->type != SOCKET_TYPE_DGRAM) {
182 return NT_STATUS_INVALID_PARAMETER;
185 if (!sock->ops->fn_recv) {
186 return NT_STATUS_NOT_IMPLEMENTED;
189 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && wantlen > 1) {
190 if (random() % 10 == 0) {
192 return STATUS_MORE_ENTRIES;
194 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread, flags);
197 return sock->ops->fn_recv(sock, buf, wantlen, nread, flags);
200 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
201 size_t wantlen, size_t *nread, uint32_t flags,
202 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
205 return NT_STATUS_CONNECTION_DISCONNECTED;
207 if (sock->type != SOCKET_TYPE_DGRAM) {
208 return NT_STATUS_INVALID_PARAMETER;
211 if (!sock->ops->fn_recvfrom) {
212 return NT_STATUS_NOT_IMPLEMENTED;
215 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, flags,
219 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
220 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
223 return NT_STATUS_CONNECTION_DISCONNECTED;
225 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
226 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
227 return NT_STATUS_INVALID_PARAMETER;
230 if (!sock->ops->fn_send) {
231 return NT_STATUS_NOT_IMPLEMENTED;
234 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && blob->length > 1) {
235 DATA_BLOB blob2 = *blob;
236 if (random() % 10 == 0) {
238 return STATUS_MORE_ENTRIES;
240 blob2.length = 1+(random() % blob2.length);
241 return sock->ops->fn_send(sock, &blob2, sendlen, flags);
244 return sock->ops->fn_send(sock, blob, sendlen, flags);
248 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
249 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags,
250 const struct socket_address *dest_addr)
253 return NT_STATUS_CONNECTION_DISCONNECTED;
255 if (sock->type != SOCKET_TYPE_DGRAM) {
256 return NT_STATUS_INVALID_PARAMETER;
259 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
260 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
261 return NT_STATUS_INVALID_PARAMETER;
264 if (!sock->ops->fn_sendto) {
265 return NT_STATUS_NOT_IMPLEMENTED;
268 return sock->ops->fn_sendto(sock, blob, sendlen, flags, dest_addr);
273 ask for the number of bytes in a pending incoming packet
275 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
278 return NT_STATUS_CONNECTION_DISCONNECTED;
280 if (!sock->ops->fn_pending) {
281 return NT_STATUS_NOT_IMPLEMENTED;
283 return sock->ops->fn_pending(sock, npending);
287 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
290 return NT_STATUS_CONNECTION_DISCONNECTED;
292 if (!sock->ops->fn_set_option) {
293 return NT_STATUS_NOT_IMPLEMENTED;
296 return sock->ops->fn_set_option(sock, option, val);
299 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
301 if (!sock->ops->fn_get_peer_name) {
305 return sock->ops->fn_get_peer_name(sock, mem_ctx);
308 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
310 if (!sock->ops->fn_get_peer_addr) {
314 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
317 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
319 if (!sock->ops->fn_get_my_addr) {
323 return sock->ops->fn_get_my_addr(sock, mem_ctx);
326 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
328 if (!sock->ops->fn_get_fd) {
332 return sock->ops->fn_get_fd(sock);
336 call dup() on a socket, and close the old fd. This is used to change
337 the fd to the lowest available number, to make select() more
338 efficient (select speed depends on the maxiumum fd number passed to
341 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
344 if (sock->fd == -1) {
345 return NT_STATUS_INVALID_HANDLE;
349 return map_nt_error_from_unix(errno);
357 /* Create a new socket_address. The type must match the socket type.
358 * The host parameter may be an IP or a hostname
361 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
366 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
371 addr->family = family;
372 addr->addr = talloc_strdup(addr, host);
378 addr->sockaddr = NULL;
379 addr->sockaddrlen = 0;
384 /* Create a new socket_address. Copy the struct sockaddr into the new
385 * structure. Used for hooks in the kerberos libraries, where they
386 * supply only a struct sockaddr */
388 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
389 struct sockaddr *sockaddr,
392 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
399 addr->sockaddr = talloc_memdup(addr, sockaddr, sockaddrlen);
400 if (!addr->sockaddr) {
404 addr->sockaddrlen = sockaddrlen;
408 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
410 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
411 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
412 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
414 if (strcmp("ip", family) == 0 ||
415 strcmp("ipv4", family) == 0) {
416 return socket_ipv4_ops(type);
420 if (strcmp("ipv6", family) == 0) {
421 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
422 DEBUG(3, ("IPv6 support was disabled in smb.conf"));
425 return socket_ipv6_ops(type);
429 if (strcmp("unix", family) == 0) {
430 return socket_unixdom_ops(type);
436 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
438 static const struct {
444 } socket_options[] = {
445 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
446 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
447 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
449 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
451 #ifdef IPTOS_LOWDELAY
452 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
454 #ifdef IPTOS_THROUGHPUT
455 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
458 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
461 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
464 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
467 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
470 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
473 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
476 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
482 Set user socket options.
484 _PUBLIC_ void set_socket_options(int fd, const char *options)
486 const char **options_list = str_list_make(NULL, options, " \t,");
492 for (j = 0; options_list[j]; j++) {
493 const char *tok = options_list[j];
497 BOOL got_value = False;
499 if ((p = strchr(tok,'='))) {
505 for (i=0;socket_options[i].name;i++)
506 if (strequal(socket_options[i].name,tok))
509 if (!socket_options[i].name) {
510 DEBUG(0,("Unknown socket option %s\n",tok));
514 switch (socket_options[i].opttype) {
517 ret = setsockopt(fd,socket_options[i].level,
518 socket_options[i].option,(char *)&value,sizeof(int));
523 DEBUG(0,("syntax error - %s does not take a value\n",tok));
526 int on = socket_options[i].value;
527 ret = setsockopt(fd,socket_options[i].level,
528 socket_options[i].option,(char *)&on,sizeof(int));
534 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
537 talloc_free(options_list);