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