/* nntpinit.c */ /* This software is copyrighted as detailed in the LICENSE file. */ /*#define DECNET *//* If you want decnet support */ /*#define EXCELAN *//* Excelan EXOS 205 support */ /*#define NONETD *//* Define if you're missing netdb.h */ #include "EXTERN.h" #include "common.h" #include "nntpclient.h" #include "INTERN.h" #include "nntpinit.h" #include "nntpinit.ih" #ifdef SUPPORT_NNTP #ifdef WINSOCK #include WSADATA wsaData; #else #include #include #ifdef NONETDB # define IPPORT_NNTP ((unsigned short) 119) #else # include #endif #endif #ifdef EXCELAN int connect _((int, struct sockaddr*)); unsigned short htons _((unsigned short)); unsigned long rhost _((char**)); int rresvport p((int)); int socket _((int, struct sockproto *, struct sockaddr_in *, int)); #endif /* EXCELAN */ #ifdef DECNET #include #include #endif /* DECNET */ #ifndef WINSOCK unsigned long inet_addr _((char*)); #ifndef NONETDB struct servent* getservbyname(); struct hostent* gethostbyname(); #endif #endif int init_nntp() { #ifdef WINSOCK if (WSAStartup(0x0101,&wsaData) == 0) { if (wsaData.wVersion == 0x0101) return 1; WSACleanup(); } fprintf(stderr,"Unable to initialize WinSock DLL.\n"); return -1; #else return 1; #endif } int server_init(machine) char* machine; { int sockt_rd, sockt_wr; #ifdef DECNET char* cp; #endif #ifdef DECNET cp = index(machine, ':'); if (cp && cp[1] == ':') { *cp = '\0'; sockt_rd = get_dnet_socket(machine); } else sockt_rd = get_tcp_socket(machine); #else /* !DECNET */ sockt_rd = get_tcp_socket(machine); #endif if (sockt_rd < 0) return -1; sockt_wr = dup(sockt_rd); /* Now we'll make file pointers (i.e., buffered I/O) out of ** the socket file descriptor. Note that we can't just ** open a fp for reading and writing -- we have to open ** up two separate fp's, one for reading, one for writing. */ if ((nntplink.rd_fp = fdopen(sockt_rd, "r")) == NULL) { perror("server_init: fdopen #1"); return -1; } if ((nntplink.wr_fp = fdopen(sockt_wr, "w")) == NULL) { perror("server_init: fdopen #2"); nntplink.rd_fp = NULL; return -1; } /* Now get the server's signon message */ nntp_check(); if (*ser_line == NNTP_CLASS_OK) { char save_line[NNTP_STRLEN]; strcpy(save_line, ser_line); /* Try MODE READER just in case we're talking to innd. ** If it is not an invalid command, use the new reply. */ if (nntp_command("MODE READER") <= 0) sprintf(ser_line, "%d failed to send MODE READER\n", NNTP_ACCESS_VAL); else if (nntp_check() <= 0 && atoi(ser_line) == NNTP_BAD_COMMAND_VAL) strcpy(ser_line, save_line); } return atoi(ser_line); } void cleanup_nntp() { #ifdef WINSOCK WSACleanup(); #endif } static int get_tcp_socket(machine) char* machine; { int s; struct sockaddr_in sin; #ifdef __hpux int socksize = 0; int socksizelen = sizeof socksize; #endif #ifdef NONETDB bzero((char*)&sin, sizeof sin); sin.sin_family = AF_INET; #else struct hostent* hp; #ifdef h_addr int x = 0; register char** cp; static char* alist[1]; #endif /* h_addr */ static struct hostent def; static struct in_addr defaddr; static char namebuf[256]; bzero((char*)&sin, sizeof sin); if (nntplink.port_number) sin.sin_port = htons(nntplink.port_number); else { struct servent* sp; if ((sp = getservbyname("nntp", "tcp")) == NULL) { fprintf(stderr, "nntp/tcp: Unknown service.\n"); return -1; } sin.sin_port = sp->s_port; } /* If not a raw ip address, try nameserver */ if (!isdigit(*machine) #ifdef INADDR_NONE || (defaddr.s_addr = inet_addr(machine)) == INADDR_NONE) #else || (long)(defaddr.s_addr = inet_addr(machine)) == -1) #endif hp = gethostbyname(machine); else { /* Raw ip address, fake */ (void) strcpy(namebuf, machine); def.h_name = namebuf; #ifdef h_addr def.h_addr_list = alist; #endif def.h_addr = (char*)&defaddr; def.h_length = sizeof(struct in_addr); def.h_addrtype = AF_INET; def.h_aliases = 0; hp = &def; } if (hp == NULL) { fprintf(stderr, "%s: Unknown host.\n", machine); return -1; } sin.sin_family = hp->h_addrtype; #endif /* !NONETDB */ /* The following is kinda gross. The name server under 4.3 ** returns a list of addresses, each of which should be tried ** in turn if the previous one fails. However, 4.2 hostent ** structure doesn't have this list of addresses. ** Under 4.3, h_addr is a #define to h_addr_list[0]. ** We use this to figure out whether to include the NS specific ** code... */ #ifdef h_addr /* get a socket and initiate connection -- use multiple addresses */ for (cp = hp->h_addr_list; cp && *cp; cp++) { extern char* inet_ntoa _((const struct in_addr)); s = socket(hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) { perror("socket"); return -1; } bcopy(*cp, (char*)&sin.sin_addr, hp->h_length); if (x < 0) fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr)); x = connect(s, (struct sockaddr*)&sin, sizeof (sin)); if (x == 0) break; fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr)); perror(""); (void) close(s); } if (x < 0) { fprintf(stderr, "giving up...\n"); return -1; } #else /* no name server */ #ifdef EXCELAN s = socket(SOCK_STREAM, (struct sockproto*)NULL, &sin, SO_KEEPALIVE); if (s < 0) { /* Get the socket */ perror("socket"); return -1; } bzero((char*)&sin, sizeof sin); sin.sin_family = AF_INET; sin.sin_port = htons(nntplink.port_number? nntplink.port_number : IPPORT_NNTP); /* set up addr for the connect */ if ((sin.sin_addr.s_addr = rhost(&machine)) == -1) { fprintf(stderr, "%s: Unknown host.\n", machine); return -1; } /* And then connect */ if (connect(s, (struct sockaddr*)&sin) < 0) { perror("connect"); (void) close(s); return -1; } #else /* !EXCELAN */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return -1; } /* And then connect */ bcopy(hp->h_addr, (char*)&sin.sin_addr, hp->h_length); if (connect(s, (struct sockaddr*)&sin, sizeof sin) < 0) { perror("connect"); (void) close(s); return -1; } #endif /* !EXCELAN */ #endif /* !h_addr */ #ifdef __hpux /* recommended by raj@cup.hp.com */ #define HPSOCKSIZE 0x8000 getsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, (caddr_t)&socksizelen); if (socksize < HPSOCKSIZE) { socksize = HPSOCKSIZE; setsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, sizeof(socksize)); } socksize = 0; socksizelen = sizeof(socksize); getsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, (caddr_t)&socksizelen); if (socksize < HPSOCKSIZE) { socksize = HPSOCKSIZE; setsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, sizeof(socksize)); } #endif return s; } #ifdef DECNET static int get_dnet_socket(machine) char* machine; { int s, area, node; struct sockaddr_dn sdn; struct nodeent *getnodebyname(), *np; bzero((char*)&sdn, sizeof sdn); switch (s = sscanf(machine, "%d%*[.]%d", &area, &node)) { case 1: node = area; area = 0; case 2: node += area*1024; sdn.sdn_add.a_len = 2; sdn.sdn_family = AF_DECnet; sdn.sdn_add.a_addr[0] = node % 256; sdn.sdn_add.a_addr[1] = node / 256; break; default: if ((np = getnodebyname(machine)) == NULL) { fprintf(stderr, "%s: Unknown host.\n", machine); return -1; } else { bcopy(np->n_addr, (char*)sdn.sdn_add.a_addr, np->n_length); sdn.sdn_add.a_len = np->n_length; sdn.sdn_family = np->n_addrtype; } break; } sdn.sdn_objnum = 0; sdn.sdn_flags = 0; sdn.sdn_objnamel = strlen("NNTP"); bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel); if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) { nerror("socket"); return -1; } /* And then connect */ if (connect(s, (struct sockaddr*)&sdn, sizeof sdn) < 0) { nerror("connect"); close(s); return -1; } return s; } #endif /* DECNET */ /* * inet_addr for EXCELAN (which does not have it!) */ #ifdef NONETDB unsigned long inet_addr(cp) register char* cp; { unsigned long val, base, n; register char c; unsigned long octet[4], *octetptr = octet; #ifndef htonl extern unsigned long htonl(); #endif /* htonl */ again: /* Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, other=decimal. */ val = 0; base = 10; if (*cp == '0') base = 8, cp++; if (*cp == 'x' || *cp == 'X') base = 16, cp++; while (c = *cp) { if (isdigit(c)) { val = (val * base) + (c - '0'); cp++; continue; } if (base == 16 && isxdigit(c)) { val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); cp++; continue; } break; } if (*cp == '.') { /* Internet format: * a.b.c.d * a.b.c (with c treated as 16-bits) * a.b (with b treated as 24 bits) */ if (octetptr >= octet + 4) return -1; *octetptr++ = val, cp++; goto again; } /* Check for trailing characters. */ if (*cp && !isspace(*cp)) return -1; *octetptr++ = val; /* Concoct the address according to the number of octet specified. */ n = octetptr - octet; switch (n) { case 1: /* a -- 32 bits */ val = octet[0]; break; case 2: /* a.b -- 8.24 bits */ val = (octet[0] << 24) | (octet[1] & 0xffffff); break; case 3: /* a.b.c -- 8.8.16 bits */ val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) | (octet[2] & 0xffff); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) | ((octet[2] & 0xff) << 8) | (octet[3] & 0xff); break; default: return -1; } val = htonl(val); return val; } #endif /* NONETDB */ #endif /* SUPPORT_NNTP */