2 * socket.c -- socket library functions
4 * For license terms, see the file COPYING in this directory.
13 #endif /* HAVE_MEMORY_H */
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
19 #if defined(STDC_HEADERS)
22 #if defined(HAVE_UNISTD_H)
25 #if defined(HAVE_STDARG_H)
31 #include "fetchmail.h"
33 #ifdef HAVE_RES_SEARCH
34 /* some versions of FreeBSD should declare this but don't */
37 /* pretend we have h_errno to avoid some #ifdef's later */
42 #include <net/security.h>
43 #endif /* NET_SECURITY */
45 static int handle_plugin(const char *host,
46 const char *service, const char *plugin)
47 /* get a socket mediated through a given external command */
52 if (socketpair(AF_UNIX,SOCK_STREAM,0,fds))
54 error(0, 0, "fetchmail: socketpair failed: %s(%d)",strerror(errno),errno);
61 if (outlevel >= O_VERBOSE)
62 error(0, 0, "running %s %s %s", plugin, host, service);
63 execlp(plugin,plugin,host,service,0);
64 error(0, 0, "execl(%s) failed: %s (%d)",
65 plugin, strerror(errno), errno);
73 int SockOpen(const char *host, const char *service, const char *options,
77 struct addrinfo *ai, req;
81 #endif /* NET_SECURITY */
84 return handle_plugin(host,service,plugin);
85 memset(&req, 0, sizeof(struct addrinfo));
86 req.ai_socktype = SOCK_STREAM;
88 if (i = getaddrinfo(host, service, &req, &ai)) {
89 error(0, 0, "fetchmail: getaddrinfo(%s.%s): %s(%d)", host, service, gai_strerror(i), i);
97 if (net_security_strtorequest((char *)options, &request, &requestlen))
100 i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
105 #else /* NET_SECURITY */
106 i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
107 #endif /* NET_SECURITY */
114 #ifndef HAVE_INET_ATON
116 #ifdef INADDR_BROADCAST
117 #define INADDR_NONE INADDR_BROADCAST
119 #define INADDR_NONE -1
122 #endif /* HAVE_INET_ATON */
124 int SockOpen(const char *host, int clientPort, const char *options,
128 #ifndef HAVE_INET_ATON
129 unsigned long inaddr;
130 #endif /* HAVE_INET_ATON */
131 struct sockaddr_in ad;
136 sprintf(buf,"%d",clientPort);
137 return handle_plugin(host,buf,plugin);
140 memset(&ad, 0, sizeof(ad));
141 ad.sin_family = AF_INET;
143 /* we'll accept a quad address */
144 #ifndef HAVE_INET_ATON
145 inaddr = inet_addr(host);
146 if (inaddr != INADDR_NONE)
147 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
150 if (!inet_aton(host, &ad.sin_addr))
151 #endif /* HAVE_INET_ATON */
153 hp = gethostbyname(host);
161 * Add a check to make sure the address has a valid IPv4 or IPv6
162 * length. This prevents buffer spamming by a broken DNS.
164 if(hp->h_length != 4 && hp->h_length != 8)
167 error(0, 0, "fetchmail: illegal address length received for host %s");
171 * FIXME: make this work for multihomed hosts.
172 * We're toast if we get back multiple addresses and h_addrs[0]
173 * (aka h_addr) is not one we can actually connect to; this happens
174 * with multi-homed boxen.
176 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
178 ad.sin_port = htons(clientPort);
180 sock = socket(AF_INET, SOCK_STREAM, 0);
186 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
200 #if defined(HAVE_STDARG_H)
201 int SockPrintf(int sock, const char* format, ...)
204 int SockPrintf(sock,format,va_alist)
213 #if defined(HAVE_STDARG_H)
214 va_start(ap, format) ;
218 #ifdef HAVE_VSNPRINTF
219 vsnprintf(buf, sizeof(buf), format, ap);
221 vsprintf(buf, format, ap);
224 return SockWrite(sock, buf, strlen(buf));
228 int SockWrite(int sock, char *buf, int len)
234 n = write(sock, buf, len);
244 int SockRead(int sock, char *buf, int len)
246 char *newline, *bp = buf;
253 * The reason for these gymnastics is that we want two things:
254 * (1) to read \n-terminated lines,
255 * (2) to return the true length of data read, even if the
256 * data coming in has embedded NULS.
258 if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
260 if ((newline = memchr(bp, '\n', n)) != NULL)
261 n = newline - bp + 1;
262 if ((n = read(sock, bp, n)) == -1)
272 int SockPeek(int sock)
273 /* peek at the next socket character without actually reading it */
278 if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
284 int SockClose(int sock)
285 /* close a socket (someday we may do other cleanup here) */
292 * Use the chargen service to test input buffering directly.
293 * You may have to uncomment the `chargen' service description in your
294 * inetd.conf (and then SIGHUP inetd) for this to work.
298 int sock = SockOpen("localhost", 19, NULL);
301 while (SockRead(sock, buf, sizeof(buf)-1))
302 SockWrite(1, buf, strlen(buf));
307 /* socket.c ends here */