Logo Search packages:      
Sourcecode: vdr-plugin-streamdev version File versions  Download package

connectionHTTP.c

/*
 *  $Id: connectionHTTP.c,v 1.13 2008/03/28 15:11:40 schmirl Exp $
 */

#include <ctype.h>
 
#include "server/connectionHTTP.h"
#include "server/menuHTTP.h"
#include "server/setup.h"

cConnectionHTTP::cConnectionHTTP(void): 
            cServerConnection("HTTP"),
            m_Status(hsRequest),
            m_LiveStreamer(NULL),
            m_StreamerParameter(""),
            m_Channel(NULL),
            m_Apid(0),
            m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
            m_ChannelList(NULL)
{
      Dprintf("constructor hsRequest\n");
}

cConnectionHTTP::~cConnectionHTTP() 
{
      delete m_LiveStreamer;
}

bool cConnectionHTTP::Command(char *Cmd) 
{
      Dprintf("command %s\n", Cmd);
      switch (m_Status) {
      case hsRequest:
            Dprintf("Request\n");
            m_Request = Cmd;
            m_Status = hsHeaders;
            return true;

      case hsHeaders:
            if (*Cmd == '\0') {
                  m_Status = hsBody;
                  return ProcessRequest();
            }
            if (strncasecmp(Cmd, "Host:", 5) == 0) {
                  Dprintf("Host-Header\n");
                  m_Host = (std::string) skipspace(Cmd + 5);
            }
            Dprintf("header\n");
            return true;
      default:
            break;
      }
      return false; // ??? shouldn't happen
}

bool cConnectionHTTP::ProcessRequest(void) 
{
      Dprintf("process\n");
      if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
            switch (m_Job) {
            case hjListing:
                  if (m_ChannelList)
                        return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
                  break;

            case hjTransfer:
                  if (m_Channel == NULL) {
                        DeferClose();
                        return Respond("HTTP/1.0 404 not found");
                  }
                  
                  m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter);
                  cDevice *device = GetDevice(m_Channel, 0);
                  if (device != NULL) {
                        device->SwitchChannel(m_Channel, false);
                        if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) {
                              m_LiveStreamer->SetDevice(device);
                              if (!SetDSCP())
                                    LOG_ERROR_STR("unable to set DSCP sockopt");
                              if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) {
                                    return Respond("HTTP/1.0 200 OK")
                                        && Respond("Content-Type: audio/mpeg")
                                        && Respond("icy-name: %s", true, m_Channel->Name())
                                        && Respond("");
                              } else {
                                    return Respond("HTTP/1.0 200 OK")
                                        && Respond("Content-Type: video/mpeg")
                                        && Respond("");
                              }
                        }
                  }
                  DELETENULL(m_LiveStreamer);
                  DeferClose();
                  return Respond("HTTP/1.0 409 Channel not available")
                        && Respond("");
            }
      }

      DeferClose();
      return Respond("HTTP/1.0 400 Bad Request")
            && Respond("");
}

void cConnectionHTTP::Flushed(void) 
{
      std::string line;

      if (m_Status != hsBody)
            return;

      switch (m_Job) {
      case hjListing:
            if (m_ChannelList) {
                  if (m_ChannelList->HasNext()) {
                        if (!Respond("%s", true, m_ChannelList->Next().c_str()))
                              DeferClose();
                  }
                  else {
                        DELETENULL(m_ChannelList);
                        m_Status = hsFinished;
                        DeferClose();
                  }
                  return;
            }
            // should never be reached
            esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list");
            m_Status = hsFinished;
            break;

      case hjTransfer:
            Dprintf("streamer start\n");
            m_LiveStreamer->Start(this);
            m_Status = hsFinished;
            break;
      }
}

bool cConnectionHTTP::CmdGET(const std::string &Opts) 
{
      const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep;
      const cChannel *chan;
      int apid = 0;

      ptr = Opts.c_str();

      // find begin of URL
      sp = skipspace(ptr);
      // find end of URL (\0 or first space character)
      for (ep = sp; *ep && !isspace(*ep); ep++) 
            ;
      // find begin of query string (first ?)
      for (qp = sp; qp < ep && *qp != '?'; qp++)
            ;
      // find begin of filename (last /)
      for (fp = qp; fp > sp && *fp != '/'; --fp)
            ;
      // find begin of section params (first ;)
      for (pp = sp; pp < fp && *pp != ';'; pp++)
            ;
      // find filename extension (first .)
      for (xp = fp; xp < qp && *xp != '.'; xp++)
            ;
      if (qp - xp > 5) // too long for a filename extension
            xp = qp;

      std::string type, filespec, fileext, query;
      // Streamtype with leading / stripped off
      if (pp > sp)
            type = Opts.substr(sp - ptr + 1, pp - sp - 1);
      // Section parameters with leading ; stripped off
      if (fp > pp)
            m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1);
      // file basename with leading / stripped off
      if (xp > fp)
            filespec = Opts.substr(fp - ptr + 1, xp - fp - 1);
      // file extension including leading .
      fileext = Opts.substr(xp - ptr, qp - xp);
      // query string including leading ?
      query = Opts.substr(qp - ptr, ep - qp);

      Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str());

      const char* pType = type.c_str();
      if (strcasecmp(pType, "PS") == 0) {
            m_StreamType = stPS;
      } else if (strcasecmp(pType, "PES") == 0) {
            m_StreamType = stPES;
      } else if (strcasecmp(pType, "TS") == 0) {
            m_StreamType = stTS;
      } else if (strcasecmp(pType, "ES") == 0) {
            m_StreamType = stES;
      } else if (strcasecmp(pType, "Extern") == 0) {
            m_StreamType = stExtern;
      }

      std::string groupTarget;
      cChannelIterator *iterator = NULL;

      if (filespec.compare("tree") == 0) {
            const cChannel* c = NULL;
            size_t groupIndex = query.find("group=");
            if (groupIndex != std::string::npos)
                  c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
            iterator = new cListTree(c);
            groupTarget = filespec + fileext;
      } else if (filespec.compare("groups") == 0) {
            iterator = new cListGroups();
            groupTarget = (std::string) "group" + fileext;
      } else if (filespec.compare("group") == 0) {
            const cChannel* c = NULL;
            size_t groupIndex = query.find("group=");
            if (groupIndex != std::string::npos)
                  c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
            iterator = new cListGroup(c);
      } else if (filespec.compare("channels") == 0) {
            iterator = new cListChannels();
      } else if (filespec.compare("all") == 0 ||
                  (filespec.empty() && fileext.empty())) {
            iterator = new cListAll();
      }

      if (iterator) {
            if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) {
                  m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str());
                  m_Job = hjListing;
            } else if (fileext.compare(".m3u") == 0) {
                  std::string base;
                  if (*(m_Host.c_str()))
                        base = "http://" + m_Host + "/";
                  else
                        base = (std::string) "http://" + LocalIp() + ":" +
                              (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/";
                  if (type.empty())
                  {
                        switch (m_StreamType)
                        {
                              case stTS:  base += "TS/"; break;
                              case stPS:  base += "PS/"; break;
                              case stPES: base += "PES/"; break;
                              case stES:  base += "ES/"; break;
                              case stExtern:    base += "Extern/"; break;
                              default:    break;
                  
                        }
                  } else {
                        base += type;
                        if (!m_StreamerParameter.empty())
                              base += ";" + m_StreamerParameter;
                        base += "/";
                  }
                  m_ChannelList = new cM3uChannelList(iterator, base.c_str());
                  m_Job = hjListing;
            } else {
                  delete iterator;
                  return false;
            }
      } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) {
            m_Channel = chan;
            m_Apid = apid;
            Dprintf("Apid is %d\n", apid);
            m_Job = hjTransfer;
      } else
            return false;
      
      Dprintf("after channelfromstring\n");
      return true;
}


Generated by  Doxygen 1.6.0   Back to index