diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/input/mmsh.c | 301 |
1 files changed, 128 insertions, 173 deletions
diff --git a/src/input/mmsh.c b/src/input/mmsh.c index a815a9ff9..6cf0a47ce 100644 --- a/src/input/mmsh.c +++ b/src/input/mmsh.c @@ -17,7 +17,7 @@ * 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.21 2003/11/26 19:43:31 f1rmb Exp $ + * $Id: mmsh.c,v 1.22 2003/12/04 21:37:40 tmattern Exp $ * * MMS over HTTP protocol * written by Thibaut Mattern @@ -58,11 +58,12 @@ #include "xineutils.h" #include "bswap.h" -#include "io_helper.h" +#include "url_helper.h" #include "mmsh.h" #include "../demuxers/asfheader.h" -#define USERAGENT "User-Agent: NSPlayer/7.1.0.3055\r\n" +/* #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" @@ -77,11 +78,13 @@ #define CHUNK_SIZE 65536 /* max chunk size */ #define ASF_HEADER_SIZE 8192 /* max header size */ +#define SCRATCH_SIZE 1024 + static const char* mmsh_FirstRequest = "GET %s HTTP/1.0\r\n" "Accept: */*\r\n" USERAGENT - "Host: %s\r\n" + "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"; @@ -90,7 +93,7 @@ static const char* mmsh_SeekableRequest = "GET %s HTTP/1.0\r\n" "Accept: */*\r\n" USERAGENT - "Host: %s\r\n" + "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" @@ -102,7 +105,7 @@ static const char* mmsh_LiveRequest = "GET %s HTTP/1.0\r\n" "Accept: */*\r\n" USERAGENT - "Host: %s\r\n" + "Host: %s:%d\r\n" "Pragma: no-cache,rate=1.000000,request-context=%u\r\n" "Pragma: xPlayStrm=1\r\n" CLIENTGUID @@ -128,12 +131,14 @@ static const char* mmsh_RangeRequest = "GET %s HTTP/1.0\r\n" "Accept: */*\r\n" USERAGENT - "Host: %s\r\n" + "Host: %s:%d\r\n" "Range: bytes=%Lu-\r\n" CLIENTGUID "Connection: Close\r\n\r\n"; #endif + + /* * mmsh specific types */ @@ -145,13 +150,16 @@ struct mmsh_s { int s; + /* url parsing */ + char *url; + char *proto; char *host; int port; - char *path; - char *file; - char *url; + char *user; + char *password; + char *uri; - char str[1024]; /* scratch buffer to built strings */ + char str[SCRATCH_SIZE]; /* scratch buffer to built strings */ int stream_type; /* seekable or broadcast */ @@ -184,51 +192,13 @@ struct mmsh_s { int has_video; }; -static uint32_t get_64 (uint8_t *buffer, int offset) { - - uint64_t ret; - - ret = ((uint64_t)buffer[offset]) | - ((uint64_t)buffer[offset + 1] << 8) | - ((uint64_t)buffer[offset + 2] << 16) | - ((uint64_t)buffer[offset + 2] << 24) | - ((uint64_t)buffer[offset + 2] << 32) | - ((uint64_t)buffer[offset + 2] << 40) | - ((uint64_t)buffer[offset + 2] << 48) | - ((uint64_t)buffer[offset + 2] << 56); - - return ret; -} - -static uint32_t get_32 (uint8_t *buffer, int offset) { - - uint32_t ret; - - ret = buffer[offset] | - buffer[offset + 1] << 8 | - buffer[offset + 2] << 16 | - buffer[offset + 3] << 24 ; - - return ret; -} - -static uint16_t get_16 (unsigned char *buffer, int offset) { - - uint16_t ret; - - ret = buffer[offset] | - buffer[offset + 1] << 8; - - return ret; -} - static int get_guid (unsigned char *buffer, int offset) { int i; GUID g; - g.Data1 = get_32(buffer, offset); - g.Data2 = get_16(buffer, offset + 4); - g.Data3 = get_16(buffer, offset + 6); + 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]; } @@ -241,11 +211,11 @@ static int get_guid (unsigned char *buffer, int offset) { } } - printf ("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", + 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]); + g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); return GUID_ERROR; } @@ -256,7 +226,8 @@ static int send_command (mmsh_t *this, char *cmd) { length = strlen(cmd); if (_x_io_tcp_write(this->stream, this->s, cmd, length) != length) { - printf ("libmmsh: send error\n"); + xprintf (this->stream->xine, XINE_LOG_MSG, + "libmmsh: send error\n"); return 0; } return 1; @@ -275,7 +246,8 @@ static int get_answer (mmsh_t *this) { while (!done) { if (_x_io_tcp_read(this->stream, this->s, &(this->buf[len]), 1) != 1) { - printf ("libmmsh: alert: end of stream\n"); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: alert: end of stream\n"); return 0; } @@ -299,25 +271,29 @@ static int get_answer (mmsh_t *this) { if (sscanf(this->buf, "HTTP/%d.%d %d", &httpver, &httpsub, &httpcode) != 3) { - printf( "libmmsh: bad response format\n"); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("libmmsh: bad response format\n")); return 0; } if (httpcode >= 300 && httpcode < 400) { - printf( _("libmmsh: 3xx redirection not implemented: >%d %s<\n"), - httpcode, httpstatus); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("libmmsh: 3xx redirection not implemented: >%d %s<\n"), + httpcode, httpstatus); return 0; } if (httpcode < 200 || httpcode >= 300) { - printf( _("libmmsh: http status not 2xx: >%d %s<\n"), - httpcode, httpstatus); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("libmmsh: http status not 2xx: >%d %s<\n"), + httpcode, httpstatus); return 0; } } else { if (!strncasecmp(this->buf, "Location: ", 10)) { - printf( _("libmmsh: Location redirection not implemented\n")); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("libmmsh: Location redirection not implemented\n")); return 0; } @@ -347,7 +323,8 @@ static int get_answer (mmsh_t *this) { } } if (this->stream_type == MMSH_UNKNOWN) { - printf("libmmsh: unknown stream type\n"); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: unknown stream type\n"); this->stream_type = MMSH_SEEKABLE; /* FIXME ? */ } return 1; @@ -362,13 +339,13 @@ static int get_chunk_header (mmsh_t *this) { /* chunk header */ len = _x_io_tcp_read(this->stream, this->s, chunk_header, CHUNK_HEADER_LENGTH); if (len != CHUNK_HEADER_LENGTH) { - lprintf ("chunk header read failed, %d != %d\n", len, CHUNK_HEADER_LENGTH); - + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "chunk header read failed, %d != %d\n", len, CHUNK_HEADER_LENGTH); return 0; } - this->chunk_type = get_16 (chunk_header, 0); - this->chunk_length = get_16 (chunk_header, 2) - 8; - this->chunk_seq_number = get_32 (chunk_header, 4); + this->chunk_type = LE_16 (chunk_header); + this->chunk_length = LE_16 (chunk_header + 2) - 8; + this->chunk_seq_number = LE_32 (chunk_header + 4); /* display debug infos */ #ifdef LOG @@ -402,7 +379,8 @@ static int get_header (mmsh_t *this) { if (get_chunk_header(this)) { if (this->chunk_type == CHUNK_TYPE_ASF_HEADER) { if ((this->asf_header_len + this->chunk_length) > ASF_HEADER_SIZE) { - printf ("libmmsh: the asf header exceed %d bytes\n", ASF_HEADER_SIZE); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: the asf header exceed %d bytes\n", ASF_HEADER_SIZE); return 0; } else { len = _x_io_tcp_read(this->stream, this->s, this->asf_header + this->asf_header_len, @@ -451,7 +429,7 @@ static void interp_header (mmsh_t *this) { guid = get_guid(this->asf_header, i); i += 16; - length = get_64(this->asf_header, i); + length = LE_64(this->asf_header + i); i += 8; if ((i + length) >= this->asf_header_len) return; @@ -460,10 +438,10 @@ static void interp_header (mmsh_t *this) { case GUID_ASF_FILE_PROPERTIES: - this->packet_length = get_32(this->asf_header, i + 92 - 24); - this->file_length = get_32(this->asf_header, i + 40 - 24); + this->packet_length = LE_32(this->asf_header + i + 92 - 24); + this->file_length = LE_32(this->asf_header + i + 40 - 24); lprintf ("file object, packet length = %d (%d)\n", - this->packet_length, get_32(this->asf_header, i + 96 - 24)); + this->packet_length, LE_32(this->asf_header + i + 96 - 24)); break; case GUID_ASF_STREAM_PROPERTIES: @@ -491,7 +469,7 @@ static void interp_header (mmsh_t *this) { type = ASF_STREAM_TYPE_UNKNOWN; } - stream_id = get_16(this->asf_header, i + 48); + stream_id = LE_16(this->asf_header + i + 48); lprintf ("stream object, stream id: %d\n", stream_id); @@ -504,7 +482,7 @@ static void interp_header (mmsh_t *this) { case GUID_ASF_STREAM_BITRATE_PROPERTIES: { - uint16_t streams = get_16(this->asf_header, i); + uint16_t streams = LE_16(this->asf_header + i); uint16_t stream_id; int j; @@ -512,14 +490,15 @@ static void interp_header (mmsh_t *this) { lprintf ("streams %d\n", streams); for(j = 0; j < streams; j++) { - stream_id = get_16(this->asf_header, i + 2 + j * 6); + stream_id = LE_16(this->asf_header + i + 2 + j * 6); lprintf ("stream id %d\n", stream_id); - this->bitrates[stream_id] = get_32(this->asf_header, i + 4 + j * 6); + this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6); this->bitrates_pos[stream_id] = i + 4 + j * 6; - printf ("libmmsh: stream id %d, bitrate %d\n", stream_id, - this->bitrates[stream_id]); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: stream id %d, bitrate %d\n", + stream_id, this->bitrates[stream_id]); } } break; @@ -537,21 +516,19 @@ static void interp_header (mmsh_t *this) { } } -const static char *const mmsh_url_s[] = { "MMS://", "MMSH://", NULL }; +const static char *const mmsh_proto_s[] = { "mms", "mmsh", NULL }; -static int mmsh_valid_url (char* url, const char *const * mmsh_url) { +static int mmsh_valid_proto (char *proto) { int i = 0; - int len; - lprintf("mmsh_valid_url\n"); + lprintf("mmsh_valid_proto\n"); - if(!url ) + if (!proto) return 0; - while(mmsh_url[i]) { - len = strlen(mmsh_url[i]); - if(!strncasecmp(url, mmsh_url[i], len)) { - return len; + while(mmsh_proto_s[i]) { + if (!strcasecmp(proto, mmsh_proto_s[i])) { + return 1; } i++; } @@ -574,62 +551,13 @@ static void report_progress (xine_stream_t *stream, int p) { } /* - * TODO: error messages - * returns 1 on error - */ -static int mmsh_parse_url(mmsh_t *this) { - int proto_len; - char *hostend; - char *forport; - char *_url; - char *_host; - - if ((proto_len = mmsh_valid_url(this->url, mmsh_url_s)) <= 0) { - lprintf ("invalid url\n"); - return 1; - } - - /* Create a local copy (alloca()'ed), avoid to corrupt the original URL */ - xine_strdupa(_url, &this->url[proto_len]); - - _host = _url; - - /* extract hostname */ - lprintf ("extracting host name \n"); - - hostend = strchr(_host, '/'); -/* - if ((!hostend) || (strlen(hostend) <= 1)) { - printf ("libmms: invalid url >%s<, failed to find hostend\n", url); - return NULL; - } -*/ - if (!hostend) { - lprintf ("no trailing /\n"); - - hostend = _host + strlen(_host); - } else { - *hostend++ = '\0'; - } - - /* Is port specified ? */ - forport = strchr(_host, ':'); - if(forport) { - *forport++ = '\0'; - this->port = atoi(forport); - } - - this->host = strdup(_host); - this->path = strdup(&this->url[proto_len] + (hostend - _url)); - this->file = strdup(strrchr (this->url, '/')); - return 0; -} - -/* * returns 1 on error */ static int mmsh_tcp_connect(mmsh_t *this) { int progress, res; + + if (!this->port) this->port = MMSH_PORT; + /* * try to connect */ @@ -638,7 +566,8 @@ static int mmsh_tcp_connect(mmsh_t *this) { this->s = _x_io_tcp_connect (this->stream, this->host, this->port); if (this->s == -1) { - printf ("libmmsh: failed to connect '%s'\n", this->host); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: failed to connect '%s'\n", this->host); return 1; } @@ -667,7 +596,8 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { int min_bw_left = 0; int stream_id; int bandwitdh_left; - char stream_selection[9 * 20]; /* 9 chars per stream */ + char stream_selection[10 * ASF_MAX_NUM_STREAMS]; /* 10 chars per stream */ + int offset; if (!url) return NULL; @@ -678,10 +608,6 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { this->stream = stream; this->url = strdup(url); - this->host = NULL; - this->port = MMSH_PORT; - this->path = NULL; - this->file = NULL; this->s = -1; this->asf_header_len = 0; this->asf_header_read = 0; @@ -694,14 +620,20 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { this->chunk_eos = 0; report_progress (stream, 0); - if (mmsh_parse_url(this)) { + + if (!_x_parse_url (this->url, &this->proto, &this->host, &this->port, + &this->user, &this->password, &this->uri)) { + xine_log (this->stream->xine, XINE_LOG_MSG, + "invalid url\n"); + goto fail; + } + + if (!mmsh_valid_proto(this->proto)) { + xine_log (this->stream->xine, XINE_LOG_MSG, + "unsupported protocol\n"); goto fail; } - lprintf ("url=%s\nlibmmsh: host=%s\nlibmmsh: " - "path=%s\nlibmmsh: file=%s\n", this->url, this->host, this->path, - this->file); - if (mmsh_tcp_connect(this)) { goto fail; } @@ -714,7 +646,8 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { /* first request */ lprintf("first http request\n"); - sprintf (this->str, mmsh_FirstRequest, this->path, this->host, 1); + snprintf (this->str, SCRATCH_SIZE, mmsh_FirstRequest, this->uri, + this->host, this->port, 1); if (!send_command (this, this->str)) goto fail; @@ -801,27 +734,34 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { /* The same selection is done with mmst */ /* 0 means selected */ /* 2 means disabled */ + offset = 0; for (i = 0; i < this->num_stream_ids; i++) { + int size; if ((this->stream_ids[i] == audio_stream) || (this->stream_ids[i] == video_stream)) { - sprintf(stream_selection + i * 9, "ffff:%d:0 ", this->stream_ids[i]); + size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset, + "ffff:%d:0 ", this->stream_ids[i]); } else { - lprintf("disabling stream %d\n", this->stream_ids[i]); - sprintf(stream_selection + i * 9, "ffff:%d:2 ", this->stream_ids[i]); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "disabling stream %d\n", this->stream_ids[i]); + size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset, + "ffff:%d:2 ", this->stream_ids[i]); } + if (size < 0) goto fail; + offset += size; } switch (this->stream_type) { case MMSH_SEEKABLE: - sprintf (this->str, mmsh_SeekableRequest, this->path, this->host, 0, 0, - 0, 2, 0, this->num_stream_ids, stream_selection); + snprintf (this->str, SCRATCH_SIZE, mmsh_SeekableRequest, this->uri, + this->host, this->port, 0, 0, 0, 2, 0, + this->num_stream_ids, stream_selection); break; case MMSH_LIVE: - sprintf (this->str, mmsh_LiveRequest, this->path, this->host, 2, - this->num_stream_ids, stream_selection); + snprintf (this->str, SCRATCH_SIZE, mmsh_LiveRequest, this->uri, + this->host, this->port, 2, + this->num_stream_ids, stream_selection); break; - default: - assert(1); } if (!send_command (this, this->str)) @@ -860,12 +800,16 @@ fail: close(this->s); if (this->url) free(this->url); + if (this->proto) + free(this->proto); if (this->host) free(this->host); - if (this->path) - free(this->path); - if (this->file) - free(this->file); + if (this->user) + free(this->user); + if (this->password) + free(this->password); + if (this->uri) + free(this->uri); free(this); @@ -886,11 +830,12 @@ static int get_media_packet (mmsh_t *this) { case CHUNK_TYPE_DATA: break; default: - printf("libmmsh: invalid chunk type\n"); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: invalid chunk type\n"); return 0; } - len = _x_read_abort (this->stream, this->s, this->buf, this->chunk_length); + len = _x_io_tcp_read (this->stream, this->s, this->buf, this->chunk_length); if (len == this->chunk_length) { /* explicit padding with 0 */ @@ -899,7 +844,8 @@ static int get_media_packet (mmsh_t *this) { this->buf_size = this->packet_length; return 1; } else { - printf("libmmsh: read error, %d != %d\n", len, this->chunk_length); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: read error, %d != %d\n", len, this->chunk_length); return 0; } } else { @@ -952,7 +898,8 @@ int mmsh_read (mmsh_t *this, char *data, int len) { this->buf_read = 0; if (!get_media_packet (this)) { - printf ("libmmsh: get_media_packet failed\n"); + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "libmmsh: get_media_packet failed\n"); return total; } bytes_left = this->buf_size; @@ -980,12 +927,20 @@ void mmsh_close (mmsh_t *this) { lprintf("mmsh_close\n"); - if (this->s !=-1) + if (this->s != -1) close(this->s); - if (this->host) - free (this->host); if (this->url) free (this->url); + if (this->proto) + free(this->proto); + if (this->host) + free(this->host); + if (this->user) + free(this->user); + if (this->password) + free(this->password); + if (this->uri) + free(this->uri); if (this) free (this); } |