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 
00052 #include <sys/heap.h>
00053 #include <sys/thread.h>
00054 #include <sys/timer.h>
00055 
00056 #include <netinet/tcp.h>
00057 #include <arpa/inet.h>
00058 
00059 #include <stdlib.h>
00060 #include <stdio.h>
00061 #include <string.h>
00062 
00063 
00064 #include "scanner.h"
00065 
00066 
00067 /*
00068  * Get line from naked TCP stream.
00069  */
00070 static int GetLine(TCPSOCKET * sock, char * line, u_short size)
00071 {
00072     int rc = 0;
00073     u_char to_cnt = 0;
00074     int got;
00075     char *cp = line;
00076 
00077     if (size > 0) {
00078         for (;;) {
00079             if ((got = NutTcpReceive(sock, cp, 1)) <= 0) {
00080                 if (got == 0 && to_cnt++ < 10)
00081                     continue;
00082                 rc = got;
00083                 printf("[GL-TO]");
00084                 break;
00085             }
00086             if (*cp == '\n') {
00087                 *cp = 0;
00088                 break;
00089             }
00090             if (*cp != '\r' && rc < (int) size) {
00091                 rc++;
00092                 cp++;
00093             }
00094         }
00095     }
00096     return rc;
00097 }
00098 
00099 static int PutString(TCPSOCKET * sock, char * str)
00100 {
00101     u_short len = strlen(str);
00102     u_short n;
00103     int c;
00104 
00105     for (n = 0; n < len; n += c)
00106         if ((c = NutTcpSend(sock, str + n, len - n)) < 0)
00107             return -1;
00108     return len;
00109 }
00110 
00111 
00115 int ScanStreamHeader(TCPSOCKET * sock, RADIOSTATION * rsp)
00116 {
00117     int rc = -1;
00118     char *line = malloc(256);
00119     char *cp;
00120 
00121     /*
00122      * Send the HTTP request.
00123      */
00124     strcpy(line, "GET /");
00125     if (rsp->rs_url)
00126         strcat(line, rsp->rs_url);
00127     strcat(line, " HTTP/1.0\r\n");
00128     PutString(sock, line);
00129 
00130     sprintf(line, "Host: %s\r\n", inet_ntoa(rsp->rs_ip));
00131     PutString(sock, line);
00132 
00133     PutString(sock, "User-Agent: WinampMPEG/2.7\r\n" "Accept: */*\r\n" "Icy-MetaData: 1\r\n" "Connection: close\r\n\r\n");
00134 
00135     if (rsp->rs_name) {
00136         free(rsp->rs_name);
00137         rsp->rs_name = 0;
00138     }
00139     if (rsp->rs_genre) {
00140         free(rsp->rs_genre);
00141         rsp->rs_genre = 0;
00142     }
00143     rsp->rs_metaint = 0;
00144 
00145     /*
00146      * Receive the HTTP header.
00147      */
00148     if (GetLine(sock, line, 256) > 5) {
00149         printf("%s\n", line);
00150         if (strncmp(line, "ICY", 3) == 0) {
00151             if (atoi(line + 4) == 200) {
00152                 for (;;) {
00153                     if ((rc = GetLine(sock, line, 256)) <= 0) {
00154                         break;
00155                     }
00156                     if (strncmp(line, "icy-name:", 9) == 0) {
00157                         cp = line + 9;
00158                         while (*cp && *cp == ' ')
00159                             cp++;
00160                         if (*cp && rsp->rs_name == 0) {
00161                             rsp->rs_name = malloc(strlen(cp) + 1);
00162                             strcpy(rsp->rs_name, cp);
00163                             printf("%s\n", cp);
00164                         }
00165                     } else if (strncmp(line, "icy-genre:", 10) == 0) {
00166                         cp = line + 10;
00167                         while (*cp && *cp == ' ')
00168                             cp++;
00169                         if (*cp && rsp->rs_genre == 0) {
00170                             rsp->rs_genre = malloc(strlen(cp) + 1);
00171                             strcpy(rsp->rs_genre, cp);
00172                         }
00173                     } else if (strncmp(line, "icy-metaint:", 12) == 0)
00174                         rsp->rs_metaint = atol(line + 12);
00175                     else if (strncmp(line, "icy-br:", 7) == 0)
00176                         rsp->rs_bitrate = atol(line + 7);
00177                 }
00178             } else
00179                 puts(line);
00180         }
00181     }
00182 
00183     free(line);
00184 
00185     printf("\n%s %ukbps %s ", inet_ntoa(rsp->rs_ip), rsp->rs_bitrate, rsp->rs_name);
00186 
00187     return rc;
00188 }
00189 
00190 /*
00191  * Process embedded meta data.
00192  */
00193 static char *ReadMetaTitle(TCPSOCKET * sock, u_long iv)
00194 {
00195     u_char blks = 0;
00196     u_short cnt;
00197     int got;
00198     int rc = 0;
00199     char *title = 0;
00200     char *buf;
00201     char *mn1;
00202     char *mn2;
00203     char *md1;
00204     char *md2;
00205 
00206     /* Allocate temporary buffer. */
00207     if ((buf = malloc(512 + 1)) == 0) {
00208         return 0;
00209     }
00210     for (cnt = 512; iv; iv -= got) {
00211         if (iv < 512)
00212             cnt = iv;
00213         if ((got = NutTcpReceive(sock, buf, cnt)) <= 0)
00214             break;
00215     }
00216 
00217     if (iv == 0) {
00218         /* Get the number of meta data blocks. */
00219         if ((got = NutTcpReceive(sock, &blks, 1)) == 1) {
00220             if (blks && blks <= 32) {
00221 
00222                 /* Receive the metadata block. */
00223                 for (cnt = blks * 16; cnt; cnt -= got) {
00224                     if ((got = NutTcpReceive(sock, buf + rc, cnt)) < 0)
00225                         break;
00226                     rc += got;
00227                     buf[rc] = 0;
00228                 }
00229                 if (cnt == 0) {
00230                     mn1 = buf;
00231                     while (mn1) {
00232                         if ((mn2 = strchr(mn1, ';')) != 0)
00233                             *mn2++ = 0;
00234                         if ((md1 = strchr(mn1, '=')) != 0) {
00235                             *md1++ = 0;
00236                             while (*md1 == ' ' || *md1 == '\'')
00237                                 md1++;
00238                             if ((md2 = strrchr(md1, '\'')) != 0)
00239                                 *md2 = 0;
00240                             if (strcasecmp(mn1, "StreamTitle") == 0) {
00241                                 title = malloc(strlen(md1) + 1);
00242                                 strcpy(title, md1);
00243                                 break;
00244                             }
00245                         }
00246                         mn1 = mn2;
00247                     }
00248                 }
00249             } else
00250                 printf("[ML=%u]", blks);
00251         }
00252     } else
00253         puts("[SMFAIL]");
00254     free(buf);
00255     return title;
00256 }
00257 
00258 
00259 
00260 /*
00261  * Background thread for playing stream.
00262  */
00263 THREAD(Scanner, arg)
00264 {
00265     TCPSOCKET *sock;
00266     RADIOSTATION *rsp;
00267     u_char rs;
00268     u_long rx_to = 10000UL;
00269 
00270     NutThreadSetPriority(128);
00271     NutSleep(10000);
00272     for (;;) {
00273         for (rs = 0; rs < MAXNUM_STATIONS; rs++) {
00274             NutSleep(2000);
00275             if (rs == radio.rc_rstation || rs == radio.rc_cstation)
00276                 continue;
00277             rsp = &station[rs];
00278             if (rsp->rs_ip == 0 || rsp->rs_port == 0 || radio.rc_off) {
00279                 continue;
00280             }
00281 
00282             /* Delay if this isn't the first connection. */
00283             if (rsp->rs_name) {
00284                 printf("%lu bytes free\n", NutHeapAvailable());
00285                 NutSleep(30000);
00286             }
00287 
00288             /* Create a socket. */
00289             if ((sock = NutTcpCreateSocket()) == 0) {
00290                 break;
00291             }
00292             NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to));
00293 
00294             /* Connect the stream server. */
00295             printf("[Scan %s:%u]\n", inet_ntoa(rsp->rs_ip), rsp->rs_port);
00296             if (NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port) == 0) {
00297                 /* Process header from server. */
00298                 if (ScanStreamHeader(sock, rsp) == 0) {
00299                     if (rsp->rs_scantitle) {
00300                         free(rsp->rs_scantitle);
00301                         rsp->rs_scantitle = 0;
00302                     }
00303                     if (rsp->rs_metaint) {
00304                         if ((rsp->rs_scantitle = ReadMetaTitle(sock, rsp->rs_metaint)) != 0) {
00305                             printf("%03u: %s\n", rs, rsp->rs_scantitle);
00306                             rsp->rs_scandead = 0;
00307                         } else
00308                             rsp->rs_scandead = 1;
00309                     } else
00310                         rsp->rs_scandead = 0;
00311                 } else
00312                     rsp->rs_scandead = 1;
00313             } else {
00314                 rsp->rs_scandead = 1;
00315                 printf("[SERR=%d]\n", NutTcpError(sock));
00316             }
00317             NutTcpCloseSocket(sock);
00318         }
00319     }
00320     NutSleep(30000);
00321 }
00322 
00329 int ScannerInit(void)
00330 {
00331     /* Start scanner thread. */
00332     if (NutThreadCreate("scanner", Scanner, 0, 512) == 0)
00333         return -1;
00334 
00335     return 0;
00336 }

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