]> Pileus Git - ~andy/fetchmail/blob - socket.c
Alll of Craig Metz's changes for IPv6 and IPSEC except the POP3 stuff.
[~andy/fetchmail] / socket.c
1 /*
2  * socket.c -- socket library functions
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include "config.h"
8 #include <stdio.h>
9 #include <string.h>
10 #ifdef HAVE_MEMORY_H
11 #include <memory.h>
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>
17 #include <netdb.h>
18 #if defined(STDC_HEADERS)
19 #include <stdlib.h>
20 #endif
21 #if defined(HAVE_UNISTD_H)
22 #include <unistd.h>
23 #endif
24 #if defined(HAVE_STDARG_H)
25 #include <stdarg.h>
26 #else
27 #include <varargs.h>
28 #endif
29 #include "socket.h"
30
31 #if NETSEC
32 #if MAIN
33 void *request = NULL;
34 int requestlen = 0;
35 #else /* MAIN */
36 extern void *request;
37 extern int requestlen;
38 #endif /* MAIN */
39 #endif /* NETSEC */
40
41 #if INET6
42 int SockOpen(const char *host, const char *service)
43 {
44   int i;
45   struct addrinfo *ai, req;
46
47   memset(&req, 0, sizeof(struct addrinfo));
48   req.ai_socktype = SOCK_STREAM;
49
50   if (i = getaddrinfo(host, service, &req, &ai)) {
51     fprintf(stderr, "fetchmail: getaddrinfo(%s.%s): %s(%d)\n", host, service, gai_strerror(i), i);
52     return -1;
53   };
54
55 #if NETSEC
56   i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
57 #else /* NETSEC */
58   i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
59 #endif /* NETSEC */
60   freeaddrinfo(ai);
61
62   return i;
63 };
64 #else /* INET6 */
65 #ifndef INET_ATON
66 #ifndef  INADDR_NONE
67 #ifdef   INADDR_BROADCAST
68 #define  INADDR_NONE    INADDR_BROADCAST
69 #else
70 #define  INADDR_NONE    -1
71 #endif
72 #endif
73 #endif /* INET_ATON */
74
75 int SockOpen(const char *host, int clientPort)
76 {
77     int sock;
78 #ifndef INET_ATON
79     unsigned long inaddr;
80 #endif /* INET_ATON */
81     struct sockaddr_in ad;
82     struct hostent *hp;
83
84     memset(&ad, 0, sizeof(ad));
85     ad.sin_family = AF_INET;
86
87     /* we'll accept a quad address */
88 #ifndef INET_ATON
89     inaddr = inet_addr(host);
90     if (inaddr != INADDR_NONE)
91         memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
92     else
93 #else
94     if (!inet_aton(host, &ad.sin_addr))
95 #endif /* INET_ATON */
96     {
97         hp = gethostbyname(host);
98
99         /*
100          * Add a check to make sure the address has a valid IPv4 or IPv6
101          * length.  This prevents buffer spamming by a broken DNS.
102          */
103         if (hp == NULL || (hp->h_length != 4 && hp->h_length != 8))
104             return -1;
105
106         memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
107     }
108     ad.sin_port = htons(clientPort);
109     
110     sock = socket(AF_INET, SOCK_STREAM, 0);
111     if (sock < 0)
112         return -1;
113     if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
114     {
115         close(sock);
116         return -1;
117     }
118
119     return(sock);
120 }
121 #endif /* INET6 */
122
123
124 #if defined(HAVE_STDARG_H)
125 int SockPrintf(int sock, char* format, ...)
126 {
127 #else
128 int SockPrintf(sock,format,va_alist)
129 int sock;
130 char *format;
131 va_dcl {
132 #endif
133
134     va_list ap;
135     char buf[8192];
136
137 #if defined(HAVE_STDARG_H)
138     va_start(ap, format) ;
139 #else
140     va_start(ap);
141 #endif
142 #ifdef HAVE_VSNPRINTF
143     vsnprintf(buf, sizeof(buf), format, ap);
144 #else
145     vsprintf(buf, format, ap);
146 #endif
147     va_end(ap);
148     return SockWrite(sock, buf, strlen(buf));
149
150 }
151
152 int SockWrite(int sock, char *buf, int len)
153 {
154     int n, wrlen = 0;
155
156     while (len)
157     {
158         n = write(sock, buf, len);
159         if (n <= 0)
160             return -1;
161         len -= n;
162         wrlen += n;
163         buf += n;
164     }
165     return wrlen;
166 }
167
168 int SockRead(int sock, char *buf, int len)
169 {
170     char *newline, *bp = buf;
171     int n;
172
173     if (--len < 1)
174         return(-1);
175     do {
176         /* 
177          * The reason for these gymnastics is that we want two things:
178          * (1) to read \n-terminated lines,
179          * (2) to return the true length of data read, even if the
180          *     data coming in has embedded NULS.
181          */
182         if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
183             return(-1);
184         if ((newline = memchr(bp, '\n', n)) != NULL)
185             n = newline - bp + 1;
186         if ((n = read(sock, bp, n)) == -1)
187             return(-1);
188         bp += n;
189         len -= n;
190     } while 
191             (!newline && len);
192     *bp = '\0';
193     return bp - buf;
194 }
195
196 int SockPeek(int sock)
197 /* peek at the next socket character without actually reading it */
198 {
199     int n;
200     char ch;
201
202     if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
203         return -1;
204     else
205         return(ch);
206 }
207
208 #ifdef MAIN
209 /*
210  * Use the chargen service to test input beuffering directly.
211  * You may have to uncomment the `chargen' service description in your
212  * inetd.conf (and then SIGHUP inetd) for this to work. 
213  */
214 main()
215 {
216     int         sock = SockOpen("localhost", 19);
217     char        buf[80];
218
219     while (SockRead(sock, buf, sizeof(buf)-1))
220         SockWrite(1, buf, strlen(buf));
221 }
222 #endif /* MAIN */
223
224 /* socket.c ends here */