2 * socket.c -- socket library functions
4 * For license terms, see the file COPYING in this directory.
12 #endif /* HAVE_MEMORY_H */
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
18 #if defined(STDC_HEADERS)
21 #if defined(HAVE_UNISTD_H)
24 #if defined(HAVE_STDARG_H)
32 #include <net/security.h>
33 #endif /* NET_SECURITY */
36 int SockOpen(const char *host, const char *service, const char *options)
39 struct addrinfo *ai, req;
41 struct net_security_operation request[NET_SECURITY_OPERATION_MAX];
43 #endif /* NET_SECURITY */
45 memset(&req, 0, sizeof(struct addrinfo));
46 req.ai_socktype = SOCK_STREAM;
48 if (i = getaddrinfo(host, service, &req, &ai)) {
49 fprintf(stderr, "fetchmail: getaddrinfo(%s.%s): %s(%d)\n", host, service, gai_strerror(i), i);
57 if (net_security_strtorequest((char *)options, request, &requestlen))
60 i = inner_connect(ai, request, requestlen, NULL,NULL, "fetchmail", NULL);
63 #else /* NET_SECURITY */
64 i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
65 #endif /* NET_SECURITY */
74 #ifdef INADDR_BROADCAST
75 #define INADDR_NONE INADDR_BROADCAST
77 #define INADDR_NONE -1
80 #endif /* INET_ATON */
82 int SockOpen(const char *host, int clientPort, const char *options)
87 #endif /* INET_ATON */
88 struct sockaddr_in ad;
91 memset(&ad, 0, sizeof(ad));
92 ad.sin_family = AF_INET;
94 /* we'll accept a quad address */
96 inaddr = inet_addr(host);
97 if (inaddr != INADDR_NONE)
98 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
101 if (!inet_aton(host, &ad.sin_addr))
102 #endif /* INET_ATON */
104 hp = gethostbyname(host);
107 * Add a check to make sure the address has a valid IPv4 or IPv6
108 * length. This prevents buffer spamming by a broken DNS.
110 if (hp == NULL || (hp->h_length != 4 && hp->h_length != 8))
114 * FIXME: make this work for multihomed hosts.
115 * We're toast if we get back multiple addresses and h_addrs[0]
116 * (aka h_addr) is not one we can actually connect to; this happens
117 * with multi-homed boxen.
119 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
121 ad.sin_port = htons(clientPort);
123 sock = socket(AF_INET, SOCK_STREAM, 0);
126 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
137 #if defined(HAVE_STDARG_H)
138 int SockPrintf(int sock, char* format, ...)
141 int SockPrintf(sock,format,va_alist)
150 #if defined(HAVE_STDARG_H)
151 va_start(ap, format) ;
155 #ifdef HAVE_VSNPRINTF
156 vsnprintf(buf, sizeof(buf), format, ap);
158 vsprintf(buf, format, ap);
161 return SockWrite(sock, buf, strlen(buf));
165 int SockWrite(int sock, char *buf, int len)
171 n = write(sock, buf, len);
181 int SockRead(int sock, char *buf, int len)
183 char *newline, *bp = buf;
190 * The reason for these gymnastics is that we want two things:
191 * (1) to read \n-terminated lines,
192 * (2) to return the true length of data read, even if the
193 * data coming in has embedded NULS.
195 if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
197 if ((newline = memchr(bp, '\n', n)) != NULL)
198 n = newline - bp + 1;
199 if ((n = read(sock, bp, n)) == -1)
209 int SockPeek(int sock)
210 /* peek at the next socket character without actually reading it */
215 if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
223 * Use the chargen service to test input beuffering directly.
224 * You may have to uncomment the `chargen' service description in your
225 * inetd.conf (and then SIGHUP inetd) for this to work.
229 int sock = SockOpen("localhost", 19, NULL);
232 while (SockRead(sock, buf, sizeof(buf)-1))
233 SockWrite(1, buf, strlen(buf));
237 /* socket.c ends here */