⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmsh.c

📁 libmms开发库源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2002-2003 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA * * $Id: mmsh.c,v 1.5 2006/07/13 12:32:20 shawarma Exp $ * * MMS over HTTP protocol *   written by Thibaut Mattern *   based on mms.c and specs from avifile *   (http://avifile.sourceforge.net/asf-1.0.htm) * * TODO: *   error messages *   http support cleanup, find a way to share code with input_http.c (http.h|c) *   http proxy support */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <stdlib.h>#include <time.h>#include <assert.h>#define LOG_MODULE "mmsh"#define LOG_VERBOSE#ifdef DEBUG# define lprintf printf#else# define lprintf(x...)#endif#include "bswap.h"#include "mmsh.h"#include "asfheader.h"#include "uri.h"/* #define USERAGENT "User-Agent: NSPlayer/7.1.0.3055\r\n" */#define USERAGENT "User-Agent: NSPlayer/4.1.0.3856\r\n"#define CLIENTGUID "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n"#define MMSH_PORT                  80#define MMSH_UNKNOWN                0#define MMSH_SEEKABLE               1#define MMSH_LIVE                   2#define CHUNK_HEADER_LENGTH         4#define EXT_HEADER_LENGTH           8#define CHUNK_TYPE_RESET       0x4324#define CHUNK_TYPE_DATA        0x4424#define CHUNK_TYPE_END         0x4524#define CHUNK_TYPE_ASF_HEADER  0x4824#define CHUNK_SIZE              65536  /* max chunk size */#define ASF_HEADER_SIZE          8192  /* max header size */#define SCRATCH_SIZE             1024static const char* mmsh_FirstRequest =    "GET %s HTTP/1.0\r\n"    "Accept: */*\r\n"    USERAGENT    "Host: %s:%d\r\n"    "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%u,max-duration=0\r\n"    CLIENTGUID    "Connection: Close\r\n\r\n";static const char* mmsh_SeekableRequest =    "GET %s HTTP/1.0\r\n"    "Accept: */*\r\n"    USERAGENT    "Host: %s:%d\r\n"    "Pragma: no-cache,rate=1.000000,stream-time=%u,stream-offset=%u:%u,request-context=%u,max-duration=%u\r\n"    CLIENTGUID    "Pragma: xPlayStrm=1\r\n"    "Pragma: stream-switch-count=%d\r\n"    "Pragma: stream-switch-entry=%s\r\n" /*  ffff:1:0 ffff:2:0 */    "Connection: Close\r\n\r\n";static const char* mmsh_LiveRequest =    "GET %s HTTP/1.0\r\n"    "Accept: */*\r\n"    USERAGENT    "Host: %s:%d\r\n"    "Pragma: no-cache,rate=1.000000,request-context=%u\r\n"    "Pragma: xPlayStrm=1\r\n"    CLIENTGUID    "Pragma: stream-switch-count=%d\r\n"    "Pragma: stream-switch-entry=%s\r\n"    "Connection: Close\r\n\r\n";#if 0/* Unused requests */static const char* mmsh_PostRequest =    "POST %s HTTP/1.0\r\n"    "Accept: */*\r\n"    USERAGENT    "Host: %s\r\n"    "Pragma: client-id=%u\r\n"/*    "Pragma: log-line=no-cache,rate=1.000000,stream-time=%u,stream-offset=%u:%u,request-context=2,max-duration=%u\r\n" */    "Pragma: Content-Length: 0\r\n"    CLIENTGUID    "\r\n";static const char* mmsh_RangeRequest =    "GET %s HTTP/1.0\r\n"    "Accept: */*\r\n"    USERAGENT    "Host: %s:%d\r\n"    "Range: bytes=%Lu-\r\n"    CLIENTGUID    "Connection: Close\r\n\r\n";#endif/*  * mmsh specific types  */struct mmsh_s {  /* FIXME: de-xine-ification */  void *custom_data;  int           s;  /* url parsing */  char         *url;  char         *proxy_url;  char         *proto;  char         *connect_host;  int           connect_port;  char         *http_host;  int           http_port;  char         *proxy_user;  char         *proxy_password;  char         *host_user;  char         *host_password;  char         *uri;  char          str[SCRATCH_SIZE]; /* scratch buffer to built strings */  int           stream_type;  /* seekable or broadcast */    /* receive buffer */    /* chunk */  uint16_t      chunk_type;  uint16_t      chunk_length;  uint16_t      chunk_seq_number;  uint8_t       buf[CHUNK_SIZE];  int           buf_size;  int           buf_read;  uint8_t       asf_header[ASF_HEADER_SIZE];  uint32_t      asf_header_len;  uint32_t      asf_header_read;  int           seq_num;  int           num_stream_ids;  int           stream_ids[ASF_MAX_NUM_STREAMS];  int           stream_types[ASF_MAX_NUM_STREAMS];  uint32_t      packet_length;  int64_t       file_length;  char          guid[37];  uint32_t      bitrates[ASF_MAX_NUM_STREAMS];  uint32_t      bitrates_pos[ASF_MAX_NUM_STREAMS];  int           has_audio;  int           has_video;  off_t         current_pos;  int           user_bandwidth;};static int fallback_io_select(void *data, int socket, int state, int timeout_msec){  fd_set set;  struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000};  FD_ZERO(&set);  FD_SET(socket, &set);  return select(1, (state == MMS_IO_READ_READY) ? &set : NULL,		       (state == MMS_IO_WRITE_READY) ? &set : NULL, NULL, &tv);}static off_t fallback_io_read(void *data, int socket, char *buf, off_t num){  off_t len = 0, ret;/*   lprintf("%d\n", fallback_io_select(data, socket, MMS_IO_READ_READY, 1000)); */  errno = 0;  while (len < num)  {    ret = (off_t)read(socket, buf + len, num - len);    if(ret == 0)      break; /* EOF */    if(ret < 0)      switch(errno)      {	  case EAGAIN:	    lprintf("len == %lld\n", (long long int) len);	    break;	  default:	    lprintf("len == %lld\n", (long long int) len);	    perror(NULL);	    /* if already read something, return it, we will fail next time */	    return len ? len : ret;       }    len += ret;  }  lprintf("ret len == %lld\nnum == %lld\n", (long long int) len, (long long int) num);  lprintf("read\n");  return len;}static off_t fallback_io_write(void *data, int socket, char *buf, off_t num){  return (off_t)write(socket, buf, num);}static int fallback_io_tcp_connect(void *data, const char *host, int port){    struct hostent *h;  int i, s;    h = gethostbyname(host);  if (h == NULL) {/*     fprintf(stderr, "unable to resolve host: %s\n", host); */    return -1;  }  s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    if (s == -1) {/*     fprintf(stderr, "failed to create socket: %s", strerror(errno)); */    return -1;  }  if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) & ~O_NONBLOCK) == -1) {/*     _x_message(stream, XINE_MSG_CONNECTION_REFUSED, "can't put socket in non-blocking mode", strerror(errno), NULL); */    return -1;  }  for (i = 0; h->h_addr_list[i]; i++) {    struct in_addr ia;    struct sockaddr_in sin;     memcpy (&ia, h->h_addr_list[i], 4);    sin.sin_family = AF_INET;    sin.sin_addr   = ia;    sin.sin_port   = htons(port);        if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) ==-1 && errno != EINPROGRESS) {      /* FIXME: de-xine-ification *//*       _x_message(stream, XINE_MSG_CONNECTION_REFUSED, strerror(errno), NULL); */      close(s);      continue;    }        return s;  }  return -1;}static mms_io_t fallback_io =  {    &fallback_io_select,    NULL,    &fallback_io_read,    NULL,    &fallback_io_write,    NULL,    &fallback_io_tcp_connect,    NULL,  };static mms_io_t default_io =   {    &fallback_io_select,    NULL,    &fallback_io_read,    NULL,    &fallback_io_write,    NULL,    &fallback_io_tcp_connect,    NULL,  };#define io_read(io, args...) ((io) ? (io)->read(io->read_data , ## args) : default_io.read(NULL , ## args))#define io_write(io, args...) ((io) ? (io)->write(io->write_data , ## args) : default_io.write(NULL , ## args))#define io_select(io, args...) ((io) ? (io)->select(io->select_data , ## args) : default_io.select(NULL , ## args))#define io_connect(io, args...) ((io) ? (io)->connect(io->connect_data , ## args) : default_io.connect(NULL , ## args))  static int get_guid (unsigned char *buffer, int offset) {  int i;  GUID g;    g.Data1 = LE_32(buffer + offset);  g.Data2 = LE_16(buffer + offset + 4);  g.Data3 = LE_16(buffer + offset + 6);  for(i = 0; i < 8; i++) {    g.Data4[i] = buffer[offset + 8 + i];  }    for (i = 1; i < GUID_END; i++) {    if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) {      lprintf ("GUID: %s\n", guids[i].name);      return i;    }  }  lprintf ("libmmsh: unknown GUID: 0x%x, 0x%x, 0x%x, "           "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n",          g.Data1, g.Data2, g.Data3,          g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],           g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);  return GUID_ERROR;}static int send_command (mms_io_t *io, mmsh_t *this, char *cmd)  {  int length;  lprintf ("send_command:\n%s\n", cmd);  length = strlen(cmd);  if (io_write(io, this->s, cmd, length) != length) {    lprintf ("mmsh: send error.\n");    return 0;  }  return 1;}static int get_answer (mms_io_t *io, mmsh_t *this) {   int done, len, linenum;  char *features;  lprintf ("get_answer\n");  done = 0; len = 0; linenum = 0;  this->stream_type = MMSH_UNKNOWN;  while (!done) {    if (io_read(io, this->s, &(this->buf[len]), 1) != 1) {      lprintf ("mmsh: alart: end of stream\n");      return 0;    }    if (this->buf[len] == '\012') {      this->buf[len] = '\0';      len--;            if ((len >= 0) && (this->buf[len] == '\015')) {        this->buf[len] = '\0';        len--;      }      linenum++;            lprintf ("answer: >%s<\n", this->buf);      if (linenum == 1) {        int httpver, httpsub, httpcode;        char httpstatus[51];        if (sscanf(this->buf, "HTTP/%d.%d %d %50[^\015\012]", &httpver, &httpsub,            &httpcode, httpstatus) != 4) {	  lprintf ("mmsh: bad response format\n");          return 0;        }        if (httpcode >= 300 && httpcode < 400) {	  lprintf ("mmsh: 3xx redirection not implemented: >%d %s<\n", httpcode, httpstatus);          return 0;        }        if (httpcode < 200 || httpcode >= 300) {	  lprintf ("mmsh: http status not 2xx: >%d %s<\n", httpcode, httpstatus);          return 0;        }      } else {        if (!strncasecmp(this->buf, "Location: ", 10)) {	  lprintf ("mmsh: Location redirection not implemented.\n");          return 0;        }                if (!strncasecmp(this->buf, "Pragma:", 7)) {          features = strstr(this->buf + 7, "features=");          if (features) {            if (strstr(features, "seekable")) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -