source: vendor/3.6.0/source4/lib/socket/socket.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 17.2 KB
Line 
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
7
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.
12
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.
17
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/>.
20*/
21
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"
27#include "../lib/tsocket/tsocket.h"
28#include "lib/util/util_net.h"
29
30/*
31 auto-close sockets on free
32*/
33static int socket_destructor(struct socket_context *sock)
34{
35 if (sock->ops->fn_close &&
36 !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
37 sock->ops->fn_close(sock);
38 }
39 return 0;
40}
41
42_PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
43 struct tevent_fd *fde,
44 int fd,
45 void *private_data)
46{
47 /* this might be the socket_wrapper swrap_close() */
48 close(fd);
49}
50
51_PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
52 struct socket_context **new_sock,
53 enum socket_type type, uint32_t flags)
54{
55 NTSTATUS status;
56
57 (*new_sock) = talloc(mem_ctx, struct socket_context);
58 if (!(*new_sock)) {
59 return NT_STATUS_NO_MEMORY;
60 }
61
62 (*new_sock)->type = type;
63 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
64 (*new_sock)->flags = flags;
65
66 (*new_sock)->fd = -1;
67
68 (*new_sock)->private_data = NULL;
69 (*new_sock)->ops = ops;
70 (*new_sock)->backend_name = NULL;
71
72 status = (*new_sock)->ops->fn_init((*new_sock));
73 if (!NT_STATUS_IS_OK(status)) {
74 talloc_free(*new_sock);
75 return status;
76 }
77
78 /* by enabling "testnonblock" mode, all socket receive and
79 send calls on non-blocking sockets will randomly recv/send
80 less data than requested */
81
82 if (!(flags & SOCKET_FLAG_BLOCK) &&
83 type == SOCKET_TYPE_STREAM &&
84 getenv("SOCKET_TESTNONBLOCK") != NULL) {
85 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
86 }
87
88 /* we don't do a connect() on dgram sockets, so need to set
89 non-blocking at socket create time */
90 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
91 set_blocking(socket_get_fd(*new_sock), false);
92 }
93
94 talloc_set_destructor(*new_sock, socket_destructor);
95
96 return NT_STATUS_OK;
97}
98
99_PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
100 struct socket_context **new_sock, uint32_t flags)
101{
102 const struct socket_ops *ops;
103
104 ops = socket_getops_byname(name, type);
105 if (!ops) {
106 return NT_STATUS_INVALID_PARAMETER;
107 }
108
109 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
110}
111
112_PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
113 const struct socket_address *my_address,
114 const struct socket_address *server_address,
115 uint32_t flags)
116{
117 if (sock == NULL) {
118 return NT_STATUS_CONNECTION_DISCONNECTED;
119 }
120 if (sock->state != SOCKET_STATE_UNDEFINED) {
121 return NT_STATUS_INVALID_PARAMETER;
122 }
123
124 if (!sock->ops->fn_connect) {
125 return NT_STATUS_NOT_IMPLEMENTED;
126 }
127
128 return sock->ops->fn_connect(sock, my_address, server_address, flags);
129}
130
131_PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
132{
133 if (!sock->ops->fn_connect_complete) {
134 return NT_STATUS_NOT_IMPLEMENTED;
135 }
136 return sock->ops->fn_connect_complete(sock, flags);
137}
138
139_PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
140 const struct socket_address *my_address,
141 int queue_size, uint32_t flags)
142{
143 if (sock == NULL) {
144 return NT_STATUS_CONNECTION_DISCONNECTED;
145 }
146 if (sock->state != SOCKET_STATE_UNDEFINED) {
147 return NT_STATUS_INVALID_PARAMETER;
148 }
149
150 if (!sock->ops->fn_listen) {
151 return NT_STATUS_NOT_IMPLEMENTED;
152 }
153
154 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
155}
156
157_PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
158{
159 NTSTATUS status;
160
161 if (sock == NULL) {
162 return NT_STATUS_CONNECTION_DISCONNECTED;
163 }
164 if (sock->type != SOCKET_TYPE_STREAM) {
165 return NT_STATUS_INVALID_PARAMETER;
166 }
167
168 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
169 return NT_STATUS_INVALID_PARAMETER;
170 }
171
172 if (!sock->ops->fn_accept) {
173 return NT_STATUS_NOT_IMPLEMENTED;
174 }
175
176 status = sock->ops->fn_accept(sock, new_sock);
177
178 if (NT_STATUS_IS_OK(status)) {
179 talloc_set_destructor(*new_sock, socket_destructor);
180 (*new_sock)->flags = 0;
181 }
182
183 return status;
184}
185
186_PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
187 size_t wantlen, size_t *nread)
188{
189 if (sock == NULL) {
190 return NT_STATUS_CONNECTION_DISCONNECTED;
191 }
192 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
193 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
194 sock->type != SOCKET_TYPE_DGRAM) {
195 return NT_STATUS_INVALID_PARAMETER;
196 }
197
198 if (!sock->ops->fn_recv) {
199 return NT_STATUS_NOT_IMPLEMENTED;
200 }
201
202 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
203 && wantlen > 1) {
204
205 if (random() % 10 == 0) {
206 *nread = 0;
207 return STATUS_MORE_ENTRIES;
208 }
209 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
210 }
211 return sock->ops->fn_recv(sock, buf, wantlen, nread);
212}
213
214_PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
215 size_t wantlen, size_t *nread,
216 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
217{
218 if (sock == NULL) {
219 return NT_STATUS_CONNECTION_DISCONNECTED;
220 }
221 if (sock->type != SOCKET_TYPE_DGRAM) {
222 return NT_STATUS_INVALID_PARAMETER;
223 }
224
225 if (!sock->ops->fn_recvfrom) {
226 return NT_STATUS_NOT_IMPLEMENTED;
227 }
228
229 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
230 mem_ctx, src_addr);
231}
232
233_PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
234 const DATA_BLOB *blob, size_t *sendlen)
235{
236 if (sock == NULL) {
237 return NT_STATUS_CONNECTION_DISCONNECTED;
238 }
239 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
240 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
241 return NT_STATUS_INVALID_PARAMETER;
242 }
243
244 if (!sock->ops->fn_send) {
245 return NT_STATUS_NOT_IMPLEMENTED;
246 }
247
248 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
249 && blob->length > 1) {
250 DATA_BLOB blob2 = *blob;
251 if (random() % 10 == 0) {
252 *sendlen = 0;
253 return STATUS_MORE_ENTRIES;
254 }
255 /* The random size sends are incompatible with TLS and SASL
256 * sockets, which require re-sends to be consistant */
257 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
258 blob2.length = 1+(random() % blob2.length);
259 } else {
260 /* This is particularly stressful on buggy
261 * LDAP clients, that don't expect on LDAP
262 * packet in many SASL packets */
263 blob2.length = 1 + blob2.length/2;
264 }
265 return sock->ops->fn_send(sock, &blob2, sendlen);
266 }
267 return sock->ops->fn_send(sock, blob, sendlen);
268}
269
270
271_PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
272 const DATA_BLOB *blob, size_t *sendlen,
273 const struct socket_address *dest_addr)
274{
275 if (sock == NULL) {
276 return NT_STATUS_CONNECTION_DISCONNECTED;
277 }
278 if (sock->type != SOCKET_TYPE_DGRAM) {
279 return NT_STATUS_INVALID_PARAMETER;
280 }
281
282 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
283 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
284 return NT_STATUS_INVALID_PARAMETER;
285 }
286
287 if (!sock->ops->fn_sendto) {
288 return NT_STATUS_NOT_IMPLEMENTED;
289 }
290
291 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
292}
293
294
295/*
296 ask for the number of bytes in a pending incoming packet
297*/
298_PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
299{
300 if (sock == NULL) {
301 return NT_STATUS_CONNECTION_DISCONNECTED;
302 }
303 if (!sock->ops->fn_pending) {
304 return NT_STATUS_NOT_IMPLEMENTED;
305 }
306 return sock->ops->fn_pending(sock, npending);
307}
308
309
310_PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
311{
312 if (sock == NULL) {
313 return NT_STATUS_CONNECTION_DISCONNECTED;
314 }
315 if (!sock->ops->fn_set_option) {
316 return NT_STATUS_NOT_IMPLEMENTED;
317 }
318
319 return sock->ops->fn_set_option(sock, option, val);
320}
321
322_PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
323{
324 if (!sock->ops->fn_get_peer_name) {
325 return NULL;
326 }
327
328 return sock->ops->fn_get_peer_name(sock, mem_ctx);
329}
330
331_PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
332{
333 if (!sock->ops->fn_get_peer_addr) {
334 return NULL;
335 }
336
337 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
338}
339
340_PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
341{
342 if (!sock->ops->fn_get_my_addr) {
343 return NULL;
344 }
345
346 return sock->ops->fn_get_my_addr(sock, mem_ctx);
347}
348
349_PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
350 const struct socket_address *a)
351{
352 struct tsocket_address *r;
353 int ret;
354
355 if (a->sockaddr) {
356 ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
357 a->sockaddr,
358 a->sockaddrlen,
359 &r);
360 } else {
361 ret = tsocket_address_inet_from_strings(mem_ctx,
362 a->family,
363 a->addr,
364 a->port,
365 &r);
366 }
367
368 if (ret != 0) {
369 return NULL;
370 }
371
372 return r;
373}
374
375_PUBLIC_ void socket_address_set_port(struct socket_address *a,
376 uint16_t port)
377{
378 if (a->sockaddr) {
379 set_sockaddr_port(a->sockaddr, port);
380 } else {
381 a->port = port;
382 }
383
384}
385
386_PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
387 const struct tsocket_address *a)
388{
389 ssize_t ret;
390 struct sockaddr_storage ss;
391 size_t sslen = sizeof(ss);
392
393 ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
394 if (ret < 0) {
395 return NULL;
396 }
397
398 return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
399}
400
401_PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
402{
403 struct socket_address *a;
404 struct tsocket_address *r;
405
406 a = socket_get_peer_addr(sock, mem_ctx);
407 if (a == NULL) {
408 return NULL;
409 }
410
411 r = socket_address_to_tsocket_address(mem_ctx, a);
412 talloc_free(a);
413 return r;
414}
415
416_PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
417{
418 struct socket_address *a;
419 struct tsocket_address *r;
420
421 a = socket_get_my_addr(sock, mem_ctx);
422 if (a == NULL) {
423 return NULL;
424 }
425
426 r = socket_address_to_tsocket_address(mem_ctx, a);
427 talloc_free(a);
428 return r;
429}
430
431_PUBLIC_ int socket_get_fd(struct socket_context *sock)
432{
433 if (!sock->ops->fn_get_fd) {
434 return -1;
435 }
436
437 return sock->ops->fn_get_fd(sock);
438}
439
440/*
441 call dup() on a socket, and close the old fd. This is used to change
442 the fd to the lowest available number, to make select() more
443 efficient (select speed depends on the maxiumum fd number passed to
444 it)
445*/
446_PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
447{
448 int fd;
449 if (sock->fd == -1) {
450 return NT_STATUS_INVALID_HANDLE;
451 }
452 fd = dup(sock->fd);
453 if (fd == -1) {
454 return map_nt_error_from_unix(errno);
455 }
456 close(sock->fd);
457 sock->fd = fd;
458 return NT_STATUS_OK;
459
460}
461
462/* Create a new socket_address. The type must match the socket type.
463 * The host parameter may be an IP or a hostname
464 */
465
466_PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
467 const char *family,
468 const char *host,
469 int port)
470{
471 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
472 if (!addr) {
473 return NULL;
474 }
475
476 addr->family = family;
477 addr->addr = talloc_strdup(addr, host);
478 if (!addr->addr) {
479 talloc_free(addr);
480 return NULL;
481 }
482 addr->port = port;
483 addr->sockaddr = NULL;
484 addr->sockaddrlen = 0;
485
486 return addr;
487}
488
489/* Create a new socket_address. Copy the struct sockaddr into the new
490 * structure. Used for hooks in the kerberos libraries, where they
491 * supply only a struct sockaddr */
492
493_PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
494 struct sockaddr *sockaddr,
495 size_t sockaddrlen)
496{
497 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
498 if (!addr) {
499 return NULL;
500 }
501 addr->family = NULL;
502 addr->addr = NULL;
503 addr->port = 0;
504 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
505 if (!addr->sockaddr) {
506 talloc_free(addr);
507 return NULL;
508 }
509 addr->sockaddrlen = sockaddrlen;
510 return addr;
511}
512
513/* Copy a socket_address structure */
514struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
515 const struct socket_address *oaddr)
516{
517 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
518 if (!addr) {
519 return NULL;
520 }
521 addr->family = oaddr->family;
522 if (oaddr->addr) {
523 addr->addr = talloc_strdup(addr, oaddr->addr);
524 if (!addr->addr) {
525 goto nomem;
526 }
527 }
528 addr->port = oaddr->port;
529 if (oaddr->sockaddr) {
530 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
531 oaddr->sockaddr,
532 oaddr->sockaddrlen);
533 if (!addr->sockaddr) {
534 goto nomem;
535 }
536 addr->sockaddrlen = oaddr->sockaddrlen;
537 }
538
539 return addr;
540
541nomem:
542 talloc_free(addr);
543 return NULL;
544}
545
546_PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
547{
548 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
549 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
550 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
551
552 if (strcmp("ip", family) == 0 ||
553 strcmp("ipv4", family) == 0) {
554 return socket_ipv4_ops(type);
555 }
556
557#if HAVE_IPV6
558 if (strcmp("ipv6", family) == 0) {
559 return socket_ipv6_ops(type);
560 }
561#endif
562
563 if (strcmp("unix", family) == 0) {
564 return socket_unixdom_ops(type);
565 }
566
567 return NULL;
568}
569
570enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
571
572static const struct {
573 const char *name;
574 int level;
575 int option;
576 int value;
577 int opttype;
578} socket_options[] = {
579 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
580 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
581 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
582#ifdef TCP_NODELAY
583 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
584#endif
585#ifdef IPTOS_LOWDELAY
586 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
587#endif
588#ifdef IPTOS_THROUGHPUT
589 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
590#endif
591#ifdef SO_REUSEPORT
592 {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
593#endif
594#ifdef SO_SNDBUF
595 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
596#endif
597#ifdef SO_RCVBUF
598 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
599#endif
600#ifdef SO_SNDLOWAT
601 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
602#endif
603#ifdef SO_RCVLOWAT
604 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
605#endif
606#ifdef SO_SNDTIMEO
607 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
608#endif
609#ifdef SO_RCVTIMEO
610 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
611#endif
612 {NULL,0,0,0,0}};
613
614
615/**
616 Set user socket options.
617**/
618_PUBLIC_ void set_socket_options(int fd, const char *options)
619{
620 const char **options_list = (const char **)str_list_make(NULL, options, " \t,");
621 int j;
622
623 if (!options_list)
624 return;
625
626 for (j = 0; options_list[j]; j++) {
627 const char *tok = options_list[j];
628 int ret=0,i;
629 int value = 1;
630 char *p;
631 bool got_value = false;
632
633 if ((p = strchr(tok,'='))) {
634 *p = 0;
635 value = atoi(p+1);
636 got_value = true;
637 }
638
639 for (i=0;socket_options[i].name;i++)
640 if (strequal(socket_options[i].name,tok))
641 break;
642
643 if (!socket_options[i].name) {
644 DEBUG(0,("Unknown socket option %s\n",tok));
645 continue;
646 }
647
648 switch (socket_options[i].opttype) {
649 case OPT_BOOL:
650 case OPT_INT:
651 ret = setsockopt(fd,socket_options[i].level,
652 socket_options[i].option,(char *)&value,sizeof(int));
653 break;
654
655 case OPT_ON:
656 if (got_value)
657 DEBUG(0,("syntax error - %s does not take a value\n",tok));
658
659 {
660 int on = socket_options[i].value;
661 ret = setsockopt(fd,socket_options[i].level,
662 socket_options[i].option,(char *)&on,sizeof(int));
663 }
664 break;
665 }
666
667 if (ret != 0)
668 DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
669 }
670
671 talloc_free(options_list);
672}
673
674/*
675 set some flags on a socket
676 */
677void socket_set_flags(struct socket_context *sock, unsigned flags)
678{
679 sock->flags |= flags;
680}
Note: See TracBrowser for help on using the repository browser.