r23183: Check in a change made by Tridge:
[sfrench/samba-autobuild/.git] / source3 / smbd / sockinit.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Andrew Tridgell                1992-1998
5    Copyright (C) James Peach                    2007
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "smb_launchd.h"
24
25 extern pstring user_socket_options;
26
27 static int init_sockets_smbd(const char *smb_ports, int listenset[FD_SETSIZE])
28 {
29         int num_interfaces = iface_count();
30         char * ports;
31         int num_sockets = 0;
32         int i, s;
33
34         /* use a reasonable default set of ports - listing on 445 and 139 */
35         if (!smb_ports) {
36                 ports = lp_smb_ports();
37                 if (!ports || !*ports) {
38                         ports = smb_xstrdup(SMB_PORTS);
39                 } else {
40                         ports = smb_xstrdup(ports);
41                 }
42         } else {
43                 ports = smb_xstrdup(smb_ports);
44         }
45
46         if (lp_interfaces() && lp_bind_interfaces_only()) {
47                 /* We have been given an interfaces line, and been 
48                    told to only bind to those interfaces. Create a
49                    socket per interface and bind to only these.
50                 */
51                 
52                 /* Now open a listen socket for each of the
53                    interfaces. */
54                 for(i = 0; i < num_interfaces; i++) {
55                         struct in_addr *ifip = iface_n_ip(i);
56                         fstring tok;
57                         const char *ptr;
58
59                         if(ifip == NULL) {
60                                 DEBUG(0,("init_sockets_smbd: interface %d has NULL IP address !\n", i));
61                                 continue;
62                         }
63
64                         for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
65                                 unsigned port = atoi(tok);
66                                 if (port == 0) {
67                                         continue;
68                                 }
69                                 s = listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
70                                 if(s == -1)
71                                         return 0;
72
73                                 /* ready to listen */
74                                 set_socket_options(s,"SO_KEEPALIVE"); 
75                                 set_socket_options(s,user_socket_options);
76      
77                                 /* Set server socket to non-blocking for the accept. */
78                                 set_blocking(s,False); 
79  
80                                 if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
81                                         DEBUG(0,("listen: %s\n",strerror(errno)));
82                                         close(s);
83                                         return 0;
84                                 }
85
86                                 num_sockets++;
87                                 if (num_sockets >= FD_SETSIZE) {
88                                         DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
89                                         return 0;
90                                 }
91                         }
92                 }
93         } else {
94                 /* Just bind to 0.0.0.0 - accept connections
95                    from anywhere. */
96
97                 fstring tok;
98                 const char *ptr;
99
100                 num_interfaces = 1;
101                 
102                 for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
103                         unsigned port = atoi(tok);
104                         if (port == 0) continue;
105                         /* open an incoming socket */
106                         s = open_socket_in(SOCK_STREAM, port, 0,
107                                            interpret_addr(lp_socket_address()),True);
108                         if (s == -1)
109                                 return 0;
110                 
111                         /* ready to listen */
112                         set_socket_options(s,"SO_KEEPALIVE"); 
113                         set_socket_options(s,user_socket_options);
114                         
115                         /* Set server socket to non-blocking for the accept. */
116                         set_blocking(s,False); 
117  
118                         if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
119                                 DEBUG(0,("init_sockets_smbd: listen: %s\n",
120                                          strerror(errno)));
121                                 close(s);
122                                 return 0;
123                         }
124
125                         listenset[num_sockets] = s;
126                         num_sockets++;
127
128                         if (num_sockets >= FD_SETSIZE) {
129                                 DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
130                                 return 0;
131                         }
132                 }
133         } 
134
135         SAFE_FREE(ports);
136         return num_sockets;
137 }
138
139 static int init_sockets_launchd(const struct smb_launch_info *linfo,
140                                 const char * smb_ports,
141                                 int listenset[FD_SETSIZE])
142 {
143         int num_sockets;
144         int i;
145
146         /* The launchd service configuration does not have to provide sockets,
147          * even though it's basically useless without it.
148          */
149         if (!linfo->num_sockets) {
150                 return init_sockets_smbd(smb_ports, listenset);
151         }
152
153         /* Make sure we don't get more sockets than we can handle. */
154         num_sockets = MIN(FD_SETSIZE, linfo->num_sockets);
155         memcpy(listenset, linfo->socket_list, num_sockets * sizeof(int));
156
157         /* Get the sockets ready. This could be hoisted into
158          * open_sockets_smbd(), but the order of socket operations might
159          * matter for some platforms, so this approach seems less risky.
160          *      --jpeach
161          */
162         for (i = 0; i < num_sockets; ++i) {
163                 set_socket_options(listenset[i], "SO_KEEPALIVE");
164                 set_socket_options(listenset[i], user_socket_options);
165
166                 /* Set server socket to non-blocking for the accept. */
167                 set_blocking(listenset[i], False);
168         }
169
170         return num_sockets;
171 }
172
173 /* This function is responsible for opening (or retrieving) all the sockets we
174  * smbd will be listening on. It should apply all the configured socket options
175  * and return the number of valid sockets in listenset.
176  */
177 int smbd_sockinit(const char *cmdline_ports, int listenset[FD_SETSIZE],
178                         struct timeval *idle)
179 {
180         int num_sockets;
181         struct smb_launch_info linfo;
182
183         ZERO_STRUCTP(idle);
184
185         if (smb_launchd_checkin(&linfo)) {
186                 /* We are running under launchd and launchd has
187                  * opened some sockets for us.
188                  */
189                 num_sockets = init_sockets_launchd(&linfo,
190                                             cmdline_ports,
191                                             listenset);
192                 idle->tv_sec = linfo.idle_timeout_secs;
193                 smb_launchd_checkout(&linfo);
194         } else {
195                 num_sockets = init_sockets_smbd(cmdline_ports,
196                                             listenset);
197         }
198
199         return num_sockets;
200 }
201