s4:sec_descriptor - fix constant
[Samba/ekacnet.git] / source4 / lib / socket / socket.c
blob8e2f1683f229c35156ce7a6409cd04b60887f980
1 /*
2 Unix SMB/CIFS implementation.
3 Socket functions
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/>.
22 #include "includes.h"
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);
37 return 0;
40 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
41 struct tevent_fd *fde,
42 int fd,
43 void *private_data)
45 /* this might be the socket_wrapper swrap_close() */
46 close(fd);
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)
53 NTSTATUS status;
55 (*new_sock) = talloc(mem_ctx, struct socket_context);
56 if (!(*new_sock)) {
57 return NT_STATUS_NO_MEMORY;
60 (*new_sock)->type = type;
61 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
62 (*new_sock)->flags = flags;
64 (*new_sock)->fd = -1;
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);
73 return status;
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);
94 return NT_STATUS_OK;
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);
103 if (!ops) {
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,
113 uint32_t flags)
115 if (sock == NULL) {
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)
141 if (sock == NULL) {
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)
157 NTSTATUS status;
159 if (sock == NULL) {
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;
181 return status;
184 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
185 size_t wantlen, size_t *nread)
187 if (sock == NULL) {
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)
201 && wantlen > 1) {
203 if (random() % 10 == 0) {
204 *nread = 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)
216 if (sock == NULL) {
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,
228 mem_ctx, src_addr);
231 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
232 const DATA_BLOB *blob, size_t *sendlen)
234 if (sock == NULL) {
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) {
250 *sendlen = 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);
257 } else {
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)
273 if (sock == NULL) {
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)
298 if (sock == NULL) {
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)
310 if (sock == NULL) {
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) {
323 return NULL;
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) {
332 return NULL;
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) {
341 return NULL;
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) {
350 return -1;
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)
364 int fd;
365 if (sock->fd == -1) {
366 return NT_STATUS_INVALID_HANDLE;
368 fd = dup(sock->fd);
369 if (fd == -1) {
370 return map_nt_error_from_unix(errno);
372 close(sock->fd);
373 sock->fd = fd;
374 return NT_STATUS_OK;
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,
383 const char *family,
384 const char *host,
385 int port)
387 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
388 if (!addr) {
389 return NULL;
392 addr->family = family;
393 addr->addr = talloc_strdup(addr, host);
394 if (!addr->addr) {
395 talloc_free(addr);
396 return NULL;
398 addr->port = port;
399 addr->sockaddr = NULL;
400 addr->sockaddrlen = 0;
402 return addr;
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,
411 size_t sockaddrlen)
413 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
414 if (!addr) {
415 return NULL;
417 addr->family = NULL;
418 addr->addr = NULL;
419 addr->port = 0;
420 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
421 if (!addr->sockaddr) {
422 talloc_free(addr);
423 return NULL;
425 addr->sockaddrlen = sockaddrlen;
426 return addr;
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);
434 if (!addr) {
435 return NULL;
437 addr->family = oaddr->family;
438 if (oaddr->addr) {
439 addr->addr = talloc_strdup(addr, oaddr->addr);
440 if (!addr->addr) {
441 goto nomem;
444 addr->port = oaddr->port;
445 if (oaddr->sockaddr) {
446 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
447 oaddr->sockaddr,
448 oaddr->sockaddrlen);
449 if (!addr->sockaddr) {
450 goto nomem;
452 addr->sockaddrlen = oaddr->sockaddrlen;
455 return addr;
457 nomem:
458 talloc_free(addr);
459 return NULL;
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);
473 #if HAVE_IPV6
474 if (strcmp("ipv6", family) == 0) {
475 return socket_ipv6_ops(type);
477 #endif
479 if (strcmp("unix", family) == 0) {
480 return socket_unixdom_ops(type);
483 return NULL;
486 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
488 static const struct {
489 const char *name;
490 int level;
491 int option;
492 int value;
493 int opttype;
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},
498 #ifdef TCP_NODELAY
499 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
500 #endif
501 #ifdef IPTOS_LOWDELAY
502 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
503 #endif
504 #ifdef IPTOS_THROUGHPUT
505 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
506 #endif
507 #ifdef SO_REUSEPORT
508 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
509 #endif
510 #ifdef SO_SNDBUF
511 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
512 #endif
513 #ifdef SO_RCVBUF
514 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
515 #endif
516 #ifdef SO_SNDLOWAT
517 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
518 #endif
519 #ifdef SO_RCVLOWAT
520 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
521 #endif
522 #ifdef SO_SNDTIMEO
523 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
524 #endif
525 #ifdef SO_RCVTIMEO
526 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
527 #endif
528 {NULL,0,0,0,0}};
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,");
537 int j;
539 if (!options_list)
540 return;
542 for (j = 0; options_list[j]; j++) {
543 const char *tok = options_list[j];
544 int ret=0,i;
545 int value = 1;
546 char *p;
547 bool got_value = false;
549 if ((p = strchr(tok,'='))) {
550 *p = 0;
551 value = atoi(p+1);
552 got_value = true;
555 for (i=0;socket_options[i].name;i++)
556 if (strequal(socket_options[i].name,tok))
557 break;
559 if (!socket_options[i].name) {
560 DEBUG(0,("Unknown socket option %s\n",tok));
561 continue;
564 switch (socket_options[i].opttype) {
565 case OPT_BOOL:
566 case OPT_INT:
567 ret = setsockopt(fd,socket_options[i].level,
568 socket_options[i].option,(char *)&value,sizeof(int));
569 break;
571 case OPT_ON:
572 if (got_value)
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));
580 break;
583 if (ret != 0)
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;