1 /* socklib.c
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <time.h>
22 #if WIN32
23 #include <winsock2.h>
24 #else
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/uio.h>
29 #include <netinet/in.h>
30 #include <net/if.h>
31 #include <sys/ioctl.h>
32 #include <netdb.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #endif
36
37 #if __UNIX__
38 #include <arpa/inet.h>
39 #elif __BEOS__
40 #include <be/net/netdb.h>
41 #endif
42
43 #include "srtypes.h"
44 #include "socklib.h"
45 #include "threadlib.h"
46 #include "compat.h"
47 #include "debug.h"
48
49
50 #if WIN32
51 #define DEFAULT_TIMEOUT (15 * 1000)
52 #define FIRST_READ_TIMEOUT (30 * 1000)
53 #endif
54
55
56 /****************************************************************************
57 * Function definitions
58 ****************************************************************************/
59 error_code
socklib_init()60 socklib_init()
61 {
62 #if WIN32
63 WORD wVersionRequested;
64 WSADATA wsaData;
65 int err;
66
67 wVersionRequested = MAKEWORD( 2, 2 );
68 err = WSAStartup( wVersionRequested, &wsaData );
69 if ( err != 0 )
70 return SR_ERROR_WIN32_INIT_FAILURE;
71 #endif
72
73 return SR_SUCCESS;
74 }
75
76 /* Try to find the local interface to bind to */
77 error_code
read_interface(char * if_name,uint32_t * addr)78 read_interface (char *if_name, uint32_t *addr)
79 {
80 #if defined (WIN32)
81 return -1;
82 #else
83 int fd;
84 struct ifreq ifr;
85
86 memset(&ifr, 0, sizeof(struct ifreq));
87 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
88 ifr.ifr_addr.sa_family = AF_INET;
89 strcpy(ifr.ifr_name, if_name);
90 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
91 *addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
92 else {
93 close(fd);
94 return -2;
95 }
96 } else
97 return -1;
98 close(fd);
99 return 0;
100 #endif
101 }
102
103 /*
104 * open's a tcp connection to host at port, host can be a dns name or IP,
105 * socket_handle gets assigned to the handle for the connection
106 */
107 error_code
socklib_open(HSOCKET * socket_handle,char * host,int port,char * if_name,int timeout)108 socklib_open (HSOCKET *socket_handle, char *host, int port,
109 char *if_name, int timeout)
110 {
111 int rc;
112 struct sockaddr_in address, local;
113 struct hostent *hp;
114 int len;
115
116 if (!socket_handle || !host)
117 return SR_ERROR_INVALID_PARAM;
118
119 /* On error:
120 Unix returns -1 and sets errno.
121 Windows??? */
122 socket_handle->s = socket(AF_INET, SOCK_STREAM, 0);
123 if (socket_handle->s == SOCKET_ERROR) {
124 debug_printf ("socket() failed\n");
125 WSACleanup ();
126 return SR_ERROR_CANT_CREATE_SOCKET;
127 }
128
129 if (if_name) {
130 if (read_interface (if_name, &local.sin_addr.s_addr) != 0)
131 local.sin_addr.s_addr = htonl(INADDR_ANY);
132 local.sin_family = AF_INET;
133 local.sin_port = htons(0);
134 /* On error:
135 Unix returns -1 and sets errno.
136 Windows??? */
137 debug_printf ("Calling bind\n");
138 if (bind(socket_handle->s, (struct sockaddr *)&local,
139 sizeof(local)) == SOCKET_ERROR) {
140 debug_printf ("Bind failed\n");
141 WSACleanup ();
142 closesocket (socket_handle->s);
143 return SR_ERROR_CANT_BIND_ON_INTERFACE;
144 }
145 }
146
147 if ((address.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
148 debug_printf ("Calling gethostbyname\n");
149 hp = gethostbyname (host);
150 if (hp) {
151 memcpy (&address.sin_addr, hp->h_addr_list[0], hp->h_length);
152 } else {
153 debug_printf ("resolving hostname: %s failed\n", host);
154 WSACleanup ();
155 /* GCS Added... */
156 closesocket (socket_handle->s);
157 return SR_ERROR_CANT_RESOLVE_HOSTNAME;
158 }
159 }
160 address.sin_family = AF_INET;
161 address.sin_port = htons((unsigned short)port);
162 len = sizeof(address);
163
164 debug_printf ("Calling connect\n");
165 rc = connect (socket_handle->s, (struct sockaddr *)&address, len);
166 debug_printf ("Connect complete\n");
167 if (rc == SOCKET_ERROR) {
168 debug_printf ("connect failed\n");
169 /* GCS Added... */
170 WSACleanup ();
171 closesocket (socket_handle->s);
172 return SR_ERROR_CONNECT_FAILED;
173 }
174
175 #ifdef WIN32
176 {
177 struct timeval tv = {timeout, 0};
178 rc = setsockopt (socket_handle->s, SOL_SOCKET, SO_RCVTIMEO,
179 (char *)&tv, sizeof(struct timeval));
180 if (rc == SOCKET_ERROR) {
181 debug_printf ("setsockopt failed\n");
182 /* GCS Added... */
183 WSACleanup ();
184 closesocket (socket_handle->s);
185 return SR_ERROR_CANT_SET_SOCKET_OPTIONS;
186 }
187 }
188 #endif
189
190 socket_handle->closed = FALSE;
191 return SR_SUCCESS;
192 }
193
194 void
socklib_cleanup()195 socklib_cleanup()
196 {
197 WSACleanup();
198 }
199
200 void
socklib_close(HSOCKET * socket_handle)201 socklib_close(HSOCKET *socket_handle)
202 {
203 closesocket(socket_handle->s);
204 socket_handle->closed = TRUE;
205 }
206
207 error_code
socklib_read_header(RIP_MANAGER_INFO * rmi,HSOCKET * socket_handle,char * buffer,int size)208 socklib_read_header(RIP_MANAGER_INFO* rmi, HSOCKET *socket_handle,
209 char *buffer, int size)
210 {
211 int i;
212 #ifdef WIN32
213 int timeout;
214 #endif
215 int ret;
216 char *t;
217
218 if (socket_handle->closed)
219 return SR_ERROR_SOCKET_CLOSED;
220
221 #ifdef WIN32
222 timeout = 2 * rmi->prefs->timeout * 1000; /* Convert sec to msec */
223 if (setsockopt (socket_handle->s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(int)) == SOCKET_ERROR)
224 return SR_ERROR_CANT_SET_SOCKET_OPTIONS;
225 #endif
226
227 memset(buffer, 0, size);
228 for (i = 0; i < size; i++)
229 {
230 ret = socklib_recvall (rmi, socket_handle, &buffer[i], 1, 0);
231 if (ret < 0) {
232 return ret;
233 }
234
235 if (ret == 0) {
236 debug_printf("http header:\n%s\n", buffer);
237 return SR_ERROR_NO_HTTP_HEADER;
238 }
239
240 if (socket_handle->closed)
241 return SR_ERROR_SOCKET_CLOSED;
242
243 #if defined (commentout)
244 /* This is too restrictive. Some servers do not send this. */
245 if (!strstr(buffer, "icy-") && !strstr(buffer,"ice-"))
246 continue;
247 #endif
248
249 t = buffer + (i > 3 ? i - 3: i);
250
251 if (strncmp(t, "\r\n\r\n", 4) == 0)
252 break;
253 /* Allegedly live365 used to do this */
254 if (strncmp(t, "\n\0\r\n", 4) == 0)
255 break;
256 }
257
258 if (i == size) {
259 debug_printf("http header:\n%s\n", buffer);
260 return SR_ERROR_NO_HTTP_HEADER;
261 }
262
263 buffer[i] = '\0';
264
265 #ifdef WIN32
266 timeout = rmi->prefs->timeout * 1000; /* Convert sec to msec */
267 if (setsockopt (socket_handle->s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) == SOCKET_ERROR)
268 return SR_ERROR_CANT_SET_SOCKET_OPTIONS;
269 #endif
270
271 return SR_SUCCESS;
272 }
273
274 error_code
socklib_recvall(RIP_MANAGER_INFO * rmi,HSOCKET * socket_handle,char * buffer,int size,int timeout)275 socklib_recvall (RIP_MANAGER_INFO* rmi, HSOCKET *socket_handle,
276 char* buffer, int size, int timeout)
277 {
278 int ret = 0, read = 0;
279 int sock;
280 fd_set fds;
281 struct timeval tv;
282
283 sock = socket_handle->s;
284 FD_ZERO(&fds);
285 while(size) {
286 if (socket_handle->closed)
287 return SR_ERROR_SOCKET_CLOSED;
288
289 if (timeout > 0) {
290 /* Wait up to 'timeout' seconds for data on socket to be
291 ready for read */
292 #if __UNIX__
293 FD_SET(rmi->abort_pipe[0], &fds);
294 #endif
295 FD_SET(sock, &fds);
296 tv.tv_sec = timeout;
297 tv.tv_usec = 0;
298 ret = select (sock + 1, &fds, NULL, NULL, &tv);
299 if (ret == SOCKET_ERROR) {
300 /* This happens when I kill winamp while ripping */
301 return SR_ERROR_SELECT_FAILED;
302 }
303 if (ret == 0) {
304 return SR_ERROR_TIMEOUT;
305 }
306 }
307 #if __UNIX__
308 if (FD_ISSET(rmi->abort_pipe[0], &fds)) {
309 debug_printf ("socklib_recvall detected write to abort pipe.\n");
310 return SR_ERROR_ABORT_PIPE_SIGNALLED;
311 }
312 #endif
313 ret = recv(socket_handle->s, &buffer[read], size, 0);
314 debug_printf ("RECV req %5d bytes, got %5d bytes\n", size, ret);
315
316 if (ret == SOCKET_ERROR) {
317 debug_printf ("RECV failed, errno = %d\n", errno);
318 debug_printf ("Err = %s\n",strerror(errno));
319 return SR_ERROR_RECV_FAILED;
320 }
321
322 /* Got zero bytes on blocking read. For unix this is an
323 orderly shutdown. */
324 if (ret == 0) {
325 debug_printf ("recv received zero bytes!\n");
326 break;
327 }
328
329 read += ret;
330 size -= ret;
331 }
332
333 return read;
334 }
335
336 int
socklib_sendall(HSOCKET * socket_handle,char * buffer,int size)337 socklib_sendall (HSOCKET *socket_handle, char* buffer, int size)
338 {
339 int ret = 0, sent = 0;
340
341 while(size) {
342 if (socket_handle->closed)
343 return SR_ERROR_SOCKET_CLOSED;
344
345 ret = send(socket_handle->s, &buffer[sent], size, 0);
346 if (ret == SOCKET_ERROR)
347 return SR_ERROR_SEND_FAILED;
348
349 if (ret == 0)
350 break;
351
352 sent += ret;
353 size -= ret;
354 }
355
356 return sent;
357 }
358