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 */
53 if (socketpair(AF_UNIX,SOCK_STREAM,0,fds))
55 error(0, 0, _("fetchmail: socketpair failed: %s(%d)"),strerror(errno),errno);
61 error(0, 0, _("fetchmail: fork failed: %s(%d)"),
62 strerror(errno), errno);
66 /* fds[1] is the parent's end; close it for proper EOF
69 if ( (dup2(fds[0],0) == -1) || (dup2(fds[0],1) == -1) ) {
70 error(0, 0, _("fetchmail: dup2 failed: %s(%d)"),
71 strerror(errno), errno);
74 /* fds[0] is now connected to 0 and 1; close it */
76 if (outlevel >= O_VERBOSE)
77 error(0, 0, _("running %s %s %s"), plugin, host, service);
78 execlp(plugin,plugin,host,service,0);
79 error(0, 0, _("execl(%s) failed: %s (%d)"),
80 plugin, strerror(errno), errno);
87 /* fds[0] is the child's end; close it for proper EOF detection */
91 #endif /* HAVE_SOCKETPAIR */
94 int SockOpen(const char *host, const char *service, const char *options,
98 struct addrinfo *ai, req;
100 void *request = NULL;
102 #endif /* NET_SECURITY */
104 #ifdef HAVE_SOCKETPAIR
106 return handle_plugin(host,service,plugin);
107 #endif /* HAVE_SOCKETPAIR */
108 memset(&req, 0, sizeof(struct addrinfo));
109 req.ai_socktype = SOCK_STREAM;
111 if (i = getaddrinfo(host, service, &req, &ai)) {
112 error(0, 0, _("fetchmail: getaddrinfo(%s.%s): %s(%d)"), host, service, gai_strerror(i), i);
120 if (net_security_strtorequest((char *)options, &request, &requestlen))
123 i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
128 #else /* NET_SECURITY */
129 i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
130 #endif /* NET_SECURITY */
137 #ifndef HAVE_INET_ATON
139 #ifdef INADDR_BROADCAST
140 #define INADDR_NONE INADDR_BROADCAST
142 #define INADDR_NONE -1
145 #endif /* HAVE_INET_ATON */
147 int SockOpen(const char *host, int clientPort, const char *options,
151 #ifndef HAVE_INET_ATON
152 unsigned long inaddr;
153 #endif /* HAVE_INET_ATON */
154 struct sockaddr_in ad;
157 #ifdef HAVE_SOCKETPAIR
160 sprintf(buf,"%d",clientPort);
161 return handle_plugin(host,buf,plugin);
163 #endif /* HAVE_SOCKETPAIR */
165 memset(&ad, 0, sizeof(ad));
166 ad.sin_family = AF_INET;
168 /* we'll accept a quad address */
169 #ifndef HAVE_INET_ATON
170 inaddr = inet_addr(host);
171 if (inaddr != INADDR_NONE)
172 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
175 if (!inet_aton(host, &ad.sin_addr))
176 #endif /* HAVE_INET_ATON */
178 hp = gethostbyname(host);
186 * Add a check to make sure the address has a valid IPv4 or IPv6
187 * length. This prevents buffer spamming by a broken DNS.
189 if(hp->h_length != 4 && hp->h_length != 8)
192 error(0, 0, _("fetchmail: illegal address length received for host %s"),host);
196 * FIXME: make this work for multihomed hosts.
197 * We're toast if we get back multiple addresses and h_addrs[0]
198 * (aka h_addr) is not one we can actually connect to; this happens
199 * with multi-homed boxen.
201 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
203 ad.sin_port = htons(clientPort);
205 sock = socket(AF_INET, SOCK_STREAM, 0);
211 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
225 #if defined(HAVE_STDARG_H)
226 int SockPrintf(int sock, const char* format, ...)
229 int SockPrintf(sock,format,va_alist)
238 #if defined(HAVE_STDARG_H)
239 va_start(ap, format) ;
243 #ifdef HAVE_VSNPRINTF
244 vsnprintf(buf, sizeof(buf), format, ap);
246 vsprintf(buf, format, ap);
249 return SockWrite(sock, buf, strlen(buf));
253 int SockWrite(int sock, char *buf, int len)
259 n = write(sock, buf, len);
269 int SockRead(int sock, char *buf, int len)
271 char *newline, *bp = buf;
278 * The reason for these gymnastics is that we want two things:
279 * (1) to read \n-terminated lines,
280 * (2) to return the true length of data read, even if the
281 * data coming in has embedded NULS.
283 if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
285 if ((newline = memchr(bp, '\n', n)) != NULL)
286 n = newline - bp + 1;
287 if ((n = read(sock, bp, n)) == -1)
297 int SockPeek(int sock)
298 /* peek at the next socket character without actually reading it */
303 if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
309 int SockClose(int sock)
310 /* close a socket (someday we may do other cleanup here) */
317 * Use the chargen service to test input buffering directly.
318 * You may have to uncomment the `chargen' service description in your
319 * inetd.conf (and then SIGHUP inetd) for this to work.
323 int sock = SockOpen("localhost", 19, NULL);
326 while (SockRead(sock, buf, sizeof(buf)-1))
327 SockWrite(1, buf, strlen(buf));
332 /* socket.c ends here */