build: commit all the waf build files in the tree
[nivanova/samba-autobuild/.git] / source4 / lib / socket / socket.c
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 */
33 static 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 */
514 struct 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
541 nomem:
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
570 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
571
572 static 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  */
677 void socket_set_flags(struct socket_context *sock, unsigned flags)
678 {
679         sock->flags |= flags;
680 }