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