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