r17168: Now that TLS (and soon SASL) is below the socket layer, we need to
[bbaumbach/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 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->ops->fn_close(sock);
35         }
36         return 0;
37 }
38
39 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
40                                          struct socket_context **new_sock, 
41                                          enum socket_type type, uint32_t flags)
42 {
43         NTSTATUS status;
44
45         (*new_sock) = talloc(mem_ctx, struct socket_context);
46         if (!(*new_sock)) {
47                 return NT_STATUS_NO_MEMORY;
48         }
49
50         (*new_sock)->type = type;
51         (*new_sock)->state = SOCKET_STATE_UNDEFINED;
52         (*new_sock)->flags = flags;
53
54         (*new_sock)->fd = -1;
55
56         (*new_sock)->private_data = NULL;
57         (*new_sock)->ops = ops;
58         (*new_sock)->backend_name = NULL;
59
60         status = (*new_sock)->ops->fn_init((*new_sock));
61         if (!NT_STATUS_IS_OK(status)) {
62                 talloc_free(*new_sock);
63                 return status;
64         }
65
66         /* by enabling "testnonblock" mode, all socket receive and
67            send calls on non-blocking sockets will randomly recv/send
68            less data than requested */
69
70         if (!(flags & SOCKET_FLAG_BLOCK) &&
71             type == SOCKET_TYPE_STREAM &&
72             lp_parm_bool(-1, "socket", "testnonblock", False)) {
73                 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
74         }
75
76         /* we don't do a connect() on dgram sockets, so need to set
77            non-blocking at socket create time */
78         if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
79                 set_blocking(socket_get_fd(*new_sock), False);
80         }
81
82         talloc_set_destructor(*new_sock, socket_destructor);
83
84         return NT_STATUS_OK;
85 }
86
87 _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type, 
88                                 struct socket_context **new_sock, uint32_t flags)
89 {
90         const struct socket_ops *ops;
91
92         ops = socket_getops_byname(name, type);
93         if (!ops) {
94                 return NT_STATUS_INVALID_PARAMETER;
95         }
96
97         return socket_create_with_ops(NULL, ops, new_sock, type, flags);
98 }
99
100 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
101                                  const struct socket_address *my_address, 
102                                  const struct socket_address *server_address,
103                                  uint32_t flags)
104 {
105         if (sock == NULL) {
106                 return NT_STATUS_CONNECTION_DISCONNECTED;
107         }
108         if (sock->state != SOCKET_STATE_UNDEFINED) {
109                 return NT_STATUS_INVALID_PARAMETER;
110         }
111
112         if (!sock->ops->fn_connect) {
113                 return NT_STATUS_NOT_IMPLEMENTED;
114         }
115
116         return sock->ops->fn_connect(sock, my_address, server_address, flags);
117 }
118
119 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
120 {
121         if (!sock->ops->fn_connect_complete) {
122                 return NT_STATUS_NOT_IMPLEMENTED;
123         }
124         return sock->ops->fn_connect_complete(sock, flags);
125 }
126
127 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock, 
128                                 const struct socket_address *my_address, 
129                                 int queue_size, uint32_t flags)
130 {
131         if (sock == NULL) {
132                 return NT_STATUS_CONNECTION_DISCONNECTED;
133         }
134         if (sock->state != SOCKET_STATE_UNDEFINED) {
135                 return NT_STATUS_INVALID_PARAMETER;
136         }
137
138         if (!sock->ops->fn_listen) {
139                 return NT_STATUS_NOT_IMPLEMENTED;
140         }
141
142         return sock->ops->fn_listen(sock, my_address, queue_size, flags);
143 }
144
145 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
146 {
147         NTSTATUS status;
148
149         if (sock == NULL) {
150                 return NT_STATUS_CONNECTION_DISCONNECTED;
151         }
152         if (sock->type != SOCKET_TYPE_STREAM) {
153                 return NT_STATUS_INVALID_PARAMETER;
154         }
155
156         if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
157                 return NT_STATUS_INVALID_PARAMETER;
158         }
159
160         if (!sock->ops->fn_accept) {
161                 return NT_STATUS_NOT_IMPLEMENTED;
162         }
163
164         status = sock->ops->fn_accept(sock, new_sock);
165
166         if (NT_STATUS_IS_OK(status)) {
167                 talloc_set_destructor(*new_sock, socket_destructor);
168         }
169
170         return status;
171 }
172
173 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf, 
174                               size_t wantlen, size_t *nread)
175 {
176         if (sock == NULL) {
177                 return NT_STATUS_CONNECTION_DISCONNECTED;
178         }
179         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
180             sock->state != SOCKET_STATE_SERVER_CONNECTED &&
181             sock->type  != SOCKET_TYPE_DGRAM) {
182                 return NT_STATUS_INVALID_PARAMETER;
183         }
184
185         if (!sock->ops->fn_recv) {
186                 return NT_STATUS_NOT_IMPLEMENTED;
187         }
188
189         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) 
190             && wantlen > 1) {
191
192                 /* The returning of 0 and MORE_ENTRIES is incompatible
193                    with TLS and SASL sockets, as there is not a
194                    constant event source to re-trigger the reads */
195
196                 if (!(sock->flags & SOCKET_FLAG_FAKE)) {
197                         if (random() % 10 == 0) {
198                                 *nread = 0;
199                                 return STATUS_MORE_ENTRIES;
200                         }
201                 }
202                 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
203         }
204         return sock->ops->fn_recv(sock, buf, wantlen, nread);
205 }
206
207 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf, 
208                                   size_t wantlen, size_t *nread, 
209                                   TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
210 {
211         if (sock == NULL) {
212                 return NT_STATUS_CONNECTION_DISCONNECTED;
213         }
214         if (sock->type != SOCKET_TYPE_DGRAM) {
215                 return NT_STATUS_INVALID_PARAMETER;
216         }
217
218         if (!sock->ops->fn_recvfrom) {
219                 return NT_STATUS_NOT_IMPLEMENTED;
220         }
221
222         return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, 
223                                       mem_ctx, src_addr);
224 }
225
226 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock, 
227                               const DATA_BLOB *blob, size_t *sendlen)
228 {
229         if (sock == NULL) {
230                 return NT_STATUS_CONNECTION_DISCONNECTED;
231         }
232         if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
233             sock->state != SOCKET_STATE_SERVER_CONNECTED) {
234                 return NT_STATUS_INVALID_PARAMETER;
235         }
236
237         if (!sock->ops->fn_send) {
238                 return NT_STATUS_NOT_IMPLEMENTED;
239         }
240         
241         if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
242             && blob->length > 1) {
243                 if (random() % 10 == 0) {
244                         *sendlen = 0;
245                         return STATUS_MORE_ENTRIES;
246                 }
247                 /* The variable size sends are incompatilbe with TLS and SASL
248                  * sockets, which require re-sends to be consistant */
249                 if (!(sock->flags & SOCKET_FLAG_FAKE)) {
250                         DATA_BLOB blob2 = *blob;
251                         blob2.length = 1+(random() % blob2.length);
252                         return sock->ops->fn_send(sock, &blob2, sendlen);
253                 }
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_SOCKET_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