2 * Networking under WINDOWS
3 * Copyright (C) 2007-2008 Andreas Ă–man
4 * Copyright (C) 2007-2008 Joakim Plate
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
34 static int socket_errno()
36 int error = WSAGetLastError();
39 case WSAEINPROGRESS: return EINPROGRESS;
40 case WSAECONNRESET : return ECONNRESET;
41 case WSAETIMEDOUT : return ETIMEDOUT;
42 case WSAEWOULDBLOCK: return EAGAIN;
43 default : return error;
48 #define MSG_WAITALL 0x8
51 static int recv_fixed (SOCKET s, char * buf, int len, int flags)
56 if((flags & MSG_WAITALL) == 0)
57 return recv(s, buf, len, flags);
59 flags &= ~MSG_WAITALL;
60 while(len > 0 && res > 0)
62 res = recv(s, buf, len, flags);
71 #define recv(s, buf, len, flags) recv_fixed(s, buf, len, flags)
77 htsp_tcp_connect_addr(struct addrinfo* addr, char *errbuf, size_t errbufsize,
82 socklen_t errlen = sizeof(int);
84 fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
86 snprintf(errbuf, errbufsize, "Unable to create socket: %s",
87 strerror(socket_errno()));
92 * Switch to nonblocking
95 ioctlsocket(fd, FIONBIO, &val);
97 r = connect(fd, addr->ai_addr, addr->ai_addrlen);
100 if(socket_errno() == EINPROGRESS ||
101 socket_errno() == EAGAIN) {
102 fd_set fd_write, fd_except;
105 tv.tv_sec = timeout / 1000;
106 tv.tv_usec = 1000 * (timeout % 1000);
111 FD_SET(fd, &fd_write);
112 FD_SET(fd, &fd_except);
114 r = select((int)fd+1, NULL, &fd_write, &fd_except, &tv);
118 snprintf(errbuf, errbufsize, "Connection attempt timed out");
124 snprintf(errbuf, errbufsize, "select() error: %s", strerror(socket_errno()));
129 getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen);
131 err = socket_errno();
138 snprintf(errbuf, errbufsize, "%s", strerror(err));
144 ioctlsocket(fd, FIONBIO, &val);
147 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&val, sizeof(val));
154 htsp_tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize,
157 struct addrinfo hints;
158 struct addrinfo *result, *addr;
161 socket_t fd = INVALID_SOCKET;
163 memset(&hints, 0, sizeof(hints));
164 hints.ai_family = AF_UNSPEC;
165 hints.ai_socktype = SOCK_STREAM;
166 hints.ai_protocol = IPPROTO_TCP;
167 sprintf(service, "%d", port);
169 res = getaddrinfo(hostname, service, &hints, &result);
173 snprintf(errbuf, errbufsize, "The specified host is unknown");
177 snprintf(errbuf, errbufsize, "A nonrecoverable failure in name resolution occurred");
181 snprintf(errbuf, errbufsize, "A memory allocation failure occurred");
185 snprintf(errbuf, errbufsize, "A temporary error occurred on an authoritative name server");
189 snprintf(errbuf, errbufsize, "Unknown error %d", res);
195 for(addr = result; addr; addr = addr->ai_next) {
196 fd = htsp_tcp_connect_addr(addr, errbuf, errbufsize, timeout);
197 if(fd != INVALID_SOCKET)
201 freeaddrinfo(result);
210 htsp_tcp_write_queue(socket_t fd, htsbuf_queue_t *q)
215 while((hd = TAILQ_FIRST(&q->hq_q)) != NULL) {
216 TAILQ_REMOVE(&q->hq_q, hd, hd_link);
218 l = hd->hd_data_len - hd->hd_data_off;
219 r = send(fd, hd->hd_data + hd->hd_data_off, l, 0);
232 tcp_fill_htsbuf_from_fd(socket_t fd, htsbuf_queue_t *hq)
234 htsbuf_data_t *hd = TAILQ_LAST(&hq->hq_q, htsbuf_data_queue);
238 /* Fill out any previous buffer */
239 c = hd->hd_data_size - hd->hd_data_len;
243 c = recv(fd, hd->hd_data + hd->hd_data_len, c, MSG_WAITALL);
247 hd->hd_data_len += c;
253 hd = malloc(sizeof(htsbuf_data_t));
255 hd->hd_data_size = 1000;
256 hd->hd_data = malloc(hd->hd_data_size);
258 c = recv(fd, hd->hd_data, hd->hd_data_size, MSG_WAITALL);
266 TAILQ_INSERT_TAIL(&hq->hq_q, hd, hd_link);
276 htsp_tcp_read_line(socket_t fd, char *buf, const size_t bufsize, htsbuf_queue_t *spill)
281 len = htsbuf_find(spill, 0xa);
284 if(tcp_fill_htsbuf_from_fd(fd, spill) < 0)
289 if(len >= (int)bufsize - 1)
292 htsbuf_read(spill, buf, len);
294 while(len > 0 && buf[len - 1] < 32)
296 htsbuf_drop(spill, 1); /* Drop the \n */
306 htsp_tcp_read_data(socket_t fd, char *buf, const size_t bufsize, htsbuf_queue_t *spill)
308 int x, tot = htsbuf_read(spill, buf, bufsize);
313 x = recv(fd, buf + tot, bufsize - tot, MSG_WAITALL);
314 if(x != bufsize - tot)
324 htsp_tcp_read(socket_t fd, void *buf, size_t len)
326 int x = recv(fd, buf, len, MSG_WAITALL);
329 return socket_errno();
340 htsp_tcp_read_timeout(socket_t fd, char *buf, size_t len, int timeout)
342 int x, tot = 0, val, err;
350 tv.tv_sec = timeout / 1000;
351 tv.tv_usec = 1000 * (timeout % 1000);
354 FD_SET(fd, &fd_read);
356 x = select((int)fd+1, &fd_read, NULL, NULL, &tv);
362 ioctlsocket(fd, FIONBIO, &val);
364 x = recv(fd, buf + tot, len - tot, 0);
365 err = socket_errno();
368 ioctlsocket(fd, FIONBIO, &val);
388 htsp_tcp_close(socket_t fd)