kernel - acpi - fix thermal thread loop
[dragonfly.git] / usr.sbin / lpr / common_source / net.c
blobde74d28fa0698a14684f00c2afd6d7d2b33caa1d
1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
38 * From: @(#)common.c 8.5 (Berkeley) 4/28/95
40 * $FreeBSD: src/usr.sbin/lpr/common_source/net.c,v 1.3.2.4 2001/06/25 01:00:56 gad Exp $
41 * $DragonFly: src/usr.sbin/lpr/common_source/net.c,v 1.3 2004/12/18 22:48:03 swildner Exp $
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/uio.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <netdb.h>
54 #include <dirent.h> /* required for lp.h, not used here */
55 #include <errno.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
62 #include "lp.h"
63 #include "lp.local.h"
64 #include "pathnames.h"
67 * 'local_host' is always the hostname of the machine which is running
68 * lpr (lpd, whatever), while 'from_host' either points at 'local_host'
69 * or points at a different buffer when receiving a job from a remote
70 * machine (and that buffer has the hostname of that remote machine).
72 char local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */
73 const char *from_host = local_host; /* client's machine name */
74 const char *from_ip = ""; /* client machine's IP address */
76 #ifdef INET6
77 u_char family = PF_UNSPEC;
78 #else
79 u_char family = PF_INET;
80 #endif
82 extern uid_t uid, euid;
85 * Create a TCP connection to host "rhost" at port "rport".
86 * If rport == 0, then use the printer service port.
87 * Most of this code comes from rcmd.c.
89 int
90 getport(const struct printer *pp, const char *rhost, int rport)
92 struct addrinfo hints, *res, *ai;
93 int s, timo = 1, lport = IPPORT_RESERVED - 1;
94 int err, refused = 0;
97 * Get the host address and port number to connect to.
99 if (rhost == NULL)
100 fatal(pp, "no remote host to connect to");
101 memset(&hints, 0, sizeof(hints));
102 hints.ai_family = family;
103 hints.ai_socktype = SOCK_STREAM;
104 hints.ai_protocol = 0;
105 err = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
106 &hints, &res);
107 if (err)
108 fatal(pp, "%s\n", gai_strerror(err));
109 if (rport != 0)
110 ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
113 * Try connecting to the server.
115 ai = res;
116 retry:
117 seteuid(euid);
118 s = rresvport_af(&lport, ai->ai_family);
119 seteuid(uid);
120 if (s < 0) {
121 if (errno != EAGAIN) {
122 if (ai->ai_next) {
123 ai = ai->ai_next;
124 goto retry;
126 if (refused && timo <= 16) {
127 sleep(timo);
128 timo *= 2;
129 refused = 0;
130 ai = res;
131 goto retry;
134 freeaddrinfo(res);
135 return(-1);
137 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
138 err = errno;
139 close(s);
140 errno = err;
142 * This used to decrement lport, but the current semantics
143 * of rresvport do not provide such a function (in fact,
144 * rresvport should guarantee that the chosen port will
145 * never result in an EADDRINUSE).
147 if (errno == EADDRINUSE) {
148 goto retry;
151 if (errno == ECONNREFUSED)
152 refused++;
154 if (ai->ai_next != NULL) {
155 ai = ai->ai_next;
156 goto retry;
158 if (refused && timo <= 16) {
159 sleep(timo);
160 timo *= 2;
161 refused = 0;
162 ai = res;
163 goto retry;
165 freeaddrinfo(res);
166 return(-1);
168 freeaddrinfo(res);
169 return(s);
173 * Figure out whether the local machine is the same
174 * as the remote machine (RM) entry (if it exists).
175 * We do this by counting the intersection of our
176 * address list and theirs. This is better than the
177 * old method (comparing the canonical names), as it
178 * allows load-sharing between multiple print servers.
179 * The return value is an error message which must be
180 * free()d.
182 char *
183 checkremote(struct printer *pp)
185 char lclhost[MAXHOSTNAMELEN];
186 struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
187 char *err;
188 int ncommonaddrs, error;
189 char h1[NI_MAXHOST], h2[NI_MAXHOST];
191 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
192 pp->remote = 1;
193 return NULL;
196 pp->remote = 0; /* assume printer is local */
197 if (pp->remote_host == NULL)
198 return NULL;
200 /* get the addresses of the local host */
201 gethostname(lclhost, sizeof(lclhost));
202 lclhost[sizeof(lclhost) - 1] = '\0';
204 memset(&hints, 0, sizeof(hints));
205 hints.ai_family = family;
206 hints.ai_socktype = SOCK_STREAM;
207 hints.ai_flags = AI_PASSIVE;
208 if ((error = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
209 asprintf(&err, "unable to get official name "
210 "for local machine %s: %s",
211 lclhost, gai_strerror(error));
212 return err;
215 /* get the official name of RM */
216 memset(&hints, 0, sizeof(hints));
217 hints.ai_family = family;
218 hints.ai_socktype = SOCK_STREAM;
219 hints.ai_flags = AI_PASSIVE;
220 if ((error = getaddrinfo(pp->remote_host, NULL,
221 &hints, &remote_res)) != 0) {
222 asprintf(&err, "unable to get address list for "
223 "remote machine %s: %s",
224 pp->remote_host, gai_strerror(error));
225 freeaddrinfo(local_res);
226 return err;
229 ncommonaddrs = 0;
230 for (lr = local_res; lr; lr = lr->ai_next) {
231 h1[0] = '\0';
232 if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1),
233 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0)
234 continue;
235 for (rr = remote_res; rr; rr = rr->ai_next) {
236 h2[0] = '\0';
237 if (getnameinfo(rr->ai_addr, rr->ai_addrlen,
238 h2, sizeof(h2), NULL, 0,
239 NI_NUMERICHOST | NI_WITHSCOPEID) != 0)
240 continue;
241 if (strcmp(h1, h2) == 0)
242 ncommonaddrs++;
247 * if the two hosts do not share at least one IP address
248 * then the printer must be remote.
250 if (ncommonaddrs == 0)
251 pp->remote = 1;
252 freeaddrinfo(local_res);
253 freeaddrinfo(remote_res);
254 return NULL;
258 * This isn't really network-related, but it's used here to write
259 * multi-part strings onto sockets without using stdio. Return
260 * values are as for writev(2).
262 ssize_t
263 writel(int strm, ...)
265 va_list ap;
266 int i, n;
267 const char *cp;
268 #define NIOV 12
269 struct iovec iov[NIOV], *iovp = iov;
270 ssize_t retval;
272 /* first count them */
273 va_start(ap, strm);
274 n = 0;
275 do {
276 cp = va_arg(ap, char *);
277 n++;
278 } while (cp);
279 va_end(ap);
280 n--; /* correct for count of trailing null */
282 if (n > NIOV) {
283 iovp = malloc(n * sizeof *iovp);
284 if (iovp == 0)
285 return -1;
288 /* now make up iovec and send */
289 va_start(ap, strm);
290 for (i = 0; i < n; i++) {
291 iovp[i].iov_base = va_arg(ap, char *);
292 iovp[i].iov_len = strlen(iovp[i].iov_base);
294 va_end(ap);
295 retval = writev(strm, iovp, n);
296 if (iovp != iov)
297 free(iovp);
298 return retval;