2 * These are socket routines for the main module of CNTLM
4 * CNTLM is free software; you can redistribute it and/or modify it under the
5 * terms of the GNU General Public License as published by the Free Software
6 * Foundation; either version 2 of the License, or (at your option) any later
9 * CNTLM is distributed in the hope that it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
16 * St, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Copyright (c) 2007 David Kubicek
22 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
41 * gethostbyname() wrapper. Return 1 if OK, otherwise 0.
43 int so_resolv(struct in_addr
*host
, const char *name
) {
45 struct hostent *resolv;
47 resolv = gethostbyname(name);
51 memcpy(host, resolv->h_addr_list[0], resolv->h_length);
54 struct addrinfo hints
, *res
, *p
;
56 memset(&hints
, 0, sizeof(hints
));
57 hints
.ai_family
= AF_INET
;
58 hints
.ai_socktype
= SOCK_STREAM
;
59 int rc
= getaddrinfo(name
, NULL
, &hints
, &res
);
62 printf("so_resolv: %s failed: %s (%d)\n", name
, gai_strerror(rc
), rc
);
67 printf("Resolve %s:\n", name
);
69 for (p
= res
; p
!= NULL
; p
= p
->ai_next
) {
70 struct sockaddr_in
*ad
= (struct sockaddr_in
*)(p
->ai_addr
);
76 memcpy(host
, &ad
->sin_addr
, sizeof(ad
->sin_addr
));
79 printf(" -> %s\n", inet_ntoa(ad
->sin_addr
));
82 printf(" %s\n", inet_ntoa(ad
->sin_addr
));
91 * Connect to a host. Host is required to be resolved
92 * in the struct in_addr already.
93 * Returns: socket descriptor
95 int so_connect(struct in_addr host
, int port
) {
97 struct sockaddr_in saddr
;
101 if ((fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
103 printf("so_connect: create: %s\n", strerror(errno
));
107 memset(&saddr
, 0, sizeof(saddr
));
108 saddr
.sin_family
= AF_INET
;
109 saddr
.sin_port
= htons(port
);
110 saddr
.sin_addr
= host
;
112 if ((flags
= fcntl(fd
, F_GETFL
, 0)) < 0) {
114 printf("so_connect: get flags: %s\n", strerror(errno
));
119 /* NON-BLOCKING connect with timeout
120 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
122 printf("so_connect: set non-blocking: %s\n", strerror(errno));
128 rc
= connect(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
));
131 printf("connect = %d\n", rc);
132 if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS)) {
138 rc = select(fd+1, NULL, &fds, NULL, &tv) - 1;
139 printf("select = %d\n", rc);
145 printf("so_connect: %s\n", strerror(errno
));
150 if (fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
) < 0) {
152 printf("so_connect: set blocking: %s\n", strerror(errno
));
161 * Bind the specified port and listen on it.
162 * Return socket descriptor if OK, otherwise 0.
164 int so_listen(int port
, struct in_addr source
) {
165 struct sockaddr_in saddr
;
169 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
172 printf("so_listen: new socket: %s\n", strerror(errno
));
178 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &clen
, sizeof(clen
));
179 memset((void *)&saddr
, 0, sizeof(saddr
));
180 saddr
.sin_family
= AF_INET
;
181 saddr
.sin_port
= htons(port
);
182 saddr
.sin_addr
.s_addr
= source
.s_addr
;
184 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
))) {
185 syslog(LOG_ERR
, "Cannot bind port %d: %s!\n", port
, strerror(errno
));
199 * Return 1 if data is available on the socket,
200 * 0 if connection was closed
201 * -1 if error (errno is set)
203 int so_recvtest(int fd
) {
209 flags
= fcntl(fd
, F_GETFL
);
210 fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
211 i
= recv(fd
, &buf
, 1, MSG_PEEK
);
212 fcntl(fd
, F_SETFL
, flags
);
214 i
= recv(fd
, &buf
, 1, MSG_DONTWAIT
| MSG_PEEK
);
221 * Return true if there are some data on the socket
223 int so_dataready(int fd
) {
224 return so_recvtest(fd
) > 0;
228 * Reliable way of finding out whether a connection was closed
229 * on the remote end, without actually reading from it.
231 int so_closed(int fd
) {
238 return (i
== 0 || (i
== -1 && errno
!= EAGAIN
&& errno
!= ENOENT
)); /* ENOENT, you ask? Perhap AIX devels could explain! :-( */
242 * Receive a single line from the socket. This is no super-efficient
243 * implementation, but more than we need to read in a few headers.
244 * What's more, the data is actually recv'd from a socket buffer.
246 * I had to time this in comparison to recv with block read :) and
247 * the performance was very similar. Given the fact that it keeps us
248 * from creating a whole buffering scheme around the socket (HTTP
249 * connection is both line and block oriented, switching back and forth),
252 int so_recvln(int fd
, char **buf
, int *size
) {
258 while (len
< *size
-1 && c
!= '\n') {
266 * End of buffer, still no EOL? Resize the buffer
268 if (len
== *size
-1 && c
!= '\n') {
270 printf("so_recvln(%d): realloc %d\n", fd
, *size
*2);
272 tmp
= realloc(*buf
, *size
);