diff --git a/Makefile b/Makefile index 591c683..5c1320d 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ CFLAGS = -Wall -g -O3 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \ -I/usr/include/ffmpeg \ -I/usr/include/libavutil -I/usr/include/libavcodec -I/usr/include/libavformat \ -I/usr/include/ffmpeg/libavutil -I/usr/include/ffmpeg/libavcodec -I/usr/include/ffmpeg/libavformat +#STATIC_LINKING: CFLAGS += -DSTATIC #STATIC_LINKING: LDFLAGS = -static CC = gcc RM = rm -f diff --git a/genconfig.sh b/genconfig.sh index 55109c0..ea933fd 100755 --- a/genconfig.sh +++ b/genconfig.sh @@ -35,6 +35,7 @@ OS_VERSION=`uname -r` TIVO="/*#define TIVO_SUPPORT*/" NETGEAR="/*#define NETGEAR*/" READYNAS="/*#define READYNAS*/" +PNPX="#define PNPX 0" ${RM} ${CONFIGFILE} @@ -123,10 +124,12 @@ case $OS_NAME in OS_NAME=$(awk -F'!!|=' '{ print $1 }' /etc/raidiator_version) OS_VERSION=$(awk -F'!!|[=,.]' '{ print $3"."$4 }' /etc/raidiator_version) OS_URL="http://www.readynas.com/" + LOG_PATH="/var/log" DB_PATH="/var/cache/minidlna" TIVO="#define TIVO_SUPPORT" NETGEAR="#define NETGEAR" READYNAS="#define READYNAS" + PNPX="#define PNPX 5" # Debian GNU/Linux special case elif [ -f /etc/debian_version ]; then OS_NAME=Debian @@ -154,13 +157,13 @@ case $OS_NAME in ;; esac -echo "#define OS_NAME \"$OS_NAME\"" >> ${CONFIGFILE} -echo "#define OS_VERSION \"$OS_NAME/$OS_VERSION\"" >> ${CONFIGFILE} -echo "#define OS_URL \"${OS_URL}\"" >> ${CONFIGFILE} +echo "#define OS_NAME \"$OS_NAME\"" >> ${CONFIGFILE} +echo "#define OS_VERSION \"$OS_NAME/$OS_VERSION\"" >> ${CONFIGFILE} +echo "#define OS_URL \"${OS_URL}\"" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} echo "/* full path of the file database */" >> ${CONFIGFILE} -echo "#define DEFAULT_DB_PATH \"${DB_PATH}\"" >> ${CONFIGFILE} +echo "#define DEFAULT_DB_PATH \"${DB_PATH}\"" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} echo "/* full path of the log directory */" >> ${CONFIGFILE} @@ -203,6 +206,8 @@ echo "/* Enable ReadyNAS-specific tweaks. */" >> ${CONFIGFILE} echo "${READYNAS}" >> ${CONFIGFILE} echo "/* Compile in TiVo support. */" >> ${CONFIGFILE} echo "${TIVO}" >> ${CONFIGFILE} +echo "/* Enable PnPX support. */" >> ${CONFIGFILE} +echo "${PNPX}" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} echo "#endif" >> ${CONFIGFILE} diff --git a/minidlna.c b/minidlna.c index 19f0ca5..a98234e 100644 --- a/minidlna.c +++ b/minidlna.c @@ -206,11 +206,13 @@ getfriendlyname(char * buf, int len) { char * dot = NULL; char * hn = calloc(1, 256); + int off; + if( gethostname(hn, 256) == 0 ) { strncpy(buf, hn, len-1); buf[len] = '\0'; - dot = index(buf, '.'); + dot = strchr(buf, '.'); if( dot ) *dot = '\0'; } @@ -219,13 +221,70 @@ getfriendlyname(char * buf, int len) strcpy(buf, "Unknown"); } free(hn); - strcat(buf, ": "); - #ifdef READYNAS - strncat(buf, "ReadyNAS", len-strlen(buf)-1); - #else + + off = strlen(buf); + off += snprintf(buf+off, len-off, ": "); +#ifdef READYNAS + FILE * info; + char ibuf[64], *key, *val; + info = fopen("/proc/sys/dev/boot/info", "r"); + if( !info ) + { + snprintf(buf+off, len-off, "ReadyNAS"); + return; + } + while( (val = fgets(ibuf, 64, info)) != NULL ) + { + key = strsep(&val, ": \t"); + val = trim(val); + if( strcmp(key, "model") == 0 ) + { + key = strchr(val, ' '); + if( key ) + { + strncpy(modelnumber, key+1, MODELNUMBER_MAX_LEN); + modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; + *key = '\0'; + } + snprintf(modelname, MODELNAME_MAX_LEN, + "Windows Media Connect compatible (%s)", val); + } + else if( strcmp(key, "serial") == 0 ) + { + strncpy(serialnumber, val, SERIALNUMBER_MAX_LEN); + serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; + if( serialnumber[0] == '\0' ) + { + char mac_str[13]; + if( getsyshwaddr(mac_str, sizeof(mac_str)) == 0 ) + strcpy(serialnumber, mac_str); + else + strcpy(serialnumber, "0"); + } + break; + } + } + fclose(info); + if( strcmp(modelnumber, "NVX") == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0101", 17); + else if( strcmp(modelnumber, "Pro") == 0 || + strcmp(modelnumber, "Pro 6") == 0 || + strncmp(modelnumber, "Ultra 6", 7) == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0102", 17); + else if( strcmp(modelnumber, "Pro 2") == 0 || + strncmp(modelnumber, "Ultra 2", 7) == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0103", 17); + else if( strcmp(modelnumber, "Pro 4") == 0 || + strncmp(modelnumber, "Ultra 4", 7) == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0104", 17); + else if( strcmp(modelnumber+1, "100") == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0105", 17); + else if( strcmp(modelnumber+1, "200") == 0 ) + memcpy(pnpx_hwid+4, "01F2&DEV_0106", 17); +#else char * logname; logname = getenv("LOGNAME"); -#if 1 // Disable for static linking +#ifndef STATIC // Disable for static linking if( !logname ) { struct passwd * pwent; @@ -234,8 +293,8 @@ getfriendlyname(char * buf, int len) logname = pwent->pw_name; } #endif - strncat(buf, logname?logname:"Unknown", len-strlen(buf)-1); - #endif + snprintf(buf+off, len-off, "%s", logname?logname:"Unknown"); +#endif } int @@ -362,6 +421,10 @@ init(int argc, char * * argv) strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; break; + case UPNPMODEL_NAME: + strncpy(modelname, ary_options[i].value, MODELNAME_MAX_LEN); + modelname[MODELNAME_MAX_LEN-1] = '\0'; + break; case UPNPMODEL_NUMBER: strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; @@ -770,10 +833,10 @@ main(int argc, char * * argv) return 1; #ifdef READYNAS - DPRINTF(E_WARN, L_GENERAL, "Starting ReadyDLNA version " MINIDLNA_VERSION ".\n"); + DPRINTF(E_WARN, L_GENERAL, "Starting " SERVER_NAME " version " MINIDLNA_VERSION ".\n"); unlink("/ramfs/.upnp-av_scan"); #else - DPRINTF(E_WARN, L_GENERAL, "Starting MiniDLNA version " MINIDLNA_VERSION " [SQLite %s].\n", sqlite3_libversion()); + DPRINTF(E_WARN, L_GENERAL, "Starting " SERVER_NAME " version " MINIDLNA_VERSION " [SQLite %s].\n", sqlite3_libversion()); if( !sqlite3_threadsafe() ) { DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! " diff --git a/options.c b/options.c index ee420b6..cfca9ee 100644 --- a/options.c +++ b/options.c @@ -50,6 +50,7 @@ static const struct { { UPNPSYSTEM_UPTIME, "system_uptime" }, { UPNPUUID, "uuid"}, { UPNPSERIAL, "serial"}, + { UPNPMODEL_NAME, "model_name"}, { UPNPMODEL_NUMBER, "model_number"}, { UPNPFRIENDLYNAME, "friendly_name"}, { UPNPMEDIADIR, "media_dir"}, diff --git a/options.h b/options.h index ba58a77..88a517a 100644 --- a/options.h +++ b/options.h @@ -43,6 +43,7 @@ enum upnpconfigoptions { UPNPSYSTEM_UPTIME, /* system_uptime */ UPNPUUID, /* uuid */ UPNPSERIAL, /* serial */ + UPNPMODEL_NAME, /* model_name */ UPNPMODEL_NUMBER, /* model_number */ UPNPFRIENDLYNAME, /* how the system should show up to DLNA clients */ UPNPMEDIADIR, /* directory to search for UPnP-A/V content */ diff --git a/testupnpdescgen.c b/testupnpdescgen.c index b5b1da2..398d731 100644 --- a/testupnpdescgen.c +++ b/testupnpdescgen.c @@ -37,9 +37,13 @@ char uuidvalue[] = "uuid:12345678-0000-0000-0000-00000000abcd"; char friendly_name[] = "localhost: system_type"; char serialnumber[] = "12345678"; +char modelname[] = "MiniDLNA"; char modelnumber[] = "1"; char presentationurl[] = "http://192.168.0.1:8080/"; unsigned int updateID = 0; +#if PNPX +char pnpx_hwid[] = "VEN_01F2&DEV_0101&REV_01 VEN_0033&DEV_0001&REV_01"; +#endif int getifaddr(const char * ifname, char * buf, int len) { diff --git a/upnpdescgen.c b/upnpdescgen.c index 81ff38f..bc577a9 100644 --- a/upnpdescgen.c +++ b/upnpdescgen.c @@ -117,37 +117,46 @@ static const char xmlver[] = static const char root_service[] = "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\""; static const char root_device[] = - "root xmlns=\"urn:schemas-upnp-org:device-1-0\""; + "root xmlns=\"urn:schemas-upnp-org:device-1-0\"" +#if PNPX + " xmlns:pnpx=\"http://schemas.microsoft.com/windows/pnpx/2005/11\"" + " xmlns:df=\"http://schemas.microsoft.com/windows/2008/09/devicefoundation\"" +#endif + ; -/* root Description of the UPnP Device - * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf - * presentationURL is only "recommended" but the router doesn't appears - * in "Network connections" in Windows XP if it is not present. */ +/* root Description of the UPnP Device */ static const struct XMLElt rootDesc[] = { {root_device, INITHELPER(1,2)}, {"specVersion", INITHELPER(3,2)}, - {"device", INITHELPER(5,14)}, + {"device", INITHELPER(5,(14+PNPX))}, {"/major", "1"}, {"/minor", "0"}, {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"}, +#if PNPX == 5 + {"/pnpx:X_hardwareId", pnpx_hwid}, + {"/pnpx:X_compatibleId", "MS_DigitalMediaDeviceClass_DMS_V001"}, + {"/pnpx:X_deviceCategory", "MediaDevices"}, + {"/df:X_deviceCategory", "Multimedia.DMS"}, + {"/microsoft:magicPacketWakeSupported xmlns:microsoft=\"urn:schemas-microsoft-com:WMPNSS-1-0\"", "0"}, +#endif {"/friendlyName", friendly_name}, /* required */ {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */ {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */ {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */ - {"/modelName", ROOTDEV_MODELNAME}, /* required */ + {"/modelName", modelname}, /* required */ {"/modelNumber", modelnumber}, {"/modelURL", ROOTDEV_MODELURL}, {"/serialNumber", serialnumber}, {"/UDN", uuidvalue}, /* required */ {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"}, {"/presentationURL", presentationurl}, /* recommended */ - {"iconList", INITHELPER(19,4)}, - {"serviceList", INITHELPER(43,3)}, - {"icon", INITHELPER(23,5)}, - {"icon", INITHELPER(28,5)}, - {"icon", INITHELPER(33,5)}, - {"icon", INITHELPER(38,5)}, + {"iconList", INITHELPER((19+PNPX),4)}, + {"serviceList", INITHELPER((43+PNPX),3)}, + {"icon", INITHELPER((23+PNPX),5)}, + {"icon", INITHELPER((28+PNPX),5)}, + {"icon", INITHELPER((33+PNPX),5)}, + {"icon", INITHELPER((38+PNPX),5)}, {"/mimetype", "image/png"}, {"/width", "48"}, {"/height", "48"}, @@ -168,9 +177,9 @@ static const struct XMLElt rootDesc[] = {"/height", "120"}, {"/depth", "24"}, {"/url", "/icons/lrg.jpg"}, - {"service", INITHELPER(46,5)}, - {"service", INITHELPER(51,5)}, - {"service", INITHELPER(56,5)}, + {"service", INITHELPER((46+PNPX),5)}, + {"service", INITHELPER((51+PNPX),5)}, + {"service", INITHELPER((56+PNPX),5)}, {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"}, {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"}, {"/controlURL", CONTENTDIRECTORY_CONTROLURL}, diff --git a/upnpdescgen.h b/upnpdescgen.h index 336b876..edfd9f5 100644 --- a/upnpdescgen.h +++ b/upnpdescgen.h @@ -84,12 +84,6 @@ genConnectionManager(int * len); char * genX_MS_MediaReceiverRegistrar(int * len); -char * -genWANIPCn(int * len); - -char * -genWANCfg(int * len); - char * getVarsContentDirectory(int * len); diff --git a/upnpglobalvars.c b/upnpglobalvars.c index 835af59..8cc68d5 100644 --- a/upnpglobalvars.c +++ b/upnpglobalvars.c @@ -52,6 +52,7 @@ #include "config.h" #include "upnpglobalvars.h" +#include "upnpdescstrings.h" /* LAN address */ /*const char * listen_addr = 0;*/ @@ -65,9 +66,12 @@ int runtime_flags = INOTIFY_MASK; const char * pidfilename = "/var/run/minidlna.pid"; char uuidvalue[] = "uuid:00000000-0000-0000-0000-000000000000"; +char modelname[MODELNAME_MAX_LEN] = ROOTDEV_MODELNAME; +char modelnumber[MODELNUMBER_MAX_LEN] = MINIDLNA_VERSION; char serialnumber[SERIALNUMBER_MAX_LEN] = "00000000"; - -char modelnumber[MODELNUMBER_MAX_LEN] = "1"; +#if PNPX +char pnpx_hwid[] = "VEN_0000&DEV_0000&REV_01 VEN_0033&DEV_0001&REV_01"; +#endif /* presentation url : * http://nnn.nnn.nnn.nnn:ppppp/ => max 30 bytes including terminating 0 */ diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 5da1c63..8c0f531 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -57,7 +57,13 @@ #include -#define MINIDLNA_VERSION "1.0.18.2" +#define MINIDLNA_VERSION "1.0.19" + +#ifdef NETGEAR +# define SERVER_NAME "ReadyDLNA" +#else +# define SERVER_NAME "MiniDLNA" +#endif #define CLIENT_CACHE_SLOTS 20 #define USE_FORK 1 @@ -69,6 +75,10 @@ #define _(string) (string) #endif +#ifndef PNPX +#define PNPX 0 +#endif + #if 0 // Add these once the newer ffmpeg libs that can detect WMAPRO are more widely used "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=01;DLNA.ORG_CI=0," "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=01;DLNA.ORG_CI=0," @@ -137,15 +147,22 @@ extern const char * pidfilename; extern char uuidvalue[]; -#define SERIALNUMBER_MAX_LEN (10) -extern char serialnumber[]; +#define MODELNAME_MAX_LEN (64) +extern char modelname[]; -#define MODELNUMBER_MAX_LEN (48) +#define MODELNUMBER_MAX_LEN (16) extern char modelnumber[]; +#define SERIALNUMBER_MAX_LEN (16) +extern char serialnumber[]; + #define PRESENTATIONURL_MAX_LEN (64) extern char presentationurl[]; +#if PNPX +extern char pnpx_hwid[]; +#endif + /* lan addresses */ /* MAX_LAN_ADDR : maximum number of interfaces * to listen to SSDP traffic */