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

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