Example #1
0
static int				/* O - 0 on success or -1 on error */
try_connect(http_addr_t *addr,		/* I - Socket address */
            const char  *addrname,	/* I - Hostname or IP address */
            int         port)		/* I - Port number */
{
  int	fd;				/* Socket */
  int	status;				/* Connection status */


  debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
               port == 515 ? "lpd" : "socket", addrname, port);

  if ((fd = socket(httpAddrFamily(addr), SOCK_STREAM, 0)) < 0)
  {
    fprintf(stderr, "ERROR: Unable to create socket: %s\n",
            strerror(errno));
    return (-1);
  }

  _httpAddrSetPort(addr, port);

  alarm(1);

  status = connect(fd, (void *)addr, (socklen_t)httpAddrLength(addr));

  close(fd);
  alarm(0);

  return (status);
}
int					/* O - 1 on success, 0 on error */
_cupsSNMPWrite(
    int            fd,			/* I - SNMP socket */
    http_addr_t    *address,		/* I - Address to send to */
    int            version,		/* I - SNMP version */
    const char     *community,		/* I - Community name */
    cups_asn1_t    request_type,	/* I - Request type */
    const unsigned request_id,		/* I - Request ID */
    const int      *oid)		/* I - OID */
{
  int		i;			/* Looping var */
  cups_snmp_t	packet;			/* SNMP message packet */
  unsigned char	buffer[CUPS_SNMP_MAX_PACKET];
					/* SNMP message buffer */
  int		bytes;			/* Size of message */
  http_addr_t	temp;			/* Copy of address */


 /*
  * Range check input...
  */

  DEBUG_printf(("4_cupsSNMPWrite(fd=%d, address=%p, version=%d, "
                "community=\"%s\", request_type=%d, request_id=%u, oid=%p)",
		fd, address, version, community, request_type, request_id, oid));

  if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community ||
      (request_type != CUPS_ASN1_GET_REQUEST &&
       request_type != CUPS_ASN1_GET_NEXT_REQUEST) || request_id < 1 || !oid)
  {
    DEBUG_puts("5_cupsSNMPWrite: Returning 0 (bad arguments)");

    return (0);
  }

 /*
  * Create the SNMP message...
  */

  memset(&packet, 0, sizeof(packet));

  packet.version      = version;
  packet.request_type = request_type;
  packet.request_id   = request_id;
  packet.object_type  = CUPS_ASN1_NULL_VALUE;

  strlcpy(packet.community, community, sizeof(packet.community));

  for (i = 0; oid[i] >= 0 && i < (CUPS_SNMP_MAX_OID - 1); i ++)
    packet.object_name[i] = oid[i];
  packet.object_name[i] = -1;

  if (oid[i] >= 0)
  {
    DEBUG_puts("5_cupsSNMPWrite: Returning 0 (OID too big)");

    errno = E2BIG;
    return (0);
  }

  bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);

  if (bytes < 0)
  {
    DEBUG_puts("5_cupsSNMPWrite: Returning 0 (request too big)");

    errno = E2BIG;
    return (0);
  }

  asn1_debug("DEBUG: OUT ", buffer, bytes, 0);

 /*
  * Send the message...
  */

  temp = *address;

  _httpAddrSetPort(&temp, CUPS_SNMP_PORT);

  return (sendto(fd, buffer, bytes, 0, (void *)&temp,
                 httpAddrLength(&temp)) == bytes);
}
Example #3
0
/* A non-blocking test whether it is possible to connect to a CUPS server specified
 * inside of GtkCupsConnectionTest structure.
 *  - you need to check it more then once.
 * The connection is closed after a successful connection.
 */
GtkCupsConnectionState 
gtk_cups_connection_test_get_state (GtkCupsConnectionTest *test)
{
  GtkCupsConnectionState result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  http_addrlist_t       *iter;
  gint                   error_code;
  gint                   flags;
  gint                   code;

  if (test == NULL)
    return GTK_CUPS_CONNECTION_NOT_AVAILABLE;

  if (test->at_init == GTK_CUPS_CONNECTION_AVAILABLE)
    {
      test->at_init = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
      return GTK_CUPS_CONNECTION_AVAILABLE;
    }
  else
    {
      if (test->socket == -1)
        {
          if (test->last_wrong_addr != NULL && test->last_wrong_addr->next != NULL)
            iter = test->last_wrong_addr->next;
          else
            {
              test->last_wrong_addr = NULL;
              iter = test->addrlist;
            }

          while (iter)
            {
              test->socket = socket (iter->addr.addr.sa_family,
                                     SOCK_STREAM,
                                     0);

              if (test->socket >= 0)
                {
                  flags = fcntl (test->socket, F_GETFL);

                  if (flags != -1)
                    flags |= O_NONBLOCK;

                  fcntl (test->socket, F_SETFL, flags);
              
                  test->current_addr = iter;
              
                  break;
                }
               iter = iter->next;
            }
        }

      if (test->socket >= 0)
        {
          code = connect (test->socket,
                          &test->current_addr->addr.addr,
                          httpAddrLength (&test->current_addr->addr));

          error_code = errno;

          if (code == 0 || error_code == EISCONN)
            {
              close (test->socket);
              test->socket = -1;
              test->current_addr = NULL;
              result = GTK_CUPS_CONNECTION_AVAILABLE;
            }
          else
            {
              if (error_code == EALREADY || error_code == EINPROGRESS)
                result = GTK_CUPS_CONNECTION_IN_PROGRESS;
              else
                {
                  close (test->socket);
                  test->socket = -1;
                  test->last_wrong_addr = test->current_addr;
                  result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
                }
            }
         }

      return result;
    }
}
Example #4
0
static int				/* O - Zero on success, non-zero on failure */
lpd_queue(const char      *hostname,	/* I - Host to connect to */
          http_addrlist_t *addrlist,	/* I - List of host addresses */
          const char      *printer,	/* I - Printer/queue name */
	  int             print_fd,	/* I - File to print */
	  int             snmp_fd,	/* I - SNMP socket */
	  int             mode,		/* I - Print mode */
          const char      *user,	/* I - Requesting user */
	  const char      *title,	/* I - Job title */
	  int             copies,	/* I - Number of copies */
	  int             banner,	/* I - Print LPD banner? */
          int             format,	/* I - Format specifier */
          int             order,	/* I - Order of data/control files */
	  int             reserve,	/* I - Reserve ports? */
	  int             manual_copies,/* I - Do copies by hand... */
	  int             timeout,	/* I - Timeout... */
	  int             contimeout,	/* I - Connection timeout */
	  const char      *orighost)	/* I - job-originating-host-name */
{
  char			localhost[255];	/* Local host name */
  int			error;		/* Error number */
  struct stat		filestats;	/* File statistics */
  int			lport;		/* LPD connection local port */
  int			fd;		/* LPD socket */
  char			control[10240],	/* LPD control 'file' */
			*cptr;		/* Pointer into control file string */
  char			status;		/* Status byte from command */
  int			delay;		/* Delay for retries... */
  char			addrname[256];	/* Address name */
  http_addrlist_t	*addr;		/* Socket address */
  int			have_supplies;	/* Printer supports supply levels? */
  int			copy;		/* Copies written */
  time_t		start_time;	/* Time of first connect */
  size_t		nbytes;		/* Number of bytes written */
  off_t			tbytes;		/* Total bytes written */
  char			buffer[32768];	/* Output buffer */
#ifdef WIN32
  DWORD			tv;		/* Timeout in milliseconds */
#else
  struct timeval	tv;		/* Timeout in secs and usecs */
#endif /* WIN32 */


 /*
  * Remember when we started trying to connect to the printer...
  */

  start_time = time(NULL);

 /*
  * Loop forever trying to print the file...
  */

  while (!abort_job)
  {
   /*
    * First try to reserve a port for this connection...
    */

    fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n", hostname,
            httpAddrPort(&(addrlist->addr)), printer);
    _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));

    for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
             delay = 5;;
         addr = addr->next)
    {
     /*
      * Stop if this job has been canceled...
      */

      if (abort_job)
        return (CUPS_BACKEND_FAILED);

     /*
      * Choose the next priviledged port...
      */

      if (!addr)
        addr = addrlist;

      lport --;

      if (lport < 721 && reserve == RESERVE_RFC1179)
	lport = 731;
      else if (lport < 1)
	lport = 1023;

#ifdef HAVE_GETEUID
      if (geteuid() || !reserve)
#else
      if (getuid() || !reserve)
#endif /* HAVE_GETEUID */
      {
       /*
	* Just create a regular socket...
	*/

	if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
	{
	  perror("DEBUG: Unable to create socket");
	  sleep(1);

          continue;
	}

        lport = 0;
      }
      else
      {
       /*
	* We're running as root and want to comply with RFC 1179.  Reserve a
	* priviledged lport between 721 and 731...
	*/

	if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
	{
	  perror("DEBUG: Unable to reserve port");
	  sleep(1);

	  continue;
	}
      }

     /*
      * Connect to the printer or server...
      */

      if (abort_job)
      {
	close(fd);

	return (CUPS_BACKEND_FAILED);
      }

      if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
	break;

      error = errno;
      close(fd);

      if (addr->next)
        continue;

      if (getenv("CLASS") != NULL)
      {
       /*
        * If the CLASS environment variable is set, the job was submitted
	* to a class and not to a specific queue.  In this case, we want
	* to abort immediately so that the job can be requeued on the next
	* available printer in the class.
	*/

        _cupsLangPrintFilter(stderr, "INFO",
			     _("Unable to contact printer, queuing on next "
			       "printer in class."));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));

      if (error == ECONNREFUSED || error == EHOSTDOWN ||
          error == EHOSTUNREACH)
      {
        if (contimeout && (time(NULL) - start_time) > contimeout)
	{
	  _cupsLangPrintFilter(stderr, "ERROR",
			       _("The printer is not responding."));
	  return (CUPS_BACKEND_FAILED);
	}

	switch (error)
	{
	  case EHOSTDOWN :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer may not exist or "
			             "is unavailable at this time."));
	      break;

	  case EHOSTUNREACH :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer is unreachable at "
				     "this time."));
	      break;

	  case ECONNREFUSED :
	  default :
	      _cupsLangPrintFilter(stderr, "WARNING",
	                           _("The printer is in use."));
	      break;
        }

	sleep(delay);

	if (delay < 30)
	  delay += 5;
      }
      else if (error == EADDRINUSE)
      {
       /*
	* Try on another port...
	*/

	sleep(1);
      }
      else
      {
	_cupsLangPrintFilter(stderr, "ERROR",
	                     _("The printer is not responding."));
	sleep(30);
      }
    }

   /*
    * Set the timeout...
    */

#ifdef WIN32
    tv = (DWORD)(timeout * 1000);

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
#else
    tv.tv_sec  = timeout;
    tv.tv_usec = 0;

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif /* WIN32 */

    fputs("STATE: -connecting-to-device\n", stderr);
    _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));

    fprintf(stderr, "DEBUG: Connected to %s:%d (local port %d)...\n",
	    httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
	    httpAddrPort(&(addr->addr)), lport);

   /*
    * See if the printer supports SNMP...
    */

    if (snmp_fd >= 0)
      have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), NULL,
                                           NULL);
    else
      have_supplies = 0;

   /*
    * Check for side-channel requests...
    */

    backendCheckSideChannel(snmp_fd, &(addrlist->addr));

   /*
    * Next, open the print file and figure out its size...
    */

    if (print_fd)
    {
     /*
      * Use the size from the print file...
      */

      if (fstat(print_fd, &filestats))
      {
	close(fd);

	perror("DEBUG: unable to stat print file");
	return (CUPS_BACKEND_FAILED);
      }

      filestats.st_size *= manual_copies;
    }
    else
    {
     /*
      * Use a "very large value" for the size so that the printer will
      * keep printing until we close the connection...
      */

#ifdef _LARGEFILE_SOURCE
      filestats.st_size = (size_t)(999999999999.0);
#else
      filestats.st_size = 2147483647;
#endif /* _LARGEFILE_SOURCE */
    }

   /*
    * Send a job header to the printer, specifying no banner page and
    * literal output...
    */

    if (lpd_command(fd, "\002%s\n",
                    printer))		/* Receive print job(s) */
    {
      close(fd);
      return (CUPS_BACKEND_FAILED);
    }

    if (orighost && _cups_strcasecmp(orighost, "localhost"))
      strlcpy(localhost, orighost, sizeof(localhost));
    else
      httpGetHostname(NULL, localhost, sizeof(localhost));

    snprintf(control, sizeof(control),
             "H%.31s\n"		/* RFC 1179, Section 7.2 - host name <= 31 chars */
	     "P%.31s\n"		/* RFC 1179, Section 7.2 - user name <= 31 chars */
	     "J%.99s\n",	/* RFC 1179, Section 7.2 - job name <= 99 chars */
	     localhost, user, title);
    cptr = control + strlen(control);

    if (banner)
    {
      snprintf(cptr, sizeof(control) - (cptr - control),
               "C%.31s\n"	/* RFC 1179, Section 7.2 - class name <= 31 chars */
	       "L%s\n",
               localhost, user);
      cptr   += strlen(cptr);
    }

    while (copies > 0)
    {
      snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
               format, (int)getpid() % 1000, localhost);
      cptr   += strlen(cptr);
      copies --;
    }

    snprintf(cptr, sizeof(control) - (cptr - control),
             "UdfA%03d%.15s\n"
	     "N%.131s\n",	/* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
             (int)getpid() % 1000, localhost, title);

    fprintf(stderr, "DEBUG: Control file is:\n%s", control);

    if (order == ORDER_CONTROL_DATA)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%u bytes)\n",
	      (unsigned)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");

      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
	                       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }
    else
      status = 0;

    if (status == 0)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the print file...
      */

      if (lpd_command(fd, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
                      CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
		      localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending data file (" CUPS_LLFMT " bytes)\n",
	      CUPS_LLCAST filestats.st_size);

      tbytes = 0;
      for (copy = 0; copy < manual_copies; copy ++)
      {
	lseek(print_fd, 0, SEEK_SET);

	while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
	{
	  _cupsLangPrintFilter(stderr, "INFO",
			       _("Spooling job, %.0f%% complete."),
			       100.0 * tbytes / filestats.st_size);

	  if (lpd_write(fd, buffer, nbytes) < nbytes)
	  {
	    perror("DEBUG: Unable to send print file to printer");
            break;
	  }
	  else
            tbytes += nbytes;
	}
      }

      if (mode == MODE_STANDARD)
      {
	if (tbytes < filestats.st_size)
	  status = errno;
	else if (lpd_write(fd, "", 1) < 1)
	{
	  perror("DEBUG: Unable to send trailing nul to printer");
	  status = errno;
	}
	else
	{
	 /*
          * Read the status byte from the printer; if we can't read the byte
	  * back now, we should set status to "errno", however at this point
	  * we know the printer got the whole file and we don't necessarily
	  * want to requeue it over and over...
	  */

          if (recv(fd, &status, 1, 0) < 1)
	  {
	    _cupsLangPrintFilter(stderr, "WARNING",
			         _("The printer did not respond."));
	    status = 0;
          }
	}
      }
      else
        status = 0;

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept data file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Data file sent successfully."));
    }

    if (status == 0 && order == ORDER_DATA_CONTROL)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%lu bytes)\n",
	      (unsigned long)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");
      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
			       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }

   /*
    * Collect the final supply levels as needed...
    */

    if (have_supplies)
      backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);

   /*
    * Close the socket connection and input file...
    */

    close(fd);

    if (status == 0)
      return (CUPS_BACKEND_OK);

   /*
    * Waiting for a retry...
    */

    sleep(30);
  }

 /*
  * If we get here, then the job has been canceled...
  */

  return (CUPS_BACKEND_FAILED);
}
Example #5
0
File: lpd.c Project: apple/cups
static int				/* O  - Socket or -1 on error */
cups_rresvport(int *port,		/* IO - Port number to bind to */
               int family)		/* I  - Address family */
{
  http_addr_t	addr;			/* Socket address */
  int		fd;			/* Socket file descriptor */


 /*
  * Try to create an IPv4 socket...
  */

  if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
    return (-1);

 /*
  * Initialize the address buffer...
  */

  memset(&addr, 0, sizeof(addr));
  addr.addr.sa_family = (sa_family_t)family;

 /*
  * Try to bind the socket to a reserved port...
  */

  while (*port > 511)
  {
   /*
    * Set the port number...
    */

    _httpAddrSetPort(&addr, *port);

   /*
    * Try binding the port to the socket; return if all is OK...
    */

    if (!bind(fd, (struct sockaddr *)&addr, (socklen_t)httpAddrLength(&addr)))
      return (fd);

   /*
    * Stop if we have any error other than "address already in use"...
    */

    if (errno != EADDRINUSE)
    {
      httpAddrClose(NULL, fd);

      return (-1);
    }

   /*
    * Try the next port...
    */

    (*port)--;
  }

 /*
  * Wasn't able to bind to a reserved port, so close the socket and return
  * -1...
  */

#ifdef WIN32
  closesocket(fd);
#else
  close(fd);
#endif /* WIN32 */

  return (-1);
}
Example #6
0
void
cupsdStartListening(void)
{
  int			status;		/* Bind result */
  int			p,		/* Port number */
			val;		/* Parameter value */
  cupsd_listener_t	*lis;		/* Current listening socket */
  char			s[256];		/* String addresss */
  const char		*have_domain;	/* Have a domain socket? */
  static const char * const encryptions[] =
		{			/* Encryption values */
		  "IfRequested",
		  "Never",
		  "Required",
		  "Always"
		};


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
                  cupsArrayCount(Listeners));

 /*
  * Setup socket listeners...
  */

  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
           have_domain = NULL;
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
  {
    httpAddrString(&(lis->address), s, sizeof(s));
    p = httpAddrPort(&(lis->address));

   /*
    * If needed, create a socket for listening...
    */

    if (lis->fd == -1)
    {
     /*
      * Create a socket for listening...
      */

      lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);

      if (lis->fd == -1)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to open listen socket for address %s:%d - %s.",
			s, p, strerror(errno));

#ifdef AF_INET6
       /*
        * IPv6 is often disabled while DNS returns IPv6 addresses...
	*/

	if (lis->address.addr.sa_family != AF_INET6 &&
	    (FatalErrors & CUPSD_FATAL_LISTEN))
	  cupsdEndProcess(getpid(), 0);
#else
	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);
#endif /* AF_INET6 */

	continue;
      }

     /*
      * Set things up to reuse the local address for this port.
      */

      val = 1;
#ifdef __sun
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
#else
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
#endif /* __sun */

     /*
      * Bind to the port we found...
      */

#ifdef AF_INET6
      if (lis->address.addr.sa_family == AF_INET6)
      {
#  ifdef IPV6_V6ONLY
       /*
	* Accept only IPv6 connections on this socket, to avoid
	* potential security issues and to make all platforms behave
	* the same.
	*/

	val = 1;
#    ifdef __sun
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
#    else
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
#    endif /* __sun */
#  endif /* IPV6_V6ONLY */

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));
      }
      else
#endif /* AF_INET6 */
#ifdef AF_LOCAL
      if (lis->address.addr.sa_family == AF_LOCAL)
      {
	mode_t	mask;			/* Umask setting */


       /*
	* Remove any existing domain socket file...
	*/

	unlink(lis->address.un.sun_path);

       /*
	* Save the current umask and set it to 0 so that all users can access
	* the domain socket...
	*/

	mask = umask(0);

       /*
	* Bind the domain socket...
	*/

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));

       /*
	* Restore the umask...
	*/

	umask(mask);
      }
      else
#endif /* AF_LOCAL */
      status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		    sizeof(lis->address.ipv4));

      if (status < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to bind socket for address %s:%d - %s.",
			s, p, strerror(errno));
	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

	continue;
      }

     /*
      * Listen for new clients.
      */

      if (listen(lis->fd, ListenBackLog) < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to listen for clients on address %s:%d - %s.",
			s, p, strerror(errno));

	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

        continue;
      }
    }

    fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);

    if (p)
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
        	      s, p, lis->fd);
    else
    {
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
        	      s, lis->fd);

      if (chmod(s, 0140777))
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to change permisssions on domain socket "
			"\"%s\" - %s", s, strerror(errno));
    }

   /*
    * Save the first port that is bound to the local loopback or
    * "any" address...
    */

    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
        (httpAddrLocalhost(&(lis->address)) ||
         httpAddrAny(&(lis->address))))
    {
      LocalPort       = p;
      LocalEncryption = lis->encryption;
    }

#ifdef AF_LOCAL
    if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
      have_domain = lis->address.un.sun_path;
#endif /* AF_LOCAL */
  }

 /*
  * Make sure that we are listening on localhost!
  */

  if (!LocalPort && !have_domain)
  {
    cupsdLogMessage(CUPSD_LOG_EMERG,
                    "No Listen or Port lines were found to allow access via "
		    "localhost!");

    if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
      cupsdEndProcess(getpid(), 0);
  }

 /*
  * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
  * the listeners...
  */

  if (have_domain)
  {
   /*
    * Use domain sockets for the local connection...
    */

    cupsdSetEnv("CUPS_SERVER", have_domain);

    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
  }
  else
  {
   /*
    * Use the default local loopback address for the server...
    */

    cupsdSetEnv("CUPS_SERVER", "localhost");
  }

  cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);

  if (LocalPort)
    cupsdSetEnvf("IPP_PORT", "%d", LocalPort);

 /*
  * Resume listening for connections...
  */

  cupsdResumeListening();
}
Example #7
0
http_addrlist_t *			/* O - Connected address or NULL on failure */
httpAddrConnect2(
    http_addrlist_t *addrlist,		/* I - List of potential addresses */
    int             *sock,		/* O - Socket */
    int             msec,		/* I - Timeout in milliseconds */
    int             *cancel)		/* I - Pointer to "cancel" variable */
{
  int			val;		/* Socket option value */
#ifndef WIN32
  int			flags;		/* Socket flags */
#endif /* !WIN32 */
  int			remaining;	/* Remaining timeout */
  int			i,		/* Looping var */
			nfds,		/* Number of file descriptors */
			fds[100],	/* Socket file descriptors */
			result;		/* Result from select() or poll() */
  http_addrlist_t	*addrs[100];	/* Addresses */
#ifndef HAVE_POLL
  int			max_fd = -1;	/* Highest file descriptor */
#endif /* !HAVE_POLL */
#ifdef O_NONBLOCK
#  ifdef HAVE_POLL
  struct pollfd		pfds[100];	/* Polled file descriptors */
#  else
  fd_set		input_set,	/* select() input set */
			output_set,	/* select() output set */
			error_set;	/* select() error set */
  struct timeval	timeout;	/* Timeout */
#  endif /* HAVE_POLL */
#endif /* O_NONBLOCK */
#ifdef DEBUG
  socklen_t		len;		/* Length of value */
  http_addr_t		peer;		/* Peer address */
  char			temp[256];	/* Temporary address string */
#endif /* DEBUG */


  DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel));

  if (!sock)
  {
    errno = EINVAL;
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    return (NULL);
  }

  if (cancel && *cancel)
    return (NULL);

  if (msec <= 0)
    msec = INT_MAX;

 /*
  * Loop through each address until we connect or run out of addresses...
  */

  nfds      = 0;
  remaining = msec;

  while (remaining > 0)
  {
    if (cancel && *cancel)
    {
      while (nfds > 0)
      {
        nfds --;
	httpAddrClose(NULL, fds[nfds]);
      }

      return (NULL);
    }

    if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])))
    {
     /*
      * Create the socket...
      */

      DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));

      if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
      {
       /*
	* Don't abort yet, as this could just be an issue with the local
	* system not being configured with IPv4/IPv6/domain socket enabled.
	*
	* Just skip this address...
	*/

        addrlist = addrlist->next;
	continue;
      }

     /*
      * Set options...
      */

      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));

#ifdef SO_REUSEPORT
      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_REUSEPORT */

#ifdef SO_NOSIGPIPE
      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_NOSIGPIPE */

     /*
      * Using TCP_NODELAY improves responsiveness, especially on systems
      * with a slow loopback interface...
      */

      val = 1;
      setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));

#ifdef FD_CLOEXEC
     /*
      * Close this socket when starting another process...
      */

      fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
#endif /* FD_CLOEXEC */

#ifdef O_NONBLOCK
     /*
      * Do an asynchronous connect by setting the socket non-blocking...
      */

      DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));

      flags = fcntl(fds[nfds], F_GETFL, 0);
      fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
#endif /* O_NONBLOCK */

     /*
      * Then connect...
      */

      if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
      {
	DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));

#ifdef O_NONBLOCK
	fcntl(fds[nfds], F_SETFL, flags);
#endif /* O_NONBLOCK */

	*sock = fds[nfds];

	while (nfds > 0)
	{
	  nfds --;
	  httpAddrClose(NULL, fds[nfds]);
	}

	return (addrlist);
      }

#ifdef WIN32
      if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
#else
      if (errno != EINPROGRESS && errno != EWOULDBLOCK)
#endif /* WIN32 */
      {
	DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
	httpAddrClose(NULL, fds[nfds]);
	addrlist = addrlist->next;
	continue;
      }

#ifndef WIN32
      fcntl(fds[nfds], F_SETFL, flags);
#endif /* !WIN32 */

#ifndef HAVE_POLL
      if (fds[nfds] > max_fd)
	max_fd = fds[nfds];
#endif /* !HAVE_POLL */

      addrs[nfds] = addrlist;
      nfds ++;
      addrlist = addrlist->next;
    }

    if (!addrlist && nfds == 0)
      break;

   /*
    * See if we can connect to any of the addresses so far...
    */

#ifdef O_NONBLOCK
    DEBUG_puts("1httpAddrConnect2: Finishing async connect()");

    do
    {
      if (cancel && *cancel)
      {
       /*
	* Close this socket and return...
	*/

	DEBUG_puts("1httpAddrConnect2: Canceled connect()");

	while (nfds > 0)
	{
	  nfds --;
	  httpAddrClose(NULL, fds[nfds]);
	}

	*sock = -1;

	return (NULL);
      }

#  ifdef HAVE_POLL
      for (i = 0; i < nfds; i ++)
      {
	pfds[i].fd     = fds[i];
	pfds[i].events = POLLIN | POLLOUT;
      }

      result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining);

      DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));

#  else
      FD_ZERO(&input_set);
      for (i = 0; i < nfds; i ++)
	FD_SET(fds[i], &input_set);
      output_set = input_set;
      error_set  = input_set;

      timeout.tv_sec  = 0;
      timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000;

      result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout);

      DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
#  endif /* HAVE_POLL */
    }
#  ifdef WIN32
    while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
#  else
    while (result < 0 && (errno == EINTR || errno == EAGAIN));
#  endif /* WIN32 */

    if (result > 0)
    {
      http_addrlist_t *connaddr = NULL;	/* Connected address, if any */

      for (i = 0; i < nfds; i ++)
      {
#  ifdef HAVE_POLL
	DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
	if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
#  else
	if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set))
#  endif /* HAVE_POLL */
	{
	  *sock    = fds[i];
	  connaddr = addrs[i];

#  ifdef DEBUG
	  len   = sizeof(peer);
	  if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
	    DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
#  endif /* DEBUG */
	}
#  ifdef HAVE_POLL
	else if (pfds[i].revents & (POLLERR | POLLHUP))
#  else
	else if (FD_ISSET(fds[i], &error_set))
#  endif /* HAVE_POLL */
        {
         /*
          * Error on socket, remove from the "pool"...
          */

	  httpAddrClose(NULL, fds[i]);
          nfds --;
          if (i < nfds)
          {
            memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
            memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
          }
          i --;
        }
      }

      if (connaddr)
        return (connaddr);
    }
#endif /* O_NONBLOCK */

    if (addrlist)
      remaining -= 100;
    else
      remaining -= 250;
  }