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