1/* 2 * "$Id: listen.c 11093 2013-07-03 20:48:42Z msweet $" 3 * 4 * Server listening routines for the CUPS scheduler. 5 * 6 * Copyright 2007-2010 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * Contents: 16 * 17 * cupsdDeleteAllListeners() - Delete all listeners. 18 * cupsdPauseListening() - Clear input polling on all listening sockets... 19 * cupsdResumeListening() - Set input polling on all listening sockets... 20 * cupsdStartListening() - Create all listening sockets... 21 * cupsdStopListening() - Close all listening sockets... 22 */ 23 24/* 25 * Include necessary headers... 26 */ 27 28#include "cupsd.h" 29 30 31/* 32 * Make sure the IPV6_V6ONLY is defined on Linux - older versions of 33 * glibc don't define it even if the kernel supports it... 34 */ 35 36#if defined(__linux) && !defined(IPV6_V6ONLY) 37# define IPV6_V6ONLY 26 38#endif /* __linux && !IPV6_V6ONLY */ 39 40 41/* 42 * 'cupsdDeleteAllListeners()' - Delete all listeners. 43 */ 44 45void 46cupsdDeleteAllListeners(void) 47{ 48 cupsd_listener_t *lis; /* Current listening socket */ 49 50 51 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); 52 lis; 53 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 54 free(lis); 55 56 cupsArrayDelete(Listeners); 57 Listeners = NULL; 58} 59 60 61/* 62 * 'cupsdPauseListening()' - Clear input polling on all listening sockets... 63 */ 64 65void 66cupsdPauseListening(void) 67{ 68 cupsd_listener_t *lis; /* Current listening socket */ 69 70 71 if (cupsArrayCount(Listeners) < 1) 72 return; 73 74 if (cupsArrayCount(Clients) == MaxClients) 75 cupsdLogMessage(CUPSD_LOG_WARN, 76 "Max clients reached, holding new connections..."); 77 else if (errno == ENFILE || errno == EMFILE) 78 cupsdLogMessage(CUPSD_LOG_WARN, 79 "Too many open files, holding new connections for " 80 "30 seconds..."); 81 82 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits..."); 83 84 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); 85 lis; 86 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 87 cupsdRemoveSelect(lis->fd); 88 89 ListeningPaused = time(NULL) + 30; 90} 91 92 93/* 94 * 'cupsdResumeListening()' - Set input polling on all listening sockets... 95 */ 96 97void 98cupsdResumeListening(void) 99{ 100 cupsd_listener_t *lis; /* Current listening socket */ 101 102 103 if (cupsArrayCount(Listeners) < 1) 104 return; 105 106 cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing..."); 107 cupsdLogMessage(CUPSD_LOG_DEBUG2, 108 "cupsdResumeListening: Setting input bits..."); 109 110 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); 111 lis; 112 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 113 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis); 114 115 ListeningPaused = 0; 116} 117 118 119/* 120 * 'cupsdStartListening()' - Create all listening sockets... 121 */ 122 123void 124cupsdStartListening(void) 125{ 126 int status; /* Bind result */ 127 int p, /* Port number */ 128 val; /* Parameter value */ 129 cupsd_listener_t *lis; /* Current listening socket */ 130 char s[256]; /* String addresss */ 131 const char *have_domain; /* Have a domain socket? */ 132 static const char * const encryptions[] = 133 { /* Encryption values */ 134 "IfRequested", 135 "Never", 136 "Required", 137 "Always" 138 }; 139 140 141 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners", 142 cupsArrayCount(Listeners)); 143 144 /* 145 * Setup socket listeners... 146 */ 147 148 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0, 149 have_domain = NULL; 150 lis; 151 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 152 { 153 httpAddrString(&(lis->address), s, sizeof(s)); 154 p = httpAddrPort(&(lis->address)); 155 156 /* 157 * If needed, create a socket for listening... 158 */ 159 160 if (lis->fd == -1) 161 { 162 /* 163 * Create a socket for listening... 164 */ 165 166 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0); 167 168 if (lis->fd == -1) 169 { 170 cupsdLogMessage(CUPSD_LOG_ERROR, 171 "Unable to open listen socket for address %s:%d - %s.", 172 s, p, strerror(errno)); 173 174#ifdef AF_INET6 175 /* 176 * IPv6 is often disabled while DNS returns IPv6 addresses... 177 */ 178 179 if (lis->address.addr.sa_family != AF_INET6 && 180 (FatalErrors & CUPSD_FATAL_LISTEN)) 181 cupsdEndProcess(getpid(), 0); 182#else 183 if (FatalErrors & CUPSD_FATAL_LISTEN) 184 cupsdEndProcess(getpid(), 0); 185#endif /* AF_INET6 */ 186 187 continue; 188 } 189 190 /* 191 * Set things up to reuse the local address for this port. 192 */ 193 194 val = 1; 195#ifdef __sun 196 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); 197#else 198 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 199#endif /* __sun */ 200 201 /* 202 * Bind to the port we found... 203 */ 204 205#ifdef AF_INET6 206 if (lis->address.addr.sa_family == AF_INET6) 207 { 208# ifdef IPV6_V6ONLY 209 /* 210 * Accept only IPv6 connections on this socket, to avoid 211 * potential security issues and to make all platforms behave 212 * the same. 213 */ 214 215 val = 1; 216# ifdef __sun 217 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val)); 218# else 219 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 220# endif /* __sun */ 221# endif /* IPV6_V6ONLY */ 222 223 status = bind(lis->fd, (struct sockaddr *)&(lis->address), 224 httpAddrLength(&(lis->address))); 225 } 226 else 227#endif /* AF_INET6 */ 228#ifdef AF_LOCAL 229 if (lis->address.addr.sa_family == AF_LOCAL) 230 { 231 mode_t mask; /* Umask setting */ 232 233 234 /* 235 * Remove any existing domain socket file... 236 */ 237 238 unlink(lis->address.un.sun_path); 239 240 /* 241 * Save the current umask and set it to 0 so that all users can access 242 * the domain socket... 243 */ 244 245 mask = umask(0); 246 247 /* 248 * Bind the domain socket... 249 */ 250 251 status = bind(lis->fd, (struct sockaddr *)&(lis->address), 252 httpAddrLength(&(lis->address))); 253 254 /* 255 * Restore the umask... 256 */ 257 258 umask(mask); 259 } 260 else 261#endif /* AF_LOCAL */ 262 status = bind(lis->fd, (struct sockaddr *)&(lis->address), 263 sizeof(lis->address.ipv4)); 264 265 if (status < 0) 266 { 267 cupsdLogMessage(CUPSD_LOG_ERROR, 268 "Unable to bind socket for address %s:%d - %s.", 269 s, p, strerror(errno)); 270 close(lis->fd); 271 lis->fd = -1; 272 273 if (FatalErrors & CUPSD_FATAL_LISTEN) 274 cupsdEndProcess(getpid(), 0); 275 276 continue; 277 } 278 279 /* 280 * Listen for new clients. 281 */ 282 283 if (listen(lis->fd, ListenBackLog) < 0) 284 { 285 cupsdLogMessage(CUPSD_LOG_ERROR, 286 "Unable to listen for clients on address %s:%d - %s.", 287 s, p, strerror(errno)); 288 289 close(lis->fd); 290 lis->fd = -1; 291 292 if (FatalErrors & CUPSD_FATAL_LISTEN) 293 cupsdEndProcess(getpid(), 0); 294 295 continue; 296 } 297 } 298 299 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC); 300 301 if (p) 302 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...", 303 s, p, lis->fd); 304 else 305 { 306 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...", 307 s, lis->fd); 308 309 if (chmod(s, 0140777)) 310 cupsdLogMessage(CUPSD_LOG_ERROR, 311 "Unable to change permisssions on domain socket " 312 "\"%s\" - %s", s, strerror(errno)); 313 } 314 315 /* 316 * Save the first port that is bound to the local loopback or 317 * "any" address... 318 */ 319 320 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 && 321 (httpAddrLocalhost(&(lis->address)) || 322 httpAddrAny(&(lis->address)))) 323 { 324 LocalPort = p; 325 LocalEncryption = lis->encryption; 326 } 327 328#ifdef AF_LOCAL 329 if (lis->address.addr.sa_family == AF_LOCAL && !have_domain) 330 have_domain = lis->address.un.sun_path; 331#endif /* AF_LOCAL */ 332 } 333 334 /* 335 * Make sure that we are listening on localhost! 336 */ 337 338 if (!LocalPort && !have_domain) 339 { 340 cupsdLogMessage(CUPSD_LOG_EMERG, 341 "No Listen or Port lines were found to allow access via " 342 "localhost!"); 343 344 if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN)) 345 cupsdEndProcess(getpid(), 0); 346 } 347 348 /* 349 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on 350 * the listeners... 351 */ 352 353 if (have_domain) 354 { 355 /* 356 * Use domain sockets for the local connection... 357 */ 358 359 cupsdSetEnv("CUPS_SERVER", have_domain); 360 361 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED; 362 } 363 else 364 { 365 /* 366 * Use the default local loopback address for the server... 367 */ 368 369 cupsdSetEnv("CUPS_SERVER", "localhost"); 370 } 371 372 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]); 373 374 if (LocalPort) 375 cupsdSetEnvf("IPP_PORT", "%d", LocalPort); 376 377 /* 378 * Resume listening for connections... 379 */ 380 381 cupsdResumeListening(); 382} 383 384 385/* 386 * 'cupsdStopListening()' - Close all listening sockets... 387 */ 388 389void 390cupsdStopListening(void) 391{ 392 cupsd_listener_t *lis; /* Current listening socket */ 393 394 395 cupsdLogMessage(CUPSD_LOG_DEBUG2, 396 "cupsdStopListening: closing all listen sockets."); 397 398 cupsdPauseListening(); 399 400 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); 401 lis; 402 lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) 403 { 404 if (lis->fd != -1) 405 { 406#ifdef WIN32 407 closesocket(lis->fd); 408#else 409 close(lis->fd); 410#endif /* WIN32 */ 411 412#ifdef AF_LOCAL 413 /* 414 * Remove domain sockets... 415 */ 416 417# ifdef HAVE_LAUNCH_H 418 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd) 419# else 420 if (lis->address.addr.sa_family == AF_LOCAL) 421# endif /* HAVE_LAUNCH_H */ 422 unlink(lis->address.un.sun_path); 423#endif /* AF_LOCAL */ 424 } 425 } 426} 427 428 429/* 430 * End of "$Id: listen.c 11093 2013-07-03 20:48:42Z msweet $". 431 */ 432