3 ** Open a connection to a remote NNTP server.
8 #include "portable/socket.h"
12 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
16 #include "inn/innconf.h"
22 ** Open a connection to an NNTP server and create stdio FILE's for talking
23 ** to it. Return -1 on error.
25 int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char *errbuff)
27 char mybuff[NNTP_STRLEN + 2];
34 struct addrinfo hints, *ressave, *addr;
36 struct sockaddr_storage client;
43 struct hostent fakehp;
44 struct in_addr quadaddr;
45 struct sockaddr_in server, client;
48 buff = errbuff ? errbuff : mybuff;
52 memset(&hints, 0, sizeof(struct addrinfo));
53 hints.ai_family = PF_UNSPEC;
54 hints.ai_socktype = SOCK_STREAM;
55 sprintf(portbuf, "%d", port);
56 if (getaddrinfo(host, portbuf, &hints, &addr) != 0)
59 for (ressave = addr; addr; addr = addr->ai_next) {
60 if ((i = socket(addr->ai_family, addr->ai_socktype,
61 addr->ai_protocol)) < 0)
62 continue; /* ignore */
63 /* bind the local (source) address, if requested */
64 memset(&client, 0, sizeof client);
65 if (addr->ai_family == AF_INET && innconf->sourceaddress) {
66 if (inet_pton(AF_INET, innconf->sourceaddress,
67 &((struct sockaddr_in *)&client)->sin_addr) < 1) {
71 ((struct sockaddr_in *)&client)->sin_family = AF_INET;
72 #ifdef HAVE_SOCKADDR_LEN
73 ((struct sockaddr_in *)&client)->sin_len = sizeof( struct sockaddr_in );
76 if (addr->ai_family == AF_INET6 && innconf->sourceaddress6) {
77 if (inet_pton(AF_INET6, innconf->sourceaddress6,
78 &((struct sockaddr_in6 *)&client)->sin6_addr) < 1) {
82 ((struct sockaddr_in6 *)&client)->sin6_family = AF_INET6;
83 #ifdef HAVE_SOCKADDR_LEN
84 ((struct sockaddr_in6 *)&client)->sin6_len = sizeof( struct sockaddr_in6 );
87 if (client.ss_family != 0) {
88 if (bind(i, (struct sockaddr *)&client, addr->ai_addrlen) < 0) {
93 /* we are ready, try to connect */
94 if (connect(i, addr->ai_addr, addr->ai_addrlen) == 0)
100 freeaddrinfo(ressave);
103 /* all connect(2) calls failed or some other error has occurred */
110 #else /* HAVE_INET6 */
111 if (inet_aton(host, &quadaddr)) {
112 /* Host was specified as a dotted-quad internet address. Fill in
113 * the parts of the hostent struct that we need. */
114 fakehp.h_length = sizeof quadaddr;
115 fakehp.h_addrtype = AF_INET;
117 fakelist[0] = (char *)&quadaddr;
121 else if ((hp = gethostbyname(host)) != NULL)
122 ap = hp->h_addr_list;
124 /* Not a host name. */
127 /* Set up the socket address. */
128 memset(&server, 0, sizeof server);
129 server.sin_family = hp->h_addrtype;
130 #ifdef HAVE_SOCKADDR_LEN
131 server.sin_len = sizeof( struct sockaddr_in );
133 server.sin_port = htons(port);
135 /* Source IP address to which we bind. */
136 memset(&client, 0, sizeof client);
137 client.sin_family = AF_INET;
138 #ifdef HAVE_SOCKADDR_LEN
139 client.sin_len = sizeof( struct sockaddr_in );
141 if (innconf->sourceaddress) {
142 if (!inet_aton(innconf->sourceaddress, &client.sin_addr))
145 client.sin_addr.s_addr = htonl(INADDR_ANY);
147 /* Loop through the address list, trying to connect. */
148 for (; ap && *ap; ap++) {
149 /* Make a socket and try to connect. */
150 if ((i = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
152 /* Bind to the source address we want. */
153 if (bind(i, (struct sockaddr *)&client, sizeof client) < 0) {
159 /* Copy the address via inline memcpy:
160 * memcpy(&server.sin_addr, *ap, hp->h_length); */
162 for (dest = (char *)&server.sin_addr, j = hp->h_length; --j >= 0; )
164 if (connect(i, (struct sockaddr *)&server, sizeof server) < 0) {
170 #endif /* HAVE_INET6 */
172 /* Connected -- now make sure we can post. */
173 if ((F = fdopen(i, "r")) == NULL) {
179 if (fgets(buff, sizeof mybuff, F) == NULL) {
186 if (j != NNTP_POSTOK_VAL && j != NNTP_NOPOSTOK_VAL) {
188 /* This seems like a reasonable error code to use... */
194 if ((*ToServerp = fdopen(dup(i), "w")) == NULL) {
206 int NNTPremoteopen(int port, FILE **FromServerp, FILE **ToServerp, char *errbuff)
210 if ((p = innconf->server) == NULL) {
212 strcpy(errbuff, "What server?");
215 return NNTPconnect(p, port, FromServerp, ToServerp, errbuff);