scanner.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00045 #include <sys/heap.h>
00046 #include <sys/thread.h>
00047 #include <sys/timer.h>
00048 
00049 #include <netinet/tcp.h>
00050 #include <arpa/inet.h>
00051 
00052 #include <stdlib.h>
00053 #include <stdio.h>
00054 #include <string.h>
00055 
00056 
00057 #include "scanner.h"
00058 
00059 
00060 /*
00061  * Get line from naked TCP stream.
00062  */
00063 static int GetLine(TCPSOCKET * sock, u_char * line, u_short size)
00064 {
00065     int rc = 0;
00066     u_char to_cnt = 0;
00067     int got;
00068     u_char *cp = line;
00069 
00070     if (size > 0) {
00071         for (;;) {
00072             if ((got = NutTcpReceive(sock, cp, 1)) <= 0) {
00073                 if (got == 0 && to_cnt++ < 10)
00074                     continue;
00075                 rc = got;
00076                 printf("[GL-TO]");
00077                 break;
00078             }
00079             if (*cp == '\n') {
00080                 *cp = 0;
00081                 break;
00082             }
00083             if (*cp != '\r' && rc < (int) size) {
00084                 rc++;
00085                 cp++;
00086             }
00087         }
00088     }
00089     return rc;
00090 }
00091 
00092 static int PutString(TCPSOCKET * sock, u_char * str)
00093 {
00094     u_short len = strlen(str);
00095     u_short n;
00096     int c;
00097 
00098     for (n = 0; n < len; n += c)
00099         if ((c = NutTcpSend(sock, str + n, len - n)) < 0)
00100             return -1;
00101     return len;
00102 }
00103 
00104 
00108 int ScanStreamHeader(TCPSOCKET * sock, RADIOSTATION * rsp)
00109 {
00110     int rc = -1;
00111     u_char *line = malloc(256);
00112     char *cp;
00113 
00114     /*
00115      * Send the HTTP request.
00116      */
00117     strcpy(line, "GET /");
00118     if (rsp->rs_url)
00119         strcat(line, rsp->rs_url);
00120     strcat(line, " HTTP/1.0\r\n");
00121     PutString(sock, line);
00122 
00123     sprintf(line, "Host: %s\r\n", inet_ntoa(rsp->rs_ip));
00124     PutString(sock, line);
00125 
00126     PutString(sock, "User-Agent: WinampMPEG/2.7\r\n" "Accept: */*\r\n" "Icy-MetaData: 1\r\n" "Connection: close\r\n\r\n");
00127 
00128     if (rsp->rs_name) {
00129         free(rsp->rs_name);
00130         rsp->rs_name = 0;
00131     }
00132     if (rsp->rs_genre) {
00133         free(rsp->rs_genre);
00134         rsp->rs_genre = 0;
00135     }
00136     rsp->rs_metaint = 0;
00137 
00138     /*
00139      * Receive the HTTP header.
00140      */
00141     if (GetLine(sock, line, 256) > 5) {
00142         printf("%s\n", line);
00143         if (strncmp(line, "ICY", 3) == 0) {
00144             if (atoi(line + 4) == 200) {
00145                 for (;;) {
00146                     if ((rc = GetLine(sock, line, 256)) <= 0) {
00147                         break;
00148                     }
00149                     if (strncmp(line, "icy-name:", 9) == 0) {
00150                         cp = line + 9;
00151                         while (*cp && *cp == ' ')
00152                             cp++;
00153                         if (*cp && rsp->rs_name == 0) {
00154                             rsp->rs_name = malloc(strlen(cp) + 1);
00155                             strcpy(rsp->rs_name, cp);
00156                             printf("%s\n", cp);
00157                         }
00158                     } else if (strncmp(line, "icy-genre:", 10) == 0) {
00159                         cp = line + 10;
00160                         while (*cp && *cp == ' ')
00161                             cp++;
00162                         if (*cp && rsp->rs_genre == 0) {
00163                             rsp->rs_genre = malloc(strlen(cp) + 1);
00164                             strcpy(rsp->rs_genre, cp);
00165                         }
00166                     } else if (strncmp(line, "icy-metaint:", 12) == 0)
00167                         rsp->rs_metaint = atol(line + 12);
00168                     else if (strncmp(line, "icy-br:", 7) == 0)
00169                         rsp->rs_bitrate = atol(line + 7);
00170                 }
00171             } else
00172                 puts(line);
00173         }
00174     }
00175 
00176     free(line);
00177 
00178     printf("\n%s %ukbps %s ", inet_ntoa(rsp->rs_ip), rsp->rs_bitrate, rsp->rs_name);
00179 
00180     return rc;
00181 }
00182 
00183 /*
00184  * Process embedded meta data.
00185  */
00186 static char *ReadMetaTitle(TCPSOCKET * sock, u_long iv)
00187 {
00188     u_char blks = 0;
00189     u_short cnt;
00190     int got;
00191     int rc = 0;
00192     char *title = 0;
00193     u_char *buf;
00194     u_char *mn1;
00195     u_char *mn2;
00196     u_char *md1;
00197     u_char *md2;
00198 
00199     /* Allocate temporary buffer. */
00200     if ((buf = malloc(512 + 1)) == 0) {
00201         return 0;
00202     }
00203     for (cnt = 512; iv; iv -= got) {
00204         if (iv < 512)
00205             cnt = iv;
00206         if ((got = NutTcpReceive(sock, buf, cnt)) <= 0)
00207             break;
00208     }
00209 
00210     if (iv == 0) {
00211         /* Get the number of meta data blocks. */
00212         if ((got = NutTcpReceive(sock, &blks, 1)) == 1) {
00213             if (blks && blks <= 32) {
00214 
00215                 /* Receive the metadata block. */
00216                 for (cnt = blks * 16; cnt; cnt -= got) {
00217                     if ((got = NutTcpReceive(sock, buf + rc, cnt)) < 0)
00218                         break;
00219                     rc += got;
00220                     buf[rc] = 0;
00221                 }
00222                 if (cnt == 0) {
00223                     mn1 = buf;
00224                     while (mn1) {
00225                         if ((mn2 = strchr(mn1, ';')) != 0)
00226                             *mn2++ = 0;
00227                         if ((md1 = strchr(mn1, '=')) != 0) {
00228                             *md1++ = 0;
00229                             while (*md1 == ' ' || *md1 == '\'')
00230                                 md1++;
00231                             if ((md2 = strrchr(md1, '\'')) != 0)
00232                                 *md2 = 0;
00233                             if (strcasecmp(mn1, "StreamTitle") == 0) {
00234                                 title = malloc(strlen(md1) + 1);
00235                                 strcpy(title, md1);
00236                                 break;
00237                             }
00238                         }
00239                         mn1 = mn2;
00240                     }
00241                 }
00242             } else
00243                 printf("[ML=%u]", blks);
00244         }
00245     } else
00246         puts("[SMFAIL]");
00247     free(buf);
00248     return title;
00249 }
00250 
00251 
00252 
00253 /*
00254  * Background thread for playing stream.
00255  */
00256 THREAD(Scanner, arg)
00257 {
00258     TCPSOCKET *sock;
00259     RADIOSTATION *rsp;
00260     u_char rs;
00261     u_long rx_to = 10000UL;
00262 
00263     NutThreadSetPriority(128);
00264     NutSleep(10000);
00265     for (;;) {
00266         for (rs = 0; rs < MAXNUM_STATIONS; rs++) {
00267             NutSleep(2000);
00268             if (rs == radio.rc_rstation || rs == radio.rc_cstation)
00269                 continue;
00270             rsp = &station[rs];
00271             if (rsp->rs_ip == 0 || rsp->rs_port == 0 || radio.rc_off) {
00272                 continue;
00273             }
00274 
00275             /* Delay if this isn't the first connection. */
00276             if (rsp->rs_name) {
00277                 printf("%u bytes free\n", NutHeapAvailable());
00278                 NutSleep(30000);
00279             }
00280 
00281             /* Create a socket. */
00282             if ((sock = NutTcpCreateSocket()) == 0) {
00283                 break;
00284             }
00285             NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to));
00286 
00287             /* Connect the stream server. */
00288             printf("[Scan %s:%u]\n", inet_ntoa(rsp->rs_ip), rsp->rs_port);
00289             if (NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port) == 0) {
00290                 /* Process header from server. */
00291                 if (ScanStreamHeader(sock, rsp) == 0) {
00292                     if (rsp->rs_scantitle) {
00293                         free(rsp->rs_scantitle);
00294                         rsp->rs_scantitle = 0;
00295                     }
00296                     if (rsp->rs_metaint) {
00297                         if ((rsp->rs_scantitle = ReadMetaTitle(sock, rsp->rs_metaint)) != 0) {
00298                             printf("%03u: %s\n", rs, rsp->rs_scantitle);
00299                             rsp->rs_scandead = 0;
00300                         } else
00301                             rsp->rs_scandead = 1;
00302                     } else
00303                         rsp->rs_scandead = 0;
00304                 } else
00305                     rsp->rs_scandead = 1;
00306             } else {
00307                 rsp->rs_scandead = 1;
00308                 printf("[SERR=%d]\n", NutTcpError(sock));
00309             }
00310             NutTcpCloseSocket(sock);
00311         }
00312     }
00313     NutSleep(30000);
00314 }
00315 
00322 int ScannerInit(void)
00323 {
00324     /* Start scanner thread. */
00325     if (NutThreadCreate("scanner", Scanner, 0, 512) == 0)
00326         return -1;
00327 
00328     return 0;
00329 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/