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