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