r22960: added a SOCKET_FLAG_NOCLOSE to allow us to tell the socket layer that
[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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/socket/socket.h"
25 #include "system/filesys.h"
26 #include "system/network.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(-1, "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         }
170
171         return status;
172 }
173
174 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf, 
175                               size_t wantlen, size_t *nread)
176 {
177         if (sock == NULL) {
178                 return NT_STATUS_CONNECTION_DISCONNECTED;
179         }
180         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
181             sock->state != SOCKET_STATE_SERVER_CONNECTED &&
182             sock->type  != SOCKET_TYPE_DGRAM) {
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         if (!sock->ops->fn_recv) {
187                 return NT_STATUS_NOT_IMPLEMENTED;
188         }
189
190         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) 
191             && wantlen > 1) {
192
193                 if (random() % 10 == 0) {
194                         *nread = 0;
195                         return STATUS_MORE_ENTRIES;
196                 }
197                 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
198         }
199         return sock->ops->fn_recv(sock, buf, wantlen, nread);
200 }
201
202 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf, 
203                                   size_t wantlen, size_t *nread, 
204                                   TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
205 {
206         if (sock == NULL) {
207                 return NT_STATUS_CONNECTION_DISCONNECTED;
208         }
209         if (sock->type != SOCKET_TYPE_DGRAM) {
210                 return NT_STATUS_INVALID_PARAMETER;
211         }
212
213         if (!sock->ops->fn_recvfrom) {
214                 return NT_STATUS_NOT_IMPLEMENTED;
215         }
216
217         return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, 
218                                       mem_ctx, src_addr);
219 }
220
221 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock, 
222                               const DATA_BLOB *blob, size_t *sendlen)
223 {
224         if (sock == NULL) {
225                 return NT_STATUS_CONNECTION_DISCONNECTED;
226         }
227         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
228             sock->state != SOCKET_STATE_SERVER_CONNECTED) {
229                 return NT_STATUS_INVALID_PARAMETER;
230         }
231
232         if (!sock->ops->fn_send) {
233                 return NT_STATUS_NOT_IMPLEMENTED;
234         }
235         
236         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
237             && blob->length > 1) {
238                 DATA_BLOB blob2 = *blob;
239                 if (random() % 10 == 0) {
240                         *sendlen = 0;
241                         return STATUS_MORE_ENTRIES;
242                 }
243                 /* The random size sends are incompatible with TLS and SASL
244                  * sockets, which require re-sends to be consistant */
245                 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
246                         blob2.length = 1+(random() % blob2.length);
247                 } else {
248                         /* This is particularly stressful on buggy
249                          * LDAP clients, that don't expect on LDAP
250                          * packet in many SASL packets */
251                         blob2.length = 1 + blob2.length/2;
252                 }
253                 return sock->ops->fn_send(sock, &blob2, sendlen);
254         }
255         return sock->ops->fn_send(sock, blob, sendlen);
256 }
257
258
259 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock, 
260                                 const DATA_BLOB *blob, size_t *sendlen, 
261                                 const struct socket_address *dest_addr)
262 {
263         if (sock == NULL) {
264                 return NT_STATUS_CONNECTION_DISCONNECTED;
265         }
266         if (sock->type != SOCKET_TYPE_DGRAM) {
267                 return NT_STATUS_INVALID_PARAMETER;
268         }
269
270         if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
271             sock->state == SOCKET_STATE_SERVER_CONNECTED) {
272                 return NT_STATUS_INVALID_PARAMETER;
273         }
274
275         if (!sock->ops->fn_sendto) {
276                 return NT_STATUS_NOT_IMPLEMENTED;
277         }
278
279         return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
280 }
281
282
283 /*
284   ask for the number of bytes in a pending incoming packet
285 */
286 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
287 {
288         if (sock == NULL) {
289                 return NT_STATUS_CONNECTION_DISCONNECTED;
290         }
291         if (!sock->ops->fn_pending) {
292                 return NT_STATUS_NOT_IMPLEMENTED;
293         }
294         return sock->ops->fn_pending(sock, npending);
295 }
296
297
298 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
299 {
300         if (sock == NULL) {
301                 return NT_STATUS_CONNECTION_DISCONNECTED;
302         }
303         if (!sock->ops->fn_set_option) {
304                 return NT_STATUS_NOT_IMPLEMENTED;
305         }
306
307         return sock->ops->fn_set_option(sock, option, val);
308 }
309
310 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
311 {
312         if (!sock->ops->fn_get_peer_name) {
313                 return NULL;
314         }
315
316         return sock->ops->fn_get_peer_name(sock, mem_ctx);
317 }
318
319 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
320 {
321         if (!sock->ops->fn_get_peer_addr) {
322                 return NULL;
323         }
324
325         return sock->ops->fn_get_peer_addr(sock, mem_ctx);
326 }
327
328 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
329 {
330         if (!sock->ops->fn_get_my_addr) {
331                 return NULL;
332         }
333
334         return sock->ops->fn_get_my_addr(sock, mem_ctx);
335 }
336
337 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
338 {
339         if (!sock->ops->fn_get_fd) {
340                 return -1;
341         }
342
343         return sock->ops->fn_get_fd(sock);
344 }
345
346 /*
347   call dup() on a socket, and close the old fd. This is used to change
348   the fd to the lowest available number, to make select() more
349   efficient (select speed depends on the maxiumum fd number passed to
350   it)
351 */
352 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
353 {
354         int fd;
355         if (sock->fd == -1) {
356                 return NT_STATUS_INVALID_HANDLE;
357         }
358         fd = dup(sock->fd);
359         if (fd == -1) {
360                 return map_nt_error_from_unix(errno);
361         }
362         close(sock->fd);
363         sock->fd = fd;
364         return NT_STATUS_OK;
365         
366 }
367
368 /* Create a new socket_address.  The type must match the socket type.
369  * The host parameter may be an IP or a hostname 
370  */
371
372 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
373                                                             const char *family,
374                                                             const char *host,
375                                                             int port)
376 {
377         struct socket_address *addr = talloc(mem_ctx, struct socket_address);
378         if (!addr) {
379                 return NULL;
380         }
381
382         addr->family = family;
383         addr->addr = talloc_strdup(addr, host);
384         if (!addr->addr) {
385                 talloc_free(addr);
386                 return NULL;
387         }
388         addr->port = port;
389         addr->sockaddr = NULL;
390         addr->sockaddrlen = 0;
391
392         return addr;
393 }
394
395 /* Create a new socket_address.  Copy the struct sockaddr into the new
396  * structure.  Used for hooks in the kerberos libraries, where they
397  * supply only a struct sockaddr */
398
399 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx, 
400                                                              struct sockaddr *sockaddr, 
401                                                              size_t sockaddrlen)
402 {
403         struct socket_address *addr = talloc(mem_ctx, struct socket_address);
404         if (!addr) {
405                 return NULL;
406         }
407         addr->family = NULL; 
408         addr->addr = NULL;
409         addr->port = 0;
410         addr->sockaddr = talloc_memdup(addr, sockaddr, sockaddrlen);
411         if (!addr->sockaddr) {
412                 talloc_free(addr);
413                 return NULL;
414         }
415         addr->sockaddrlen = sockaddrlen;
416         return addr;
417 }
418
419 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
420 {
421         extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
422         extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
423         extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
424
425         if (strcmp("ip", family) == 0 || 
426             strcmp("ipv4", family) == 0) {
427                 return socket_ipv4_ops(type);
428         }
429
430 #if HAVE_IPV6
431         if (strcmp("ipv6", family) == 0) {
432                 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
433                         DEBUG(3, ("IPv6 support was disabled in smb.conf"));
434                         return NULL;
435                 }
436                 return socket_ipv6_ops(type);
437         }
438 #endif
439
440         if (strcmp("unix", family) == 0) {
441                 return socket_unixdom_ops(type);
442         }
443
444         return NULL;
445 }
446
447 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
448
449 static const struct {
450         const char *name;
451         int level;
452         int option;
453         int value;
454         int opttype;
455 } socket_options[] = {
456   {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
457   {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
458   {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
459 #ifdef TCP_NODELAY
460   {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
461 #endif
462 #ifdef IPTOS_LOWDELAY
463   {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
464 #endif
465 #ifdef IPTOS_THROUGHPUT
466   {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
467 #endif
468 #ifdef SO_REUSEPORT
469   {"SO_REUSEPORT",      SOL_SOCKET,    SO_REUSEPORT,    0,                 OPT_BOOL},
470 #endif
471 #ifdef SO_SNDBUF
472   {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
473 #endif
474 #ifdef SO_RCVBUF
475   {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
476 #endif
477 #ifdef SO_SNDLOWAT
478   {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
479 #endif
480 #ifdef SO_RCVLOWAT
481   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
482 #endif
483 #ifdef SO_SNDTIMEO
484   {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
485 #endif
486 #ifdef SO_RCVTIMEO
487   {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
488 #endif
489   {NULL,0,0,0,0}};
490
491
492 /**
493  Set user socket options.
494 **/
495 _PUBLIC_ void set_socket_options(int fd, const char *options)
496 {
497         const char **options_list = str_list_make(NULL, options, " \t,");
498         int j;
499
500         if (!options_list)
501                 return;
502
503         for (j = 0; options_list[j]; j++) {
504                 const char *tok = options_list[j];
505                 int ret=0,i;
506                 int value = 1;
507                 char *p;
508                 BOOL got_value = False;
509
510                 if ((p = strchr(tok,'='))) {
511                         *p = 0;
512                         value = atoi(p+1);
513                         got_value = True;
514                 }
515
516                 for (i=0;socket_options[i].name;i++)
517                         if (strequal(socket_options[i].name,tok))
518                                 break;
519
520                 if (!socket_options[i].name) {
521                         DEBUG(0,("Unknown socket option %s\n",tok));
522                         continue;
523                 }
524
525                 switch (socket_options[i].opttype) {
526                 case OPT_BOOL:
527                 case OPT_INT:
528                         ret = setsockopt(fd,socket_options[i].level,
529                                                 socket_options[i].option,(char *)&value,sizeof(int));
530                         break;
531
532                 case OPT_ON:
533                         if (got_value)
534                                 DEBUG(0,("syntax error - %s does not take a value\n",tok));
535
536                         {
537                                 int on = socket_options[i].value;
538                                 ret = setsockopt(fd,socket_options[i].level,
539                                                         socket_options[i].option,(char *)&on,sizeof(int));
540                         }
541                         break;    
542                 }
543       
544                 if (ret != 0)
545                         DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
546         }
547
548         talloc_free(options_list);
549 }
550
551 /*
552   set some flags on a socket 
553  */
554 void socket_set_flags(struct socket_context *sock, unsigned flags)
555 {
556         sock->flags |= flags;
557 }