2 * socket.c -- socket library functions
4 * Copyright 1998 by Eric S. Raymond.
5 * For license terms, see the file COPYING in this directory.
14 #endif /* HAVE_MEMORY_H */
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
20 #if defined(STDC_HEADERS)
23 #if defined(HAVE_UNISTD_H)
26 #if defined(HAVE_STDARG_H)
32 #include "fetchmail.h"
35 #ifdef HAVE_RES_SEARCH
36 /* some versions of FreeBSD should declare this but don't */
39 /* pretend we have h_errno to avoid some #ifdef's later */
44 #include <net/security.h>
45 #endif /* NET_SECURITY */
47 #ifdef HAVE_SOCKETPAIR
48 static int handle_plugin(const char *host,
49 const char *service, const char *plugin)
50 /* get a socket mediated through a given external command */
55 if (socketpair(AF_UNIX,SOCK_STREAM,0,fds))
57 error(0, 0, _("fetchmail: socketpair failed: %s(%d)"),strerror(errno),errno);
64 if (outlevel >= O_VERBOSE)
65 error(0, 0, _("running %s %s %s"), plugin, host, service);
66 execlp(plugin,plugin,host,service,0);
67 error(0, 0, _("execl(%s) failed: %s (%d)"),
68 plugin, strerror(errno), errno);
74 #endif /* HAVE_SOCKETPAIR */
77 int SockOpen(const char *host, const char *service, const char *options,
81 struct addrinfo *ai, req;
85 #endif /* NET_SECURITY */
87 #ifdef HAVE_SOCKETPAIR
89 return handle_plugin(host,service,plugin);
90 #endif /* HAVE_SOCKETPAIR */
91 memset(&req, 0, sizeof(struct addrinfo));
92 req.ai_socktype = SOCK_STREAM;
94 if (i = getaddrinfo(host, service, &req, &ai)) {
95 error(0, 0, _("fetchmail: getaddrinfo(%s.%s): %s(%d)"), host, service, gai_strerror(i), i);
103 if (net_security_strtorequest((char *)options, &request, &requestlen))
106 i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
111 #else /* NET_SECURITY */
112 i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
113 #endif /* NET_SECURITY */
120 #ifndef HAVE_INET_ATON
122 #ifdef INADDR_BROADCAST
123 #define INADDR_NONE INADDR_BROADCAST
125 #define INADDR_NONE -1
128 #endif /* HAVE_INET_ATON */
130 int SockOpen(const char *host, int clientPort, const char *options,
134 #ifndef HAVE_INET_ATON
135 unsigned long inaddr;
136 #endif /* HAVE_INET_ATON */
137 struct sockaddr_in ad;
140 #ifdef HAVE_SOCKETPAIR
143 sprintf(buf,"%d",clientPort);
144 return handle_plugin(host,buf,plugin);
146 #endif /* HAVE_SOCKETPAIR */
148 memset(&ad, 0, sizeof(ad));
149 ad.sin_family = AF_INET;
151 /* we'll accept a quad address */
152 #ifndef HAVE_INET_ATON
153 inaddr = inet_addr(host);
154 if (inaddr != INADDR_NONE)
155 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
158 if (!inet_aton(host, &ad.sin_addr))
159 #endif /* HAVE_INET_ATON */
161 hp = gethostbyname(host);
169 * Add a check to make sure the address has a valid IPv4 or IPv6
170 * length. This prevents buffer spamming by a broken DNS.
172 if(hp->h_length != 4 && hp->h_length != 8)
175 error(0, 0, _("fetchmail: illegal address length received for host %s"));
179 * FIXME: make this work for multihomed hosts.
180 * We're toast if we get back multiple addresses and h_addrs[0]
181 * (aka h_addr) is not one we can actually connect to; this happens
182 * with multi-homed boxen.
184 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
186 ad.sin_port = htons(clientPort);
188 sock = socket(AF_INET, SOCK_STREAM, 0);
194 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
208 #if defined(HAVE_STDARG_H)
209 int SockPrintf(int sock, const char* format, ...)
212 int SockPrintf(sock,format,va_alist)
221 #if defined(HAVE_STDARG_H)
222 va_start(ap, format) ;
226 #ifdef HAVE_VSNPRINTF
227 vsnprintf(buf, sizeof(buf), format, ap);
229 vsprintf(buf, format, ap);
232 return SockWrite(sock, buf, strlen(buf));
236 int SockWrite(int sock, char *buf, int len)
242 n = write(sock, buf, len);
252 int SockRead(int sock, char *buf, int len)
254 char *newline, *bp = buf;
261 * The reason for these gymnastics is that we want two things:
262 * (1) to read \n-terminated lines,
263 * (2) to return the true length of data read, even if the
264 * data coming in has embedded NULS.
266 if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
268 if ((newline = memchr(bp, '\n', n)) != NULL)
269 n = newline - bp + 1;
270 if ((n = read(sock, bp, n)) == -1)
280 int SockPeek(int sock)
281 /* peek at the next socket character without actually reading it */
286 if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
292 int SockClose(int sock)
293 /* close a socket (someday we may do other cleanup here) */
300 * Use the chargen service to test input buffering directly.
301 * You may have to uncomment the `chargen' service description in your
302 * inetd.conf (and then SIGHUP inetd) for this to work.
306 int sock = SockOpen("localhost", 19, NULL);
309 while (SockRead(sock, buf, sizeof(buf)-1))
310 SockWrite(1, buf, strlen(buf));
315 /* socket.c ends here */