scanner.c

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

© 2000-2010 by contributors - visit http://www.ethernut.de/