diff options
Diffstat (limited to 'usr/src/cmd/lp/model/netpr/netpr.c')
-rw-r--r-- | usr/src/cmd/lp/model/netpr/netpr.c | 118 |
1 files changed, 114 insertions, 4 deletions
diff --git a/usr/src/cmd/lp/model/netpr/netpr.c b/usr/src/cmd/lp/model/netpr/netpr.c index ee2614b8f6..bdce543aa5 100644 --- a/usr/src/cmd/lp/model/netpr/netpr.c +++ b/usr/src/cmd/lp/model/netpr/netpr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,15 +35,126 @@ #include <unistd.h> #include <sys/mman.h> #include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> #include <fcntl.h> #include <syslog.h> +#include <sys/utsname.h> #include "netpr.h" + static void usage_exit(); static void pipehandler(int); char data_file_type = 0; +/* + * null() is to be used as a signal handler that does nothing. It is used in + * place of SIG_IGN, because we want the signal to be delivered and + * interupt the current system call. + */ +static void +null(int i) +{ + syslog(LOG_DEBUG, "null(%d)", i); +} + +/* + * net_open() opens a tcp connection to the printer port on the host specified + * in the arguments passed in. If the connection is not made in the + * timeout (in seconds) passed in, an error it returned. If the host is + * unknown, an error is returned. If all is well, a file descriptor is + * returned to be used for future communications. + */ +int +net_open(char *host, int timeout) +{ + struct hostent *hp; + struct servent *sp; + struct sockaddr_in6 sin; + void (*old_handler)(); + static struct utsname uts; + + int s, + lport, + err, + error_num; + unsigned timo = 1; + + syslog(LOG_DEBUG, "net_open(%s, %d)", (host != NULL ? host : "NULL"), + timeout); + /* + * Get the host address and port number to connect to. + */ + if (host == NULL) { + return (-1); + } + + (void) memset((char *)&sin, NULL, sizeof (sin)); + if ((hp = getipnodebyname(host, AF_INET6, AI_DEFAULT, + &error_num)) == NULL) { + syslog(LOG_DEBUG|LOG_ERR, "unknown host %s " + "getipnodebyname() returned %d", host, error_num); + return (NETWORK_ERROR_HOST); + } + (void) memcpy((caddr_t)&sin.sin6_addr, hp->h_addr, hp->h_length); + sin.sin6_family = hp->h_addrtype; + freehostent(hp); + + if ((sp = getservbyname("printer", "tcp")) == NULL) { + syslog(LOG_DEBUG|LOG_ERR, "printer/tcp: unknown service"); + return (NETWORK_ERROR_SERVICE); + } + sin.sin6_port = sp->s_port; + +retry: + /* + * Try connecting to the server. + * + * Use 0 as lport means that rresvport_af() will bind to a port in + * the anonymous privileged port range. + */ + lport = 0; + s = rresvport_af(&lport, AF_INET6); + if (s < 0) + return (NETWORK_ERROR_PORT); + + old_handler = signal(SIGALRM, null); + (void) alarm(timeout); + if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { + (void) alarm(0); + (void) signal(SIGALRM, old_handler); + err = errno; + (void) close(s); + errno = err; + if (errno == EADDRINUSE) { + goto retry; + } + /* + * If connecting to the local system fails, try + * again with "localhost" address instead. + */ + if (uts.nodename[0] == '\0') + (void) uname(&uts); + if (strcmp(host, uts.nodename) == 0) { + IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_LOOPBACK), + &sin.sin6_addr); + sin.sin6_family = AF_INET6; + goto retry; + } + if (errno == ECONNREFUSED && timo <= 16) { + (void) sleep(timo); + timo *= 2; + goto retry; + } + return (NETWORK_ERROR_UNKNOWN); + } + (void) alarm(0); + (void) signal(SIGALRM, old_handler); + return (s); +} + int main(int argc, char *argv[]) { |