diff options
-rw-r--r-- | misc/Makefile.am | 3 | ||||
-rw-r--r-- | misc/cdda_server.c | 201 | ||||
-rw-r--r-- | misc/libdvdcss-1.2.6-network.patch | 512 |
3 files changed, 701 insertions, 15 deletions
diff --git a/misc/Makefile.am b/misc/Makefile.am index 5c9bbe853..375491c12 100644 --- a/misc/Makefile.am +++ b/misc/Makefile.am @@ -29,3 +29,6 @@ maintainer-clean-generic: xine-fontconv: xine-fontconv.c $(CC) -W -Wall -g -o xine-fontconv xine-fontconv.c -lz `freetype-config --cflags` `freetype-config --libs` + +cdda_server: cdda_server.c + $(CC) -W -Wall -g -o cdda_server cdda_server.c -ldl diff --git a/misc/cdda_server.c b/misc/cdda_server.c index 3ce9c126f..96dc57842 100644 --- a/misc/cdda_server.c +++ b/misc/cdda_server.c @@ -1,11 +1,12 @@ -/* cdda_server.c +/* CDDA / DVD server * * This is a TCP server that can be used with xine's cdda input plugin to - * play audio cds over the network. + * play audio CDs over the network. It also supports playing DVDs with a + * patched version of libdvdcss. * * quick howto: * - compile it: - * gcc -o cdda_server cdda_server.c + * gcc -o cdda_server cdda_server.c -ldl * * - start the server: * ./cdda_server /dev/cdrom 3000 @@ -18,6 +19,8 @@ * * 6 May 2003 - Miguel Freitas * This feature was sponsored by 1Control + * + * note: see also libdvdcss-1.2.6-network.patch */ #include <stdio.h> @@ -37,19 +40,32 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> +#include <dlfcn.h> #define QLEN 5 /* maximum connection queue length */ #define _BUFSIZ 300 -static int msock; -static int cdda_fd; -static char *cdrom_device; - /* CD-relevant defines and data structures */ #define CD_SECONDS_PER_MINUTE 60 #define CD_FRAMES_PER_SECOND 75 #define CD_RAW_FRAME_SIZE 2352 #define CD_LEADOUT_TRACK 0xAA +#define DVD_BLOCK_SIZE 2048 + +/* functions from external DVD lib */ +typedef struct dvd_s *dvd_handle; +static dvd_handle (*dvd_open) (const char *); +static int (*dvd_close) (dvd_handle); +static int (*dvd_seek) (dvd_handle, int, int); +static int (*dvd_title) (dvd_handle, int); +static int (*dvd_read) (dvd_handle, void *, int, int); +static char * (*dvd_error) (dvd_handle); + +static int dvd_support; +static int msock; +static int cdda_fd; +static dvd_handle dvd; +static char *cdrom_device; #if defined (__linux__) @@ -307,15 +323,87 @@ int sock_string_write(int socket, char *msg, ...) { } +/** + * Setup dvd read functions + */ +int dvdinput_setup(void) +{ + void *dvdcss_library = NULL; + char **dvdcss_version = NULL; + + /* dlopening libdvdcss */ + +#ifndef _MSC_VER + dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY); +#else + dvdcss_library = dlopen("libdvdcss.dll", RTLD_LAZY); +#endif + + if(dvdcss_library != NULL) { +#if defined(__OpenBSD__) && !defined(__ELF__) +#define U_S "_" +#else +#define U_S +#endif + dvd_open = (dvd_handle (*)(const char*)) + dlsym(dvdcss_library, U_S "dvdcss_open"); + dvd_close = (int (*)(dvd_handle)) + dlsym(dvdcss_library, U_S "dvdcss_close"); + dvd_title = (int (*)(dvd_handle, int)) + dlsym(dvdcss_library, U_S "dvdcss_title"); + dvd_seek = (int (*)(dvd_handle, int, int)) + dlsym(dvdcss_library, U_S "dvdcss_seek"); + dvd_read = (int (*)(dvd_handle, void*, int, int)) + dlsym(dvdcss_library, U_S "dvdcss_read"); + dvd_error = (char* (*)(dvd_handle)) + dlsym(dvdcss_library, U_S "dvdcss_error"); + + dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2"); + + if(dlsym(dvdcss_library, U_S "dvdcss_crack")) { + fprintf(stderr, + "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n" + "libdvdread: You should get the latest version from " + "http://www.videolan.org/\n" ); + dlclose(dvdcss_library); + dvdcss_library = NULL; + } else if(!dvd_open || !dvd_close || !dvd_title || !dvd_seek + || !dvd_read || !dvd_error || !dvdcss_version) { + fprintf(stderr, "libdvdread: Missing symbols in libdvdcss.so.2, " + "this shouldn't happen !\n"); + dlclose(dvdcss_library); + } + } + + if(dvdcss_library != NULL) { + printf("Using libdvdcss version %s for DVD access\n", + *dvdcss_version); + + return 1; + + } else { + printf("No libdvdcss: DVD support unavailable.\n"); + + return 0; + } +} + + +#define CMD_CDDA_OPEN "cdda_open" #define CMD_CDDA_READ "cdda_read" #define CMD_CDDA_TOCHDR "cdda_tochdr" #define CMD_CDDA_TOCENTRY "cdda_tocentry" -#define CMD_CDDA_OPEN "cdda_open" +#define CMD_DVD_OPEN "dvd_open" +#define CMD_DVD_ERROR "dvd_error" +#define CMD_DVD_SEEK "dvd_seek" +#define CMD_DVD_READ "dvd_read" +#define CMD_DVD_TITLE "dvd_title" static int process_commands( int socket ) { char cmd[_BUFSIZ]; int start_frame, num_frames, i; + int blocks, flags; int ret, n; while( sock_has_data(socket) ) @@ -342,6 +430,25 @@ static int process_commands( int socket ) continue; } + if( dvd_support && !strncmp(cmd, CMD_DVD_OPEN, strlen(CMD_DVD_OPEN)) ) { + + if( dvd != NULL ) + dvd_close(dvd); + + dvd = dvd_open ( cdrom_device ); + if( !dvd ) + { + printf( "argh ! couldn't open DVD (%s)\n", cdrom_device ); + if( sock_string_write(socket,"-1 0") < 0 ) + return -1; + } + else { + if( sock_string_write(socket,"0 0") < 0 ) + return -1; + } + continue; + } + if( cdda_fd != -1 ) { if( !strncmp(cmd, CMD_CDDA_READ, strlen(CMD_CDDA_READ)) ) { @@ -395,14 +502,72 @@ static int process_commands( int socket ) continue; } - } else { + } else if ( dvd != NULL ) { + + if( !strncmp(cmd, CMD_DVD_ERROR, strlen(CMD_DVD_ERROR)) ) { + char *errmsg = dvd_error( dvd ); + + n = strlen(errmsg)+1; + if( sock_string_write(socket,"0 %d", n) < 0 ) + return -1; + + if( sock_data_write(socket,errmsg,n) < 0 ) + return -1; + + continue; + } + + if( !strncmp(cmd, CMD_DVD_SEEK, strlen(CMD_DVD_SEEK)) ) { + + sscanf(cmd,"%*s %d %d", &blocks, &flags); + ret = dvd_seek(dvd, blocks, flags); + + if( sock_string_write(socket,"%d 0", ret) < 0 ) + return -1; + + continue; + } + + if( !strncmp(cmd, CMD_DVD_READ, strlen(CMD_DVD_READ)) ) { + char *buf; - /* no device open. return error */ - if( sock_string_write(socket,"-1 0") < 0 ) - return -1; + sscanf(cmd,"%*s %d %d", &blocks, &flags); + + n = blocks * DVD_BLOCK_SIZE; + buf = malloc( n ); + if( !buf ) + { + printf("fatal error: could not allocate memory\n"); + exit(1); + } + ret = dvd_read(dvd, buf, blocks, flags); + if( sock_string_write(socket,"%d %d", ret, n) < 0 ) + return -1; + + if( sock_data_write(socket,buf,n) < 0 ) + return -1; + + free(buf); + continue; + } + + if( !strncmp(cmd, CMD_DVD_TITLE, strlen(CMD_DVD_TITLE)) ) { + + sscanf(cmd,"%*s %d", &blocks); + + ret = dvd_title(dvd, blocks); + + if( sock_string_write(socket,"%d 0", ret) < 0 ) + return -1; + + continue; + } } + /* no device open, or unknown command. return error */ + if( sock_string_write(socket,"-1 0") < 0 ) + return -1; } return 0; } @@ -457,6 +622,11 @@ static void server_loop() close(cdda_fd); cdda_fd = -1; } + + if( dvd != NULL ) { + dvd_close(dvd); + dvd = NULL; + } } } } @@ -466,11 +636,11 @@ static void server_loop() int main( int argc, char *argv[] ) { unsigned int port; - int ret; struct sockaddr_in servAddr; /* Print version number */ - printf( "CDDA TCP Server\n" ); + printf( "CDDA / DVD tcp server v0.1\n" ); + dvd_support = dvdinput_setup(); /* Check for 2 arguments */ if( argc != 3 ) @@ -482,6 +652,7 @@ int main( int argc, char *argv[] ) port = atoi( argv[2] ); cdda_fd = -1; + dvd = NULL; cdrom_device = argv[1]; msock = socket(PF_INET, SOCK_STREAM, 0); @@ -508,6 +679,6 @@ int main( int argc, char *argv[] ) close(msock); - return ret; + return 0; } diff --git a/misc/libdvdcss-1.2.6-network.patch b/misc/libdvdcss-1.2.6-network.patch new file mode 100644 index 000000000..8152039cc --- /dev/null +++ b/misc/libdvdcss-1.2.6-network.patch @@ -0,0 +1,512 @@ +diff -u --new-file libdvdcss-1.2.6/src/Makefile.am libdvdcss-1.2.6-network/src/Makefile.am +--- libdvdcss-1.2.6/src/Makefile.am 2003-03-10 12:57:09.000000000 -0500 ++++ libdvdcss-1.2.6-network/src/Makefile.am 2003-05-06 15:59:47.000000000 -0400 +@@ -4,6 +4,7 @@ + + libdvdcss_la_SOURCES = \ + libdvdcss.c libdvdcss.h \ ++ network.c network.h \ + device.c device.h \ + css.c css.h csstables.h \ + ioctl.c ioctl.h \ +diff -u --new-file libdvdcss-1.2.6/src/libdvdcss.c libdvdcss-1.2.6-network/src/libdvdcss.c +--- libdvdcss-1.2.6/src/libdvdcss.c 2003-02-01 16:24:49.000000000 -0500 ++++ libdvdcss-1.2.6-network/src/libdvdcss.c 2003-05-06 16:28:21.000000000 -0400 +@@ -125,6 +125,9 @@ + #include "libdvdcss.h" + #include "ioctl.h" + #include "device.h" ++#include "network.h" ++ ++#define MAX_ERR_MSG 300 + + /** + * \brief Symbol for version checks. +@@ -204,6 +207,10 @@ + } + } + ++ dvdcss->i_socket_fd = dvdcss_network_connect( dvdcss->psz_device ); ++ if( dvdcss->i_socket_fd != -1 ) ++ return dvdcss; ++ + /* + * Find method from DVDCSS_METHOD environment variable + */ +@@ -439,6 +446,16 @@ + */ + extern char * dvdcss_error ( dvdcss_t dvdcss ) + { ++ if( dvdcss->i_socket_fd != -1 ) ++ { ++ static char buf[MAX_ERR_MSG]; ++ ++ if( dvdcss_network_command( dvdcss->i_socket_fd, buf, "dvd_error") < 0 ) ++ return "(network error)"; ++ else ++ return buf; ++ } ++ + return dvdcss->psz_error; + } + +@@ -468,6 +485,12 @@ + */ + extern int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags ) + { ++ if( dvdcss->i_socket_fd != -1 ) ++ { ++ return dvdcss_network_command( dvdcss->i_socket_fd, NULL, ++ "dvd_seek %d %d", i_blocks, i_flags); ++ } ++ + /* title cracking method is too slow to be used at each seek */ + if( ( ( i_flags & DVDCSS_SEEK_MPEG ) + && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) +@@ -512,6 +535,12 @@ + { + int i_ret, i_index; + ++ if( dvdcss->i_socket_fd != -1 ) ++ { ++ return dvdcss_network_command( dvdcss->i_socket_fd, p_buffer, ++ "dvd_read %d %d", i_blocks, i_flags); ++ } ++ + i_ret = dvdcss->pf_read( dvdcss, p_buffer, i_blocks ); + + if( i_ret <= 0 +@@ -588,6 +617,12 @@ + void *iov_base; + size_t iov_len; + ++ if( dvdcss->i_socket_fd != -1 ) ++ { ++ printf("error: network dvdcss_readv not implemented\n"); ++ return -1; ++ } ++ + i_ret = dvdcss->pf_readv( dvdcss, _p_iovec, i_blocks ); + + if( i_ret <= 0 +@@ -642,20 +677,28 @@ + dvd_title_t *p_title; + int i_ret; + +- /* Free our list of keys */ +- p_title = dvdcss->p_titles; +- while( p_title ) ++ if( dvdcss->i_socket_fd != -1 ) + { +- dvd_title_t *p_tmptitle = p_title->p_next; +- free( p_title ); +- p_title = p_tmptitle; ++ close(dvdcss->i_socket_fd); + } ++ else ++ { + +- i_ret = _dvdcss_close( dvdcss ); ++ /* Free our list of keys */ ++ p_title = dvdcss->p_titles; ++ while( p_title ) ++ { ++ dvd_title_t *p_tmptitle = p_title->p_next; ++ free( p_title ); ++ p_title = p_tmptitle; ++ } + +- if( i_ret < 0 ) +- { +- return i_ret; ++ i_ret = _dvdcss_close( dvdcss ); ++ ++ if( i_ret < 0 ) ++ { ++ return i_ret; ++ } + } + + free( dvdcss->psz_device ); +@@ -670,6 +713,11 @@ + #undef dvdcss_title + extern int dvdcss_title ( dvdcss_t dvdcss, int i_block ) + { ++ if( dvdcss->i_socket_fd != -1 ) ++ { ++ return dvdcss_network_command( dvdcss->i_socket_fd, NULL, ++ "dvd_title %d", i_block); ++ } + return _dvdcss_title( dvdcss, i_block ); + } + +diff -u --new-file libdvdcss-1.2.6/src/libdvdcss.h libdvdcss-1.2.6-network/src/libdvdcss.h +--- libdvdcss-1.2.6/src/libdvdcss.h 2002-12-19 10:36:04.000000000 -0500 ++++ libdvdcss-1.2.6-network/src/libdvdcss.h 2003-04-29 05:31:04.000000000 -0400 +@@ -34,6 +34,7 @@ + int i_fd; + int i_read_fd; + int i_pos; ++ int i_socket_fd; + + /* File handling */ + int ( * pf_seek ) ( dvdcss_t, int ); +diff -u --new-file libdvdcss-1.2.6/src/network.c libdvdcss-1.2.6-network/src/network.c +--- libdvdcss-1.2.6/src/network.c 1969-12-31 19:00:00.000000000 -0500 ++++ libdvdcss-1.2.6-network/src/network.c 2003-05-06 16:28:04.000000000 -0400 +@@ -0,0 +1,331 @@ ++/*************************************************************************** ++ network.c - description ++ ------------------- ++ begin : Wed Mar 19 2003 ++ copyright : (C) 2003 by miguel ++ email : miguel@miguel ++ ***************************************************************************/ ++ ++/*************************************************************************** ++ * * ++ * This program 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. * ++ * * ++ ***************************************************************************/ ++ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdarg.h> ++#include <unistd.h> ++#include <string.h> ++#include <signal.h> ++#include <errno.h> ++#include <sys/time.h> ++#include <sys/socket.h> ++#include <netinet/in.h> ++#include <arpa/inet.h> ++#include <netdb.h> ++ ++ ++#define _BUFSIZ 300 ++ ++static int host_connect_attempt (struct in_addr ia, int port) ++{ ++ int s; ++ struct sockaddr_in sin; ++ ++ s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ++ ++ if (s==-1) { ++ printf("network: failed to open socket\n"); ++ return -1; ++ } ++ ++ 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) { ++ printf("network: cannot connect to host\n"); ++ close(s); ++ return -1; ++ } ++ ++ return s; ++} ++ ++static int host_connect (const char *host, int port) ++{ ++ struct hostent *h; ++ int i; ++ int s; ++ ++ h=gethostbyname(host); ++ if (h==NULL) { ++ printf("network: unable to resolve >%s<\n", host); ++ return -1; ++ } ++ ++ for(i=0; h->h_addr_list[i]; i++) { ++ struct in_addr ia; ++ memcpy(&ia, h->h_addr_list[i], 4); ++ s=host_connect_attempt(ia, port); ++ if(s != -1) { ++ signal( SIGPIPE, SIG_IGN ); ++ return s; ++ } ++ } ++ ++ printf("network: unable to connect to >%s<\n", host); ++ return -1; ++} ++ ++ ++static int parse_url (char *urlbuf, char** host, int *port) { ++ char *start = NULL; ++ char *portcolon = NULL; ++ ++ if (host != NULL) ++ *host = NULL; ++ ++ if (port != NULL) ++ *port = 0; ++ ++ start = strstr(urlbuf, "://"); ++ if (start != NULL) ++ start += 3; ++ else ++ start = urlbuf; ++ ++ while( *start == '/' ) ++ start++; ++ ++ portcolon = strchr(start, ':'); ++ ++ if (host != NULL) ++ *host = start; ++ ++ if (portcolon != NULL) ++ { ++ *portcolon = '\0'; ++ ++ if (port != NULL) ++ *port = atoi(portcolon + 1); ++ } ++ ++ return 0; ++} ++ ++static int sock_check_opened(int socket) { ++ fd_set readfds, writefds, exceptfds; ++ int retval; ++ struct timeval timeout; ++ ++ for(;;) { ++ FD_ZERO(&readfds); ++ FD_ZERO(&writefds); ++ FD_ZERO(&exceptfds); ++ FD_SET(socket, &exceptfds); ++ ++ timeout.tv_sec = 0; ++ timeout.tv_usec = 0; ++ ++ retval = select(socket + 1, &readfds, &writefds, &exceptfds, &timeout); ++ ++ if(retval == -1 && (errno != EAGAIN && errno != EINTR)) ++ return 0; ++ ++ if (retval != -1) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * read binary data from socket ++ */ ++static int sock_data_read (int socket, char *buf, int nlen) { ++ int n, num_bytes; ++ ++ if((socket < 0) || (buf == NULL)) ++ return -1; ++ ++ if(!sock_check_opened(socket)) ++ return -1; ++ ++ num_bytes = 0; ++ ++ while (num_bytes < nlen) { ++ ++ n = read (socket, &buf[num_bytes], nlen - num_bytes); ++ ++ /* read errors */ ++ if (n < 0) { ++ if(errno == EAGAIN) { ++ fd_set rset; ++ struct timeval timeout; ++ ++ FD_ZERO (&rset); ++ FD_SET (socket, &rset); ++ ++ timeout.tv_sec = 30; ++ timeout.tv_usec = 0; ++ ++ if (select (socket+1, &rset, NULL, NULL, &timeout) <= 0) { ++ printf ("network: timeout on read\n"); ++ return 0; ++ } ++ continue; ++ } ++ printf ("network: read error %d\n", errno); ++ return 0; ++ } ++ ++ num_bytes += n; ++ ++ /* end of stream */ ++ if (!n) break; ++ } ++ ++ return num_bytes; ++} ++ ++/* ++ * read a line (\n-terminated) from socket ++ */ ++static int sock_string_read(int socket, char *buf, int len) { ++ char *pbuf; ++ int r, rr; ++ void *nl; ++ ++ if((socket < 0) || (buf == NULL)) ++ return -1; ++ ++ if(!sock_check_opened(socket)) ++ return -1; ++ ++ if (--len < 1) ++ return(-1); ++ ++ pbuf = buf; ++ ++ do { ++ ++ if((r = recv(socket, pbuf, len, MSG_PEEK)) <= 0) ++ return -1; ++ ++ if((nl = memchr(pbuf, '\n', r)) != NULL) ++ r = ((char *) nl) - pbuf + 1; ++ ++ if((rr = read(socket, pbuf, r)) < 0) ++ return -1; ++ ++ pbuf += rr; ++ len -= rr; ++ ++ } while((nl == NULL) && len); ++ ++ if (pbuf > buf && *(pbuf-1) == '\n'){ ++ *(pbuf-1) = '\0'; ++ } ++ *pbuf = '\0'; ++ return (pbuf - buf); ++} ++ ++/* ++ * Write to socket. ++ */ ++static int sock_data_write(int socket, char *buf, int len) { ++ ssize_t size; ++ int wlen = 0; ++ ++ if((socket < 0) || (buf == NULL)) ++ return -1; ++ ++ if(!sock_check_opened(socket)) ++ return -1; ++ ++ while(len) { ++ size = write(socket, buf, len); ++ ++ if(size <= 0) ++ return -1; ++ ++ len -= size; ++ wlen += size; ++ buf += size; ++ } ++ ++ return wlen; ++} ++ ++int dvdcss_network_command( int socket, char *data_buf, char *msg, ...) ++{ ++ char buf[_BUFSIZ]; ++ va_list args; ++ int ret, n; ++ ++ va_start(args, msg); ++ vsnprintf(buf, _BUFSIZ, msg, args); ++ va_end(args); ++ ++ /* Each line sent is '\n' terminated */ ++ if((buf[strlen(buf)] == '\0') && (buf[strlen(buf) - 1] != '\n')) ++ sprintf(buf, "%s%c", buf, '\n'); ++ ++ if( sock_data_write(socket, buf, strlen(buf)) < (int)strlen(buf) ) ++ { ++ printf("network: error writing to socket\n"); ++ return -1; ++ } ++ ++ if( sock_string_read(socket, buf, _BUFSIZ) <= 0 ) ++ { ++ printf("network: error reading from socket\n"); ++ return -1; ++ } ++ ++ sscanf(buf, "%d %d", &ret, &n ); ++ ++ if( n ) { ++ if( !data_buf ) { ++ printf("network: protocol error, data returned but no buffer provided.\n"); ++ return -1; ++ } ++ if( sock_data_read(socket, data_buf, n) < n ) ++ return -1; ++ } ++ ++ return ret; ++} ++ ++int dvdcss_network_connect( char *url ) ++{ ++ char *host; ++ int port; ++ int fd; ++ ++ url = strdup(url); ++ parse_url(url, &host, &port); ++ ++ if( !host || !strlen(host) || !port ) ++ { ++ free(url); ++ return -1; ++ } ++ ++ fd = host_connect( host, port ); ++ free(url); ++ ++ if( fd != -1 ) { ++ if( dvdcss_network_command(fd, NULL, "dvd_open") < 0 ) { ++ close(fd); ++ return -1; ++ } ++ } ++ return fd; ++} +diff -u --new-file libdvdcss-1.2.6/src/network.h libdvdcss-1.2.6-network/src/network.h +--- libdvdcss-1.2.6/src/network.h 1969-12-31 19:00:00.000000000 -0500 ++++ libdvdcss-1.2.6-network/src/network.h 2003-05-06 16:26:15.000000000 -0400 +@@ -0,0 +1,20 @@ ++/*************************************************************************** ++ network.h - description ++ ------------------- ++ begin : Wed Mar 19 2003 ++ copyright : (C) 2003 by miguel ++ email : miguel@miguel ++ ***************************************************************************/ ++ ++/*************************************************************************** ++ * * ++ * This program 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. * ++ * * ++ ***************************************************************************/ ++ ++int dvdcss_network_connect( char *url ); ++ ++int dvdcss_network_command( int socket, char *data_buf, char *msg, ...); |