1 /* nntpinit.c
2 */
3 /* This software is copyrighted as detailed in the LICENSE file. */
4
5
6 /*#define DECNET *//* If you want decnet support */
7 /*#define EXCELAN *//* Excelan EXOS 205 support */
8 /*#define NONETD *//* Define if you're missing netdb.h */
9
10 #include "EXTERN.h"
11 #include "common.h"
12 #include "nntpclient.h"
13 #include "INTERN.h"
14 #include "nntpinit.h"
15 #include "nntpinit.ih"
16
17 #ifdef SUPPORT_NNTP
18
19 #ifdef WINSOCK
20 #include <winsock.h>
21 WSADATA wsaData;
22 #else
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #ifdef NONETDB
26 # define IPPORT_NNTP ((unsigned short) 119)
27 #else
28 # include <netdb.h>
29 #endif
30 #endif
31
32 #ifdef EXCELAN
33 int connect _((int, struct sockaddr*));
34 unsigned short htons _((unsigned short));
35 unsigned long rhost _((char**));
36 int rresvport p((int));
37 int socket _((int, struct sockproto *, struct sockaddr_in *, int));
38 #endif /* EXCELAN */
39
40 #ifdef DECNET
41 #include <netdnet/dn.h>
42 #include <netdnet/dnetdb.h>
43 #endif /* DECNET */
44
45 #ifndef WINSOCK
46 unsigned long inet_addr _((char*));
47 #ifndef NONETDB
48 struct servent* getservbyname();
49 struct hostent* gethostbyname();
50 #endif
51 #endif
52
53 int
init_nntp()54 init_nntp()
55 {
56 #ifdef WINSOCK
57 if (WSAStartup(0x0101,&wsaData) == 0) {
58 if (wsaData.wVersion == 0x0101)
59 return 1;
60 WSACleanup();
61 }
62 fprintf(stderr,"Unable to initialize WinSock DLL.\n");
63 return -1;
64 #else
65 return 1;
66 #endif
67 }
68
69 int
server_init(machine)70 server_init(machine)
71 char* machine;
72 {
73 int sockt_rd, sockt_wr;
74 #ifdef DECNET
75 char* cp;
76 #endif
77
78 #ifdef DECNET
79 cp = index(machine, ':');
80
81 if (cp && cp[1] == ':') {
82 *cp = '\0';
83 sockt_rd = get_dnet_socket(machine);
84 } else
85 sockt_rd = get_tcp_socket(machine, nntplink.port_number, "nntp");
86 #else /* !DECNET */
87 sockt_rd = get_tcp_socket(machine, nntplink.port_number, "nntp");
88 #endif
89
90 if (sockt_rd < 0)
91 return -1;
92
93 sockt_wr = dup(sockt_rd);
94
95 /* Now we'll make file pointers (i.e., buffered I/O) out of
96 ** the socket file descriptor. Note that we can't just
97 ** open a fp for reading and writing -- we have to open
98 ** up two separate fp's, one for reading, one for writing. */
99 if ((nntplink.rd_fp = fdopen(sockt_rd, "r")) == NULL) {
100 perror("server_init: fdopen #1");
101 return -1;
102 }
103 if ((nntplink.wr_fp = fdopen(sockt_wr, "w")) == NULL) {
104 perror("server_init: fdopen #2");
105 nntplink.rd_fp = NULL;
106 return -1;
107 }
108
109 /* Now get the server's signon message */
110 nntp_check();
111
112 if (*ser_line == NNTP_CLASS_OK) {
113 char save_line[NNTP_STRLEN];
114 strcpy(save_line, ser_line);
115 /* Try MODE READER just in case we're talking to innd.
116 ** If it is not an invalid command, use the new reply. */
117 if (nntp_command("MODE READER") <= 0)
118 sprintf(ser_line, "%d failed to send MODE READER\n", NNTP_ACCESS_VAL);
119 else if (nntp_check() <= 0 && atoi(ser_line) == NNTP_BAD_COMMAND_VAL)
120 strcpy(ser_line, save_line);
121 }
122 return atoi(ser_line);
123 }
124
125 void
cleanup_nntp()126 cleanup_nntp()
127 {
128 #ifdef WINSOCK
129 WSACleanup();
130 #endif
131 }
132
133 int
get_tcp_socket(machine,port,service)134 get_tcp_socket(machine, port, service)
135 char* machine;
136 int port;
137 char* service;
138 {
139 int s;
140 #if INET6
141 struct addrinfo hints;
142 struct addrinfo* res;
143 struct addrinfo* res0;
144 char portstr[8];
145 char* cause = NULL;
146 int error;
147
148 memset(&hints, 0, sizeof hints);
149 hints.ai_family = PF_UNSPEC;
150 hints.ai_socktype = SOCK_STREAM;
151 hints.ai_flags = 0;
152 if (port)
153 sprintf(service = portstr, "%d", port);
154 error = getaddrinfo(machine, service, &hints, &res0);
155 if (error) {
156 fprintf(stderr, "%s", gai_strerror(error));
157 return -1;
158 }
159 for (res = res0; res; res = res->ai_next) {
160 char buf[64] = "";
161 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162 if (s < 0) {
163 cause = "socket";
164 continue;
165 }
166
167 inet_ntop(res->ai_family, res->ai_addr, buf, sizeof buf);
168 if (res != res0)
169 fprintf(stderr, "trying %s...", buf);
170
171 if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
172 break; /* okay we got one */
173
174 fprintf(stderr, "connection to %s: ", buf);
175 perror("");
176 cause = "connect";
177 close(s);
178 s = -1;
179 }
180 if (s < 0) {
181 fprintf(stderr, "giving up... ");
182 perror(cause);
183 }
184 freeaddrinfo(res0);
185 #else /* !INET6 */
186 struct sockaddr_in sin;
187 #ifdef __hpux
188 int socksize = 0;
189 int socksizelen = sizeof socksize;
190 #endif
191 #ifdef NONETDB
192 bzero((char*)&sin, sizeof sin);
193 sin.sin_family = AF_INET;
194 #else
195 struct hostent* hp;
196 #ifdef h_addr
197 int x = 0;
198 register char** cp;
199 static char* alist[1];
200 #endif /* h_addr */
201 static struct hostent def;
202 static struct in_addr defaddr;
203 static char namebuf[256];
204
205 bzero((char*)&sin, sizeof sin);
206
207 if (port)
208 sin.sin_port = htons(port);
209 else {
210 struct servent* sp;
211 if ((sp = getservbyname(service, "tcp")) == NULL) {
212 fprintf(stderr, "%s/tcp: Unknown service.\n", service);
213 return -1;
214 }
215 sin.sin_port = sp->s_port;
216 }
217 /* If not a raw ip address, try nameserver */
218 if (!isdigit(*machine)
219 #ifdef INADDR_NONE
220 || (defaddr.s_addr = inet_addr(machine)) == INADDR_NONE)
221 #else
222 || (long)(defaddr.s_addr = inet_addr(machine)) == -1)
223 #endif
224 hp = gethostbyname(machine);
225 else {
226 /* Raw ip address, fake */
227 (void) strcpy(namebuf, machine);
228 def.h_name = namebuf;
229 #ifdef h_addr
230 def.h_addr_list = alist;
231 #endif
232 def.h_addr = (char*)&defaddr;
233 def.h_length = sizeof (struct in_addr);
234 def.h_addrtype = AF_INET;
235 def.h_aliases = 0;
236 hp = &def;
237 }
238 if (hp == NULL) {
239 fprintf(stderr, "%s: Unknown host.\n", machine);
240 return -1;
241 }
242
243 sin.sin_family = hp->h_addrtype;
244 #endif /* !NONETDB */
245
246 /* The following is kinda gross. The name server under 4.3
247 ** returns a list of addresses, each of which should be tried
248 ** in turn if the previous one fails. However, 4.2 hostent
249 ** structure doesn't have this list of addresses.
250 ** Under 4.3, h_addr is a #define to h_addr_list[0].
251 ** We use this to figure out whether to include the NS specific
252 ** code... */
253 #ifdef h_addr
254 /* get a socket and initiate connection -- use multiple addresses */
255 for (cp = hp->h_addr_list; cp && *cp; cp++) {
256 extern char* inet_ntoa _((const struct in_addr));
257 s = socket(hp->h_addrtype, SOCK_STREAM, 0);
258 if (s < 0) {
259 perror("socket");
260 return -1;
261 }
262 bcopy(*cp, (char*)&sin.sin_addr, hp->h_length);
263
264 if (x < 0)
265 fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
266 x = connect(s, (struct sockaddr*)&sin, sizeof (sin));
267 if (x == 0)
268 break;
269 fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
270 perror("");
271 (void) close(s);
272 }
273 if (x < 0) {
274 fprintf(stderr, "giving up...\n");
275 return -1;
276 }
277 #else /* no name server */
278 #ifdef EXCELAN
279 s = socket(SOCK_STREAM, (struct sockproto*)NULL, &sin, SO_KEEPALIVE);
280 if (s < 0) {
281 /* Get the socket */
282 perror("socket");
283 return -1;
284 }
285 bzero((char*)&sin, sizeof sin);
286 sin.sin_family = AF_INET;
287 sin.sin_port = htons(port? port : *service == 'n'? IPPORT_NNTP : 80);
288
289 /* set up addr for the connect */
290 if ((sin.sin_addr.s_addr = rhost(&machine)) == -1) {
291 fprintf(stderr, "%s: Unknown host.\n", machine);
292 return -1;
293 }
294
295 /* And then connect */
296 if (connect(s, (struct sockaddr*)&sin) < 0) {
297 perror("connect");
298 (void) close(s);
299 return -1;
300 }
301 #else /* !EXCELAN */
302 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
303 perror("socket");
304 return -1;
305 }
306
307 /* And then connect */
308
309 bcopy(hp->h_addr, (char*)&sin.sin_addr, hp->h_length);
310 if (connect(s, (struct sockaddr*)&sin, sizeof sin) < 0) {
311 perror("connect");
312 (void) close(s);
313 return -1;
314 }
315
316 #endif /* !EXCELAN */
317 #endif /* !h_addr */
318 #endif /* !INET6 */
319 #ifdef __hpux /* recommended by raj@cup.hp.com */
320 #define HPSOCKSIZE 0x8000
321 getsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, (caddr_t)&socksizelen);
322 if (socksize < HPSOCKSIZE) {
323 socksize = HPSOCKSIZE;
324 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, sizeof (socksize));
325 }
326 socksize = 0;
327 socksizelen = sizeof (socksize);
328 getsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, (caddr_t)&socksizelen);
329 if (socksize < HPSOCKSIZE) {
330 socksize = HPSOCKSIZE;
331 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, sizeof (socksize));
332 }
333 #endif
334 return s;
335 }
336
337 #ifdef DECNET
338 static int
get_dnet_socket(machine)339 get_dnet_socket(machine)
340 char* machine;
341 {
342 int s, area, node;
343 struct sockaddr_dn sdn;
344 struct nodeent *getnodebyname(), *np;
345
346 bzero((char*)&sdn, sizeof sdn);
347
348 switch (s = sscanf(machine, "%d%*[.]%d", &area, &node)) {
349 case 1:
350 node = area;
351 area = 0;
352 case 2:
353 node += area*1024;
354 sdn.sdn_add.a_len = 2;
355 sdn.sdn_family = AF_DECnet;
356 sdn.sdn_add.a_addr[0] = node % 256;
357 sdn.sdn_add.a_addr[1] = node / 256;
358 break;
359 default:
360 if ((np = getnodebyname(machine)) == NULL) {
361 fprintf(stderr, "%s: Unknown host.\n", machine);
362 return -1;
363 }
364 bcopy(np->n_addr, (char*)sdn.sdn_add.a_addr, np->n_length);
365 sdn.sdn_add.a_len = np->n_length;
366 sdn.sdn_family = np->n_addrtype;
367 break;
368 }
369 sdn.sdn_objnum = 0;
370 sdn.sdn_flags = 0;
371 sdn.sdn_objnamel = strlen("NNTP");
372 bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
373
374 if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
375 nerror("socket");
376 return -1;
377 }
378
379 /* And then connect */
380 if (connect(s, (struct sockaddr*)&sdn, sizeof sdn) < 0) {
381 nerror("connect");
382 close(s);
383 return -1;
384 }
385 return s;
386 }
387 #endif /* DECNET */
388
389 /*
390 * inet_addr for EXCELAN (which does not have it!)
391 */
392 #ifdef NONETDB
393 unsigned long
inet_addr(cp)394 inet_addr(cp)
395 register char* cp;
396 {
397 unsigned long val, base, n;
398 register char c;
399 unsigned long octet[4], *octetptr = octet;
400 #ifndef htonl
401 extern unsigned long htonl();
402 #endif /* htonl */
403 again:
404 /* Collect number up to ``.''.
405 * Values are specified as for C:
406 * 0x=hex, 0=octal, other=decimal. */
407 val = 0; base = 10;
408 if (*cp == '0')
409 base = 8, cp++;
410 if (*cp == 'x' || *cp == 'X')
411 base = 16, cp++;
412 while (c = *cp) {
413 if (isdigit(c)) {
414 val = (val * base) + (c - '0');
415 cp++;
416 continue;
417 }
418 if (base == 16 && isxdigit(c)) {
419 val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
420 cp++;
421 continue;
422 }
423 break;
424 }
425 if (*cp == '.') {
426 /* Internet format:
427 * a.b.c.d
428 * a.b.c (with c treated as 16-bits)
429 * a.b (with b treated as 24 bits) */
430 if (octetptr >= octet + 4)
431 return -1;
432 *octetptr++ = val, cp++;
433 goto again;
434 }
435 /* Check for trailing characters. */
436 if (*cp && !isspace(*cp))
437 return -1;
438 *octetptr++ = val;
439 /* Concoct the address according to the number of octet specified. */
440 n = octetptr - octet;
441 switch (n) {
442 case 1: /* a -- 32 bits */
443 val = octet[0];
444 break;
445 case 2: /* a.b -- 8.24 bits */
446 val = (octet[0] << 24) | (octet[1] & 0xffffff);
447 break;
448 case 3: /* a.b.c -- 8.8.16 bits */
449 val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
450 (octet[2] & 0xffff);
451 break;
452 case 4: /* a.b.c.d -- 8.8.8.8 bits */
453 val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
454 ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
455 break;
456 default:
457 return -1;
458 }
459 val = htonl(val);
460 return val;
461 }
462 #endif /* NONETDB */
463
464 #endif /* SUPPORT_NNTP */
465