1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <string.h>
5 
6 #include "mynet.h"
7 #include "debug.h"
8 
9 /* Cette fonction se reconnecte au server servername,
10  * port serverport, toute les time secondes, avec un
11  * maximum de _nb_tentatives.
12  *
13  * Si _nb_tentatives est NULL, ou �gal a -1, alors il n'y
14  * a aucune limite.
15  *
16  * Retourne la chausette cr��e
17  */
reconnect(int time,int _nb_tentatives,int _get_headers,icyHeaders * out_icy)18 int reconnect(int time, int _nb_tentatives, int _get_headers, icyHeaders *out_icy)
19 {
20   int tentatives = 0;
21   int server_socket;
22   serverSettings_t *settings;
23   icyHeaders *icy;
24 
25   if (!time) time = 2;
26 
27   if (serversPool == NULL)
28   {
29     _ERROR("Error: not any server defined.\n");
30     exit(1);
31   }
32 
33   /* Get an entry in the pool */
34   settings = getSettings(serversPool, &poolPosition);
35   if (settings == NULL)
36   {
37     _ERROR("No valid settings in urlPool.\n");
38     exit(1);
39   }
40 
41 RECO:
42   sleep(time);
43 
44   while ( (server_socket = server_connect(settings->serverAddr, settings->port)) < 0)
45   {
46     /* Get an entry in the pool */
47     settings = getSettings(serversPool, &poolPosition);
48     if (settings == NULL)
49     {
50       _ERROR("No valid settings in urlPool.\n");
51       exit(1);
52     }
53 
54     tentatives++;
55     if ((tentatives > _nb_tentatives) && (_nb_tentatives != -1))
56     {
57       MESSAGE("Too many tentatives. Exiting program.\n");
58       exit(-2);
59     }
60     MESSAGE("Reconnecting to http://%s:%d%s [try %d] in %d sec.\n", settings->serverAddr, settings->port, settings->mountpoint, tentatives, time);
61     sleep(time);
62   }
63 
64   VERBOSE("Time spent to reconnect: %d seconds, %d tentatives.\n", (tentatives * time), tentatives);
65 
66   if (sendHeaders(server_socket, settings->mountpoint, 1) <= 0)
67   {
68     _ERROR("Error sending headers: 0 byte sent.\n");
69     goto RECO;
70   }
71 
72   if (_get_headers)
73   {
74     if ( (icy = readicyheaders(getHeaders(server_socket))) == NULL)
75       goto RECO;
76     else
77       out_icy = icy;
78   }
79 
80   cPigeStats->reconnections++;
81 
82   return server_socket;
83 }
84 
server_connect(char * servername,int serverport)85 int server_connect (char *servername, int serverport)
86 {
87   struct sockaddr_in serverSockAddr;
88   struct hostent *serverHostEnt;
89   in_addr_t hostAddr;
90 
91 #if WIN32
92   int res;
93   VERBOSE("Using win32 sockets\n");
94   WSADATA WSAData;
95   if((res = WSAStartup(MAKEWORD(2,0), &WSAData)) != 0)
96     printf("Impossible d'initialiser l'API Winsock 2.0\n");
97 #endif
98 
99   VERBOSE("Entring Server_connect\n");
100 
101   /* on initialise la socket */
102   memset(&serverSockAddr, 0, sizeof(serverSockAddr));
103   VERBOSE("Servername: %s\n", servername);
104   VERBOSE("Port: %d\n", serverport);
105   hostAddr = inet_addr(servername);
106 
107   /* If it is an ip address */
108   if ( hostAddr != INADDR_NONE )
109     memcpy(&serverSockAddr.sin_addr, &hostAddr, sizeof(hostAddr));
110   else {
111     serverHostEnt = gethostbyname(servername);
112     if (serverHostEnt == NULL)
113     {
114       _ERROR("Error with gethostbyname. exiting.\n");
115       return -1;
116     }
117     memcpy(&serverSockAddr.sin_addr, serverHostEnt->h_addr, serverHostEnt->h_length);
118   }
119   serverSockAddr.sin_port = htons(serverport);
120   serverSockAddr.sin_family = AF_INET; /* FIXEME: IPv6 Support ? */
121 
122   /* creation de la socket */
123   if ( (server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
124   {
125     _ERROR("Error creating shoutcast socket. Exiting.\n");
126     return -2;
127   }
128 
129   VERBOSE("Socket Creation Sucessful.\n");
130   VERBOSE("Connection in progress...\n");
131 
132   /* requete de connexion */
133   if(connect( server_socket, (struct sockaddr *)&serverSockAddr, sizeof(serverSockAddr)) < 0 )
134   {
135     _ERROR("Remote host connection failed.\n");
136     return -3;
137   } else {
138     VERBOSE("Connected.\n");
139   }
140 
141   FD_ZERO(&rfds);
142   FD_SET(server_socket, &rfds);
143 
144   return server_socket;
145 }
146 
server_close(int serversocket)147 int server_close (int serversocket)
148 {
149   VERBOSE("Closing server connection.\n");
150   shutdown(server_socket, 2);
151   close(server_socket);
152   server_socket = 0;
153   VERBOSE("Server connection closed.\n");
154   return -1;
155 }
156 
sendHeaders(int serversocket,char * mountpoint,int metadata)157 int sendHeaders(int serversocket, char *mountpoint, int metadata)
158 {
159   int ret = 0;
160   char headers[256 + sizeof(USER_AGENT) + 16 + 11 + 4];
161 
162   if (mountpoint == NULL)
163     snprintf(headers, 255, "GET / HTTP/1.0\r\n");
164   else
165     snprintf(headers, 255, "GET %s HTTP/1.0\r\n", mountpoint);
166 
167   if (metadata != 0)
168     strncat(headers, "Icy-MetaData:1\r\n", 16);
169   else
170     strncat(headers, "Icy-MetaData:0\r\n", 16);
171 
172   strncat(headers, "User-Agent:", 11);
173   strncat(headers, USER_AGENT, sizeof(USER_AGENT));
174   strncat(headers, "\r\n\r\n", 4);
175 
176   ret = send(serversocket, headers, strlen(headers), 0);
177   return ret;
178 }
179 
getHeaders(int serversocket)180 char *getHeaders(int serversocket)
181 {
182   int count = 0;
183   int j, i = 0;
184   int retval, errorCode = 0;
185   char *ptr;
186   char headers[4096]; /* Must check for overflow */
187   char buffer[512];
188   char c;
189 
190   memset(headers, 0, 4096);
191   memset(buffer, 0, 512);
192 
193   /* For select() it's a global struct. */
194   timeout.tv_sec = SOCKET_TIMEOUT;
195   timeout.tv_usec = 0;
196 
197   retval = select(server_socket+1, &rfds, NULL, NULL, &timeout);
198   if (retval <= 0)
199   {
200     _ERROR("Erreur de connexion in getHeaders().\n");
201     goto error;
202   }
203 
204   i = 0;
205 
206   while ( (recv(serversocket, &c, 1, 0) > 0) && (i < 512) )
207   {
208     if (c == '\r')
209       continue;
210 
211     if (c == '\n')
212       break;
213 
214     buffer[i++] = c;
215   }
216 
217   errorCode = getHTTPCode(buffer);
218   switch(errorCode)
219   {
220     case 200:
221     case 301:
222     case 302:
223       break;
224     default:
225       _ERROR("Unknown error code received: %d\n", errorCode);
226       goto error;
227       break;
228   }
229 
230   headers[0] = 0;
231 
232   for(j = 0, i = 0; ((j < 4096) && (count != 4)); j++)
233   {
234     /* For select() it's a global struct. */
235     timeout.tv_sec = SOCKET_TIMEOUT;
236     timeout.tv_usec = 0;
237     retval = select(server_socket+1, &rfds, NULL, NULL, &timeout);
238     if (retval <= 0)
239     {
240       _ERROR("Connection error in select (getHeaders).\n");
241       goto error;
242 
243     } else if (recv(server_socket, &c, 1, 0) != 1) {
244       _ERROR("Error reading data in getHeaders()\n");
245       goto error;
246     }
247 
248     if ((c == '\n') || (c == '\r'))
249     {
250        headers[i++] = c;
251        count++;
252     } else  {
253        headers[i++] = c;
254        count = 0;
255     }
256   }
257   headers[i] = 0;
258 
259   if (!strlen(headers))
260     return NULL;
261 
262   ptr = strdup(headers);
263   printf("\n\n%s\n\n", ptr);
264 
265   return ptr;
266 
267 error:
268   server_close(server_socket);
269 
270   return NULL;
271 }
272 
getHTTPCode(char * buffer)273 int getHTTPCode(char *buffer)
274 {
275   char c;
276   char array[256]; /* Must check for overflow */
277   int i;
278   int j = 0;
279   int flag = 0;
280   int returnCode = 0;
281 
282   if ((buffer == NULL) || (strlen(buffer) > 256)) return 0;
283 
284   for (i = 0; i < strlen(buffer) && j < 256; i++)
285   {
286     c = buffer[i];
287 
288     if (c == ' ')
289     {
290       if (flag)
291       {
292         array[j+1] = 0;
293         flag = 0;
294       } else
295         flag = 1;
296     }
297 
298     if (flag)
299       array[j++] = c;
300 
301   } /* for */
302 
303   array[j] = 0;
304   returnCode = atoi((char *) &array);
305 
306   return returnCode;
307 }
308 
309 
310