1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 /*
32 * create a Datakit connection to a remote destination
33 */
34 #ifndef DIAL
35 static char SCCSID[] = "@(#)dkdial.c 2.7+BNU DKHOST 87/03/09";
36 #endif
37 /*
38 * COMMKIT(TM) Software - Datakit(R) VCS Interface Release 2.0 V1
39 */
40
41 #include <fcntl.h>
42 #include "dk.h"
43 #include <stdio.h>
44 #include <signal.h>
45 #define SIGRTN void
46 #include <setjmp.h>
47 #include <sysexits.h>
48 #include <errno.h>
49
50
51 #define DK_DEFWAIT 89 /* default time to wait for dial return */
52 #define DK_MAXWAIT 600 /* maximum wait to allow the caller - 10 min */
53
54
55 GLOBAL unsigned int dk_timewait = DK_DEFWAIT; /* Caller to dkdial might modify */
56
57 static char Conn_Msg[] = "Can't connect to %s: %s\n";
58 static char Resp_Msg[] = "No response from Datakit";
59
60 static SIGRTN timout(); /* Alarm signal handler */
61 static void setalarm(), usralarm();
62 EXTERN int dkndial();
63 static int Elapsed; /* Alarm time elapsed during dial */
64 static int Timer; /* Current alarm setting */
65 static short TimeErr; /* Alarm clock rang */
66
67 extern char *getenv();
68 EXTERN int dk_verbose, dk_errno;
69
70 GLOBAL int
dkdial(dest)71 dkdial(dest)
72 char *dest;
73 {
74 return(dkndial(dest, atoi(getenv("DKINTF"))));
75 }
76
77 GLOBAL int
dkndial(dest,intf)78 dkndial(dest, intf)
79 char *dest;
80 {
81 short fd; /* Channel Descriptor */
82 SIGRTN (*SigWas)(); /* Caller's alarm handler */
83 unsigned int TimWas; /* Caller's alarm clock */
84 char *key;
85 struct diocdial {
86 struct diocreq iocb;
87 char dialstring[128];
88 } ioreq;
89 char dial_dev[32];
90
91
92 sprintf(dial_dev, "/dev/dk/dial%d", intf);
93
94 /*
95 ** Clear our elapsed time and save caller's alarm stuff.
96 */
97
98 Timer = Elapsed = 0;
99 SigWas = signal(SIGALRM, timout);
100 TimWas = alarm(0);
101
102 /*
103 ** If requested timeout interval is unreasonable, use the default.
104 */
105
106 if ((dk_timewait == 0) || (dk_timewait > DK_MAXWAIT))
107 dk_timewait = DK_DEFWAIT;
108
109 /*
110 ** Do an alarm protected open of the dial device
111 */
112
113 setalarm(dk_timewait);
114
115 if ((fd = open(dial_dev, O_RDWR)) < 0) {
116 setalarm(0);
117 if (dk_verbose)
118 fprintf(stderr, "dkdial: Can't open %s\n", dial_dev);
119 usralarm(TimWas, SigWas);
120 if (errno == EBUSY)
121 return(dk_errno = -EX_TEMPFAIL);
122 else
123 return(dk_errno = -EX_OSFILE);
124 }
125
126 /*
127 ** If the caller has a DKKEY, use it.
128 */
129
130 if((key = getenv("DKKEY")) != NULL && getuid() == geteuid())
131 sprintf(ioreq.dialstring, "%s\n%s", dest, key);
132 else
133 strcpy(ioreq.dialstring, dest);
134
135 ioreq.iocb.req_traffic = 0;
136 ioreq.iocb.req_1param = 0;
137 ioreq.iocb.req_2param = 0;
138
139 /*
140 ** Try to dial the call. If the alarm expires during the ioctl,
141 ** the ioctl will return in error.
142 */
143
144 if (ioctl(fd, DKIODIAL, &ioreq) < 0) {
145 setalarm(0);
146 if (dk_verbose)
147 if (TimeErr)
148 fprintf(stderr, Conn_Msg, Resp_Msg, ioreq.dialstring);
149 else
150 fprintf(stderr, Conn_Msg, ioreq.dialstring, dkerr(ioreq.iocb.req_error));
151
152 setalarm(2); /* Don't wait forever on close */
153 close(fd);
154 usralarm(TimWas, SigWas);
155 if (errno == EBUSY)
156 return(-dkerrmap(dk_errno = -EX_TEMPFAIL));
157 else
158 return(-dkerrmap(dk_errno = ioreq.iocb.req_error));
159 }
160 usralarm(TimWas, SigWas);
161 return (fd);
162 }
163
164 /*
165 ** timout() is the alarm clock signal handling routine. It is called
166 ** whenever the alarm clock expires during dial processing.
167 */
168
169 /* ARGSUSED */
170 static SIGRTN
timout(arg)171 timout(arg)
172 int arg;
173 {
174 TimeErr++;
175 }
176
177 /*
178 ** setalarm() is called to request an alarm at a future time. The residual
179 ** from the previous alarm (if any) is added to the elapsed time counter.
180 */
181
182 static void
setalarm(Seconds)183 setalarm(Seconds)
184 {
185 TimeErr = 0;
186 (void) signal(SIGALRM, timout);
187 Elapsed += Timer - alarm(Seconds);
188 Timer = Seconds;
189 }
190
191 /*
192 ** usralarm() is used to restore the alarm service for the caller.
193 */
194
195 static void
usralarm(TimWas,SigWas)196 usralarm(TimWas, SigWas)
197 int TimWas; /* Caller's alarm clock */
198 SIGRTN (*SigWas)(); /* Caller's alarm handler */
199 {
200 Elapsed += Timer - alarm(0);
201 (void) signal(SIGALRM, SigWas);
202 if (TimWas > 0) {
203 TimWas -= Elapsed;
204 if (TimWas < 2)
205 TimWas = 2;
206 }
207 alarm(TimWas);
208 }
209