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