]> Pileus Git - ~andy/fetchmail/blob - socket.c
Simplify the autoconfig process a lot.
[~andy/fetchmail] / socket.c
1 /*
2  * For license terms, see the file COPYING in this directory.
3  */
4
5 /***********************************************************************
6   module:       socket.c
7   project:      fetchmail
8   programmer:   Carl Harris, ceharris@mal.com
9   description:  socket library functions
10
11  ***********************************************************************/
12
13 #include <config.h>
14
15 #include <fcntl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 #include <sys/time.h>
22 #include <sys/ioctl.h>
23 #if defined(STDC_HEADERS)
24 #include <string.h>
25 #endif
26 #if defined(HAVE_UNISTD_H)
27 #include <unistd.h>
28 #endif
29 #if defined(HAVE_STDARG_H)
30 #include <stdarg.h>
31 #else
32 #include <varargs.h>
33 #endif
34 #include <stdlib.h>
35 #include <errno.h>
36 #include "socket.h"
37
38 /* Size of buffer for internal buffering read function 
39    don't increase beyond the maximum atomic read/write size for
40    your sockets, or you'll take a potentially huge performance hit */
41
42 #define  INTERNAL_BUFSIZE       2048
43
44 int Socket(host, clientPort)
45 char *host;
46 int clientPort;
47 {
48     int sock;
49     unsigned long inaddr;
50     struct sockaddr_in ad;
51     struct hostent *hp;
52     
53     memset(&ad, 0, sizeof(ad));
54     ad.sin_family = AF_INET;
55
56     inaddr = inet_addr(host);
57     if (inaddr != INADDR_NONE)
58         memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
59     else
60     {
61         hp = gethostbyname(host);
62         if (hp == NULL)
63             return -1;
64         memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
65     }
66     ad.sin_port = htons(clientPort);
67     
68     sock = socket(AF_INET, SOCK_STREAM, 0);
69     if (sock < 0)
70         return sock;
71     if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
72         return -1;
73     return sock;
74 }
75
76 int SockGets(socket,buf,len)
77 int socket;
78 char *buf;
79 int len;
80 {
81     int rdlen = 0;
82     RETSIGTYPE (*sigsave)();
83
84     while (--len)
85     {
86         if (SockInternalRead(socket, buf, 1) != 1)
87             return -1;
88         else
89             rdlen++;
90         if (*buf == '\n')
91             break;
92         if (*buf != '\r') /* remove all CRs */
93             buf++;
94     }
95     *buf = 0;
96     return rdlen;
97 }
98
99 int SockPuts(socket,buf)
100 int socket;
101 char *buf;
102 {
103     int rc;
104     
105     if (rc = SockWrite(socket, buf, strlen(buf)))
106         return rc;
107     return SockWrite(socket, "\r\n", 2);
108 }
109
110 int SockWrite(socket,buf,len)
111 int socket;
112 char *buf;
113 int len;
114 {
115     int n;
116     
117     while (len)
118     {
119         n = write(socket, buf, len);
120         if (n <= 0)
121             return -1;
122         len -= n;
123         buf += n;
124     }
125     return 0;
126 }
127
128 int SockRead(socket,buf,len)
129 int socket;
130 char *buf;
131 int len;
132 {
133     int n;
134     
135     
136     while (len)
137     {
138         n = SockInternalRead(socket, buf, len);
139         if (n <= 0)
140             return -1;
141         len -= n;
142         buf += n;
143     }
144     return 0;
145 }
146
147 static int sbuflen = 0;
148
149 int SockInternalRead (socket,buf,len)
150 int socket;
151 char *buf;
152 int len;
153 {
154    static char sbuf [INTERNAL_BUFSIZE];
155    static char *bp;
156    
157    if (sbuflen == 0) {
158      /* buffer is empty; refresh. */
159      if ((sbuflen = read(socket,sbuf,INTERNAL_BUFSIZE)) < 0) {
160        if (errno = EINTR)
161            return -1;
162        perror("SockInternalRead: read");
163        exit(9);
164      }
165      else
166        bp = sbuf;
167    }
168    else
169      ;  /* already some data in the buffer */
170
171    /* can't get more than we have right now. */ 
172    /* XXX -- should probably try to load any unused part of sbuf
173              so that as much of 'len' as possible can be satisfied */
174    if (len > sbuflen)
175      len = sbuflen;
176    else
177      ;  /* wants no more than we already have */
178
179    /* transfer to caller's buffer */
180    if (len == 1) {
181      /* special case:  if caller only wants one character, it probably
182         costs a lot more to call bcopy than to do it ourselves. */
183      *buf = *(bp++);
184      sbuflen--;
185    }
186    else {
187      bcopy(bp,buf,len);
188      sbuflen -= len;
189      bp += len;
190    }
191    return(len);
192 }
193
194 /* SockClearHeader: call this procedure in order to kill off any
195    forthcoming Header info from the socket that we no longer want.
196    */
197 int SockClearHeader(socket)
198 int socket;
199 {
200    char *bufp;
201    static char sbuf[INTERNAL_BUFSIZE];
202    int nBytes;
203    int res;
204
205    if ((res = SockDataWaiting(socket))  <= 0)
206      return res;
207
208    while (1) 
209      {
210         if (SockGets(socket,sbuf,INTERNAL_BUFSIZE) < 0)
211           return 0;
212         bufp = sbuf;
213         if (*bufp == '.') {
214           bufp++;
215           if (*bufp == 0)
216             break;
217         }
218      }
219    sbuflen = 0;
220    return 0;
221 }
222
223
224 /* SockDataWaiting: Return a non-zero value if this socket is waiting
225   for data.   */
226 int  SockDataWaiting(int socket)
227 {
228   int flags;
229   char sbuf[INTERNAL_BUFSIZE];
230   int n;
231   int res;
232   flags = fcntl(socket,F_GETFL,0);
233   
234   /* set it to non-block */
235   if (fcntl(socket,F_SETFL,flags | O_NONBLOCK) == -1)
236     return -1;
237
238   if ((n = recv(socket,sbuf,INTERNAL_BUFSIZE,MSG_PEEK)) == -1)
239     { 
240       /* No data to read. */
241       if (errno == EWOULDBLOCK)
242         res = 0;
243     }
244   else
245     res = n;
246
247   /* reset it to block (or, whatever it was). */
248   fcntl(socket,F_SETFL,flags);
249   return res;
250 }
251 #if defined(HAVE_STDARG_H)
252 int SockPrintf(int socket, char* format, ...)
253 {
254 #else
255 int SockPrintf(socket,format,va_alist)
256 int socket;
257 char *format;
258 va_dcl {
259 #endif
260
261     va_list ap;
262     char buf[8192];
263
264 #if defined(HAVE_STDARG_H)
265     va_start(ap, format) ;
266 #else
267     va_start(ap);
268 #endif
269     vsprintf(buf, format, ap);
270     va_end(ap);
271     return SockWrite(socket, buf, strlen(buf));
272
273 }