]> Pileus Git - ~andy/fetchmail/blob - socket.c
d4dde00913701a991354784c72b28a881d564668
[~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  * The file pointer arguments are currently misleading -- there
8  * is only one shared internal buffer for all sockets.
9  *
10  * For license terms, see the file COPYING in this directory.
11  */
12
13 #include <config.h>
14
15 #include <stdio.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <sys/time.h>
23 #include <sys/ioctl.h>
24 #if defined(STDC_HEADERS)
25 #include <string.h>
26 #include <stdlib.h>
27 #endif
28 #if defined(HAVE_UNISTD_H)
29 #include <unistd.h>
30 #endif
31 #if defined(HAVE_STDARG_H)
32 #include <stdarg.h>
33 #else
34 #include <varargs.h>
35 #endif
36 #include <errno.h>
37 #include "socket.h"
38
39 /* Size of buffer for internal buffering read function 
40    don't increase beyond the maximum atomic read/write size for
41    your sockets, or you'll take a potentially huge performance hit */
42
43 #define  INTERNAL_BUFSIZE       2048
44
45 FILE *Socket(host, clientPort)
46 char *host;
47 int clientPort;
48 {
49     int sock;
50     unsigned long inaddr;
51     struct sockaddr_in ad;
52     struct hostent *hp;
53     
54     memset(&ad, 0, sizeof(ad));
55     ad.sin_family = AF_INET;
56
57     inaddr = inet_addr(host);
58     if (inaddr != INADDR_NONE)
59         memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
60     else
61     {
62         hp = gethostbyname(host);
63         if (hp == NULL)
64             return (FILE *)NULL;
65         memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
66     }
67     ad.sin_port = htons(clientPort);
68     
69     sock = socket(AF_INET, SOCK_STREAM, 0);
70     if (sock < 0)
71         return (FILE *)NULL;
72     if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
73         return (FILE *)NULL;
74     return fdopen(sock, "r+");
75 }
76
77 int SockWrite(buf,len,sockfp)
78 char *buf;
79 int len;
80 FILE *sockfp;
81 {
82     int n, wrlen = 0;
83     
84     while (len)
85     {
86         n = write(fileno(sockfp), buf, len);
87         if (n <= 0)
88             return -1;
89         len -= n;
90         wrlen += n;
91         buf += n;
92     }
93     return wrlen;
94 }
95
96 static int sbuflen = 0;
97
98 static int SockInternalRead (socket,buf,len)
99 int socket;
100 char *buf;
101 int len;
102 {
103    static char sbuf [INTERNAL_BUFSIZE];
104    static char *bp;
105    
106    if (sbuflen <= 0) {
107      /* buffer is empty; refresh. */
108      if ((sbuflen = read(socket,sbuf,INTERNAL_BUFSIZE)) < 0) {
109        if (errno == EINTR)
110            return -1;
111        perror("SockInternalRead: read");
112        exit(9);
113      }
114      else
115        bp = sbuf;
116    }
117    else
118      ;  /* already some data in the buffer */
119
120    /* can't get more than we have right now. */ 
121    /* XXX -- should probably try to load any unused part of sbuf
122              so that as much of 'len' as possible can be satisfied */
123    if (len > sbuflen)
124      len = sbuflen;
125    else
126      ;  /* wants no more than we already have */
127
128    /* transfer to caller's buffer */
129    if (len == 1) {
130      /* special case:  if caller only wants one character, it probably
131         costs a lot more to call bcopy than to do it ourselves. */
132      *buf = *(bp++);
133      sbuflen--;
134    }
135    else {
136      bcopy(bp,buf,len);
137      sbuflen -= len;
138      bp += len;
139    }
140    return(len);
141 }
142
143 int SockGets(buf, len, sockfp)
144 char *buf;
145 int len;
146 FILE *sockfp;
147 {
148     int rdlen = 0;
149
150     while (--len)
151     {
152         if (SockInternalRead(fileno(sockfp), buf, 1) != 1)
153             return -1;
154         else
155             rdlen++;
156         if (*buf == '\n')
157             break;
158         if (*buf != '\r') /* remove all CRs */
159             buf++;
160     }
161     *buf = 0;
162     return rdlen;
163 }
164
165 #if defined(HAVE_STDARG_H)
166 int SockPrintf(FILE *sockfp, char* format, ...)
167 {
168 #else
169 int SockPrintf(sockfp,format,va_alist)
170 FILE *sockfp;
171 char *format;
172 va_dcl {
173 #endif
174
175     va_list ap;
176     char buf[8192];
177
178 #if defined(HAVE_STDARG_H)
179     va_start(ap, format) ;
180 #else
181     va_start(ap);
182 #endif
183     vsprintf(buf, format, ap);
184     va_end(ap);
185     return SockWrite(buf, strlen(buf), sockfp);
186
187 }
188
189 /* socket.c ends here */