webradio/station.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2007 by egnite Software GmbH. All rights reserved.
00003  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  */
00033 
00045 #include <cfg/os.h>
00046 #include <cfg/clock.h>
00047 #include <dev/board.h>
00048 
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <stdio.h>
00052 #include <fcntl.h>
00053 #include <io.h>
00054 
00055 #include <sys/version.h>
00056 #include <sys/confnet.h>
00057 #include <sys/atom.h>
00058 #include <sys/heap.h>
00059 #include <sys/thread.h>
00060 #include <sys/timer.h>
00061 #include <sys/event.h>
00062 #include <sys/socket.h>
00063 
00064 #if defined(USE_SOFTWARE_CODEC)
00065 #include <hxmp3/mp3dec.h>
00066 #endif
00067 
00068 #include <netinet/tcp.h>
00069 #include <arpa/inet.h>
00070 #include <net/route.h>
00071 #include <pro/dhcp.h>
00072 
00073 #include "config.h"
00074 #include "logmsg.h"
00075 #include "utils.h"
00076 #include "shoutcast.h"
00077 
00083 void StationDisconnect(STATIONINFO *sip)
00084 {
00085     if (sip) {
00086         LogMsg(LOG_STATION, "Disconnecting %.8s\n", sip->si_name);
00087         if (sip->si_sock) {
00088             NutTcpCloseSocket(sip->si_sock);
00089         }
00090         TcpReleaseHeaderLines(sip->si_header);
00091         free(sip);
00092     }
00093 }
00094 
00104 STATIONINFO *StationConnect(RADIOSTATION * scp, int sidx)
00105 {
00106     STATIONINFO *sip = NULL;
00107     TCPSOCKET *sock = NULL;
00108     u_short mss = MAX_TCPSEG_SIZE;
00109     u_short tcpbufsiz = MAX_TCPBUF_SIZE;
00110     u_long rx_to = MAX_TCPRCV_WAIT;
00111     int err = -1;
00112     int cr;
00113     char *line;
00114     HTTP_SCHEME *schm;
00115 
00116     if ((schm = HttpSchemeParse(scp->rs_uri[sidx])) == NULL) {
00117         return NULL;
00118     }
00119 
00120     /* Create a TCP socket. */
00121     if ((sock = NutTcpCreateSocket()) != NULL) {
00122         /* Set socket options. Failures are ignored. */
00123         NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss));
00124         NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz, sizeof(tcpbufsiz));
00125         NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to));
00126 
00127         /* Connect the stream server. */
00128         LogMsg(LOG_STATION, "Trying entry %d, %s\n", sidx, scp->rs_uri[sidx]);
00129         cr = TcpHostConnect(sock, schm->schm_host, schm->schm_portnum);
00130         if (cr == 0) {
00131             LogMsg(LOG_STATION, "Connected %s:%u\n", schm->schm_host, schm->schm_portnum);
00132 
00133             /* Create a new station info structure. */
00134             if ((sip = malloc(sizeof(STATIONINFO))) != NULL) {
00135                 memset(sip, 0, sizeof(STATIONINFO));
00136                 sip->si_sock = sock;
00137                 sip->si_scp = scp;
00138 
00139                 /*
00140                  * Send the HTTP request.
00141                  */
00142                 line = malloc(256);
00143 
00144                 if (proxy.proxy_port) {
00145                     /* A proxy requires an absolute URI. */
00146                     sprintf(line, "GET http://%s/", scp->rs_uri[sidx]);
00147                 }
00148                 else {
00149                     strcpy(line, "GET /");
00150                 }
00151                 if (schm->schm_path) {
00152                     /* URL contains a specific path. */
00153                     strcat(line, schm->schm_path);
00154                 }
00155                 strcat(line, " HTTP/1.0\r\n");
00156                 err = TcpPutString(sock, line);
00157 
00158                 if (err == 0) {
00159                     /* HTTP 1.1 requires this. So just in case... */
00160                     sprintf(line, "Host: %s\r\n", schm->schm_host);
00161                     err = TcpPutString(sock, line);
00162                 }
00163 
00164                 if (err == 0) {
00165                     /* Some SHOUTcast servers seem to require a user-agent line. 
00166                        "Eat chalk" to get in. */
00167                     TcpPutString(sock, "User-Agent: WinampMPEG/2.7\r\n" /* */
00168                         "Accept: */*\r\n"  /* */
00169                         "Icy-MetaData: 1\r\n"  /* */
00170                         "Connection: close\r\n\r\n");
00171                 }
00172 
00173                 free(line);
00174 
00175                 /* Read the servers response, collecting all header lines. */
00176                 if (TcpGetHeaderLines(sock, &sip->si_header) <= 0) {
00177                     err = -1;
00178                 }
00179             }
00180         }
00181 
00182         /* Release resources in case of any error. */
00183         if (err) {
00184             if (sip) {
00185                 StationDisconnect(sip);
00186                 sip = NULL;
00187             }
00188             else {
00189                 NutTcpCloseSocket(sock);
00190             }
00191         }
00192     }
00193     HttpSchemeRelease(schm);
00194 
00195     return sip;
00196 }

© 2008 by egnite GmbH - visit www.ethernut.de