From 8cfa0e488ca8871bf9df4574b319c8cf59a17b90 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Sat, 3 Feb 2007 19:30:31 +0000 Subject: [PATCH] Merge of trunk into branch-1.4.x. git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/branches/branch-1.4.x@127 119443c7-1b9e-41f8-b6fc-b9c35fce742c --- ChangeLog | 105 +++++++++++-- Makefile.am | 39 +++-- THANKS | 4 +- build/libupnp.dsp | 145 +++++++++++++++++- configure.ac | 73 ++++++--- docs/dist/Makefile.am | 13 +- ixml/src/ixml.c | 12 +- ixml/src/ixmlparser.c | 59 +++++--- libupnp.spec | 13 +- threadutil/inc/ThreadPool.h | 74 +++++---- threadutil/src/ThreadPool.c | 32 ++++ upnp/Makefile.am | 3 +- upnp/inc/upnp.h | 16 +- upnp/sample/tvdevice/upnp_tv_device.c | 2 - upnp/src/api/upnpapi.c | 24 +-- upnp/src/api/upnptools.c | 19 ++- upnp/src/gena/gena_ctrlpt.c | 34 +++-- upnp/src/gena/gena_device.c | 31 ++-- upnp/src/genlib/miniserver/miniserver.c | 5 + upnp/src/genlib/net/http/httpreadwrite.c | 184 +++++++++++++---------- upnp/src/genlib/net/http/webserver.c | 158 +++++++++---------- upnp/src/inc/config.h | 11 ++ upnp/src/inc/httpreadwrite.h | 1 + upnp/src/inc/ssdplib.h | 2 +- upnp/src/inc/webserver.h | 4 +- upnp/src/soap/soap_ctrlpt.c | 120 +++++++++------ upnp/src/soap/soap_device.c | 68 +++++---- upnp/src/ssdp/ssdp_device.c | 52 ++++--- upnp/src/ssdp/ssdp_server.c | 14 +- 29 files changed, 874 insertions(+), 443 deletions(-) diff --git a/ChangeLog b/ChangeLog index d55331d..1307131 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,30 +2,100 @@ Version 1.4.2 ************************************************************************* +2007-02-02 Marcelo Jimenez + + * Bumped the program version to 1.4.2 in config.ac. + + * Now requires autoconf 2.60. + + * Fixed docdir use. + + * Does not install the documentation by default. + + * Use dist-bzip2 to create a .bz2 distribution file. + +2007-01-23 Marcelo Jimenez + + * SF Tracker [ 1634922 ] Support for large files (>= 2 GiB), part 2 + Submitted By: Jonathan - no_dice + Summary: This patch hopefully fixes the remaining types and related + code to enable files >= 2 GiB to be streamed. Jonathan claims to have + tested this with a patched version of ushare-0.9.8 and a D-Link DSM-520. + +2007-01-09 Marcelo Jimenez + + * SF Tracker [ 1628629 ] Multicast interface patch + Submitted By: Fredrik Svensson - svefredrik + This patch fixes two problems: + 1) Specify the IP address for the interface when we do + setsockopt IP_ADD_MEMBERSHIP. This makes it possible to run + when no default router has been configured. + 2) Explicitly set the multicast interface through setsockopt + IP_MULTICAST_IF. Avoids socket error -207 in some cases. + + * SF Tracker [ 1628590 ] XML parsing segfault patch + Submitted By: Fredrik Svensson - svefredrik + This patch fixes a segmentation fault problem that occurrs + when parsing XML code than some routers produce. + +2007-01-06 Marcelo Jimenez + + * SF Tracker [ 1628552 ] XML white space patch + Submitted By: Fredrik Svensson - svefredrik + + * SF Tracker [ 1628562 ] Maximum total jobs patch + Submitted By: Fredrik Svensson - svefredrik + Also, I incremented the libray versions and included some + comments in the file configure.ac so that we do not bump + the library version excessively, only the necessary numbers + on the next release. + + * SF Tracker [ 1628575 ] Linksys WRT54G patch + Submitted By: Fredrik Svensson - svefredrik + + * SF Tracker [ 1628636 ] SSDP packet copy patch + Submitted By: Fredrik Svensson - svefredrik + Changed NUM_COPY to 1 since, according to section 9.2 of the + HTTPU/MU spec, we should never send more than one copy of a + reply to an SSDP request. Ref. section 9.2 of + http://www.upnp.org/download/draft-goland-http-udp-04.txt + 2006-12-23 Marcelo Jimenez + * Thorough revision of every call of http_MakeMessage() due to a + bug introduced in rev.79 "largefile patch added". + http_MakeMessage() has a worst than brain damaged "printf" like + interface. In rev.79, the "N" format parameter must be an off_t. + Every call of this function with an "N" format parameter and an + int passed on the stack would fail terribly. + + * SF Bug tracker [ 1590469 ] + Typo in ixmlparser.c + Submitted By: Erik Johansson - erijo + + * SF Bug Tracker [ 1590466 ] Invalid xml output + Submitted By: Erik Johansson - erijo + + * SF Patch tracker [ 1581161 ] VStudio2005 patch + Submitted By: David Maass - darkservant + + * SF Patch tracker [ 1587272 ] const-ified ixml + Submitted By: Erik Johansson + * Finished const-ifications as suggested by Erik Johansson in SF Patch tracker [ 1587272 ]. -2006-12-23 Marcelo Jimenez +2006-07-05 Nektarios K. Papadopoulos + * [bug-id] 1580440 + [submitted-by] Erik Johansson - erijo + [patched-by] Erik Johansson - erijo + The SOAP HTTP message that's generated on upnp errors + is missing a \r\n\ between header and body. - * Erik Johansson's patch for const-ified ixml - SF Patch tracker [ 1587272 ]. +2006-07-07 Oxy -2006-12-23 Marcelo Jimenez + * support for large files (>2 GBytes) added - * David Maass's patch for VStudio2005 compilation failure. - SF Patch tracker [ 1581161 ]. - -2006-12-23 Marcelo Jimenez - - * Erik Johansson's patch for invalid xml output. - SF Bug Tracker [ 1590466 ]. - -2006-12-23 Marcelo Jimenez - - * Erik Johansson's patch for typo in ixmlparser.c. - SF Bug tracker [ 1590469 ]. ************************************************************************* Version 1.4.1 @@ -79,10 +149,13 @@ Version 1.4.0 2006-05-18 Oxy * DSM-320 patch added (fetched from project MediaTomb) + * httpGet additons atch added, Added proxy support by introducing UpnpOpenHttpGetProxy. UpnpOpenHttpGet now just calls UpnpOpenHttpGetProxy with the proxy url set to NULL. + * Bugfix for typo ("\0" / "0") in ixmlparser.c + * Bugfix for M-Search packet ************************************************************************* diff --git a/Makefile.am b/Makefile.am index 4db6fe6..87543cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,40 +5,39 @@ # Copyright (C) 2005 Rémi Turboult # -ACLOCAL_AMFLAGS = -I m4 +ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = --enable-debug --enable-samples -SUBDIRS = ixml threadutil upnp docs/dist +SUBDIRS = ixml threadutil upnp docs/dist -EXTRA_DIST = libupnp.pc.in LICENSE THANKS libupnp.spec \ - build/libupnp.bpf \ - build/libupnp.bpr \ - build/libupnp.dsp \ - build/libupnp.dsw \ - build/inc/autoconfig.h \ - build/inc/config.h \ - build/inc/upnpconfig.h +EXTRA_DIST = \ + libupnp.pc.in \ + LICENSE \ + THANKS \ + libupnp.spec \ + build/libupnp.bpf \ + build/libupnp.bpr \ + build/libupnp.dsp \ + build/libupnp.dsw \ + build/inc/autoconfig.h \ + build/inc/config.h \ + build/inc/upnpconfig.h # This variable must have 'exec' in its name, in order to be installed # by 'install-exec' target (instead of default 'install-data') -pkgconfigexecdir = $(libdir)/pkgconfig -pkgconfigexec_DATA = libupnp.pc +pkgconfigexecdir = $(libdir)/pkgconfig +pkgconfigexec_DATA = libupnp.pc $(pkgconfigexec_DATA): config.status -if WITH_DOCDIR - docdir = @DOCDIR@ - doc_DATA = LICENSE README NEWS TODO THANKS +if WITH_DOCUMENTATION + doc_DATA = LICENSE README NEWS TODO THANKS endif -CLEANFILES = IUpnpErrFile.txt IUpnpInfoFile.txt - - - - +CLEANFILES = IUpnpErrFile.txt IUpnpInfoFile.txt diff --git a/THANKS b/THANKS index b157ccb..9ced75c 100644 --- a/THANKS +++ b/THANKS @@ -12,15 +12,17 @@ exempt of errors. - Erik Johansson - Eric Tanguy - Erwan Velu +- Fredrik Svensson - Jiri Zouhar - John Dennis +- Jonathan (no_dice) - Leuk_He - Loigu - Marcelo Roberto Jimenez - Markus Strobl - Nektarios K. Papadopoulos - Oskar Liljeblad -- Oxy +- Michael (Oxy) - Paul Vixie - Siva Chandran diff --git a/build/libupnp.dsp b/build/libupnp.dsp index 7deea4a..2890869 100644 --- a/build/libupnp.dsp +++ b/build/libupnp.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBUPNP_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\pthreads\include" /I "..\ixml\src\inc" /I "..\ixml\inc" /I "..\threadutil\inc" /I "..\upnp\inc" /I "..\upnp\src\inc" /I ".\inc" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBUPNP_EXPORTS" /FR /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\pthreads\include" /I "..\ixml\src\inc" /I "..\ixml\inc" /I "..\threadutil\inc" /I "..\upnp\inc" /I "..\upnp\src\inc" /I ".\inc" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBUPNP_EXPORTS" /D "PTW32_STATIC_LIB" /D "UPNP_STATIC_LIB" /FR /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x407 /d "NDEBUG" @@ -53,7 +53,8 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\pthreads\lib\pthreadvc2.lib ws2_32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib pthreads\lib\pthreadvc2.lib ws2_32.lib /nologo /dll /machine:I386 +# SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "libupnp - Win32 Debug" @@ -274,6 +275,146 @@ SOURCE=..\upnp\src\win_dll.c # Begin Group "Header-Dateien" # PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\upnp\src\inc\client_table.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\config.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\gena.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\gena_ctrlpt.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\gena_device.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\global.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\gmtdate.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\http_client.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\httpparser.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\httpreadwrite.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\inet_pton.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\md5.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\membuffer.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\miniserver.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\netall.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\parsetools.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\server.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\service_table.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\soaplib.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\sock.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\ssdplib.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\statcodes.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\statuscodes.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\strintmap.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\sysdep.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\unixutil.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\upnp_timeout.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\upnpapi.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\upnpclosesocket.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\uri.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\urlconfig.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\util.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\utilall.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\uuid.h +# End Source File +# Begin Source File + +SOURCE=..\upnp\src\inc\webserver.h +# End Source File # End Group # Begin Group "Ressourcendateien" diff --git a/configure.ac b/configure.ac index dabef66..909d4d2 100644 --- a/configure.ac +++ b/configure.ac @@ -8,9 +8,9 @@ # (C) Copyright 2005-2006 Rémi Turboult # -AC_PREREQ(2.59) +AC_PREREQ(2.60) -AC_INIT([libupnp], [1.4.1], [virtual_worlds@gmx.de]) +AC_INIT([libupnp], [1.4.2], [mroberto@users.sourceforge.net]) # *Independently* of the above libupnp package version, the libtool version # of the 3 libraries need to be updated whenever there is a change released : # "current:revision:age" (this is NOT the same as the package version), where: @@ -19,16 +19,34 @@ AC_INIT([libupnp], [1.4.1], [virtual_worlds@gmx.de]) # - interfaces added: age++ # - interfaces removed: age=0 # *please update only once, before a formal release, not for each change* -AC_SUBST([LT_VERSION_IXML], [2:2:0]) -AC_SUBST([LT_VERSION_THREADUTIL], [2:2:0]) -AC_SUBST([LT_VERSION_UPNP], [2:2:0]) +# +# For release 1.4.1, we had: +#AC_SUBST([LT_VERSION_IXML], [2:2:0]) +#AC_SUBST([LT_VERSION_THREADUTIL], [2:2:0]) +#AC_SUBST([LT_VERSION_UPNP], [2:2:0]) +# +# "current:revision:age" +# +# - Code has changed in ixml +# revision: 2 -> 3 +# - Code has changed in threadutil +# revision: 2 -> 3 +# - Interface added in threadutil +# current: 2 -> 3 +# revisiion: 3 -> 0 +# age: 0 -> 1 +# - Code has changed in upnp (revision 2 -> 3) +# revision: 2 -> 3 +AC_SUBST([LT_VERSION_IXML], [2:3:0]) +AC_SUBST([LT_VERSION_THREADUTIL], [3:0:1]) +AC_SUBST([LT_VERSION_UPNP], [2:3:0]) AC_CONFIG_AUX_DIR(config.aux) AC_CONFIG_MACRO_DIR(m4) AC_CONFIG_SRCDIR(upnp/inc/upnp.h) -AM_INIT_AUTOMAKE([1.8 -Wall foreign subdir-objects]) +AM_INIT_AUTOMAKE([1.8 -Wall foreign subdir-objects dist-bzip2]) # # There are 3 configuration files : @@ -42,6 +60,7 @@ AM_INIT_AUTOMAKE([1.8 -Wall foreign subdir-objects]) # installed libraries. # AC_CONFIG_HEADERS([autoconfig.h upnp/inc/upnpconfig.h]) +#AC_SYS_LARGEFILE_SENSITIVE AC_REVISION([$Revision: 1.11 $]) @@ -106,19 +125,28 @@ RT_BOOL_ARG_ENABLE([samples], [yes], [compilation of upnp/sample/ code]) # doc installation -AC_MSG_CHECKING([documentation installation]) -AC_ARG_WITH([docdir], -AC_HELP_STRING([--with-docdir=DIR], - [where documentation is installed - @<:@[DATADIR/doc/]AC_PACKAGE_NAME[-]AC_PACKAGE_VERSION@:>@]) -AC_HELP_STRING([--without-docdir], - [do not install the documentation]), - [DOCDIR="$with_docdir"], - [DOCDIR="${datadir}/doc/${PACKAGE_NAME}-${PACKAGE_VERSION}"]) +# autoconf >= 2.60 already defines ${docdir}, but we will not use its +# default value, which is ${datarootdir}/doc/${PACKAGE_TARNAME}. +# That would give us ${datarootdir}/doc/libupnp, and we want the package +# version on that. +docdir="${datadir}/doc/${PACKAGE_NAME}-${PACKAGE_VERSION}" +AC_MSG_CHECKING([for documentation directory]) +AC_ARG_WITH([documentation], + AS_HELP_STRING([--with-documentation=directory_name], + [where documentation is installed + @<:@[DATADIR/doc/]AC_PACKAGE_NAME[-]AC_PACKAGE_VERSION@:>@]) +AS_HELP_STRING([--without-documentation], + [do not install the documentation]), + [], + [with_documentation=no]) -AM_CONDITIONAL(WITH_DOCDIR, test x"$with_docdir" != xno) -AC_SUBST(DOCDIR) -AC_MSG_RESULT($DOCDIR) +# If something has been entered after an equal sign, assume it is the directory +if test x"$with_documentation" != xyes -a x"$with_documentation" != xno; then + docdir="$with_documentation" +fi +AM_CONDITIONAL(WITH_DOCUMENTATION, test x"$with_documentation" != xno) +AC_SUBST(docdir) +AC_MSG_RESULT($docdir) # @@ -144,9 +172,12 @@ else fi AX_CFLAGS_WARN_ALL -# Arrange for large-file support (can be disabled with --disable-largefile). -# Define _FILE_OFFSET_BITS and _LARGE_FILES if necessary -AC_SYS_LARGEFILE +# +# Lot's of stuff to ensure large file support +# +AC_TYPE_OFF_T +AC_DEFINE(_LARGE_FILE_SOURCE, [], [Large files support]) +AC_DEFINE(_FILE_OFFSET_BITS, [64], [File Offset size]) # diff --git a/docs/dist/Makefile.am b/docs/dist/Makefile.am index a948ba2..729f244 100644 --- a/docs/dist/Makefile.am +++ b/docs/dist/Makefile.am @@ -1,4 +1,7 @@ -EXTRA_DIST = ./UPnP_Programming_Guide.pdf \ + + +EXTRA_DIST = \ + ./UPnP_Programming_Guide.pdf \ ./IXML_Programming_Guide.pdf \ ./html/upnp/icon1.gif \ ./html/upnp/icon2.gif \ @@ -251,9 +254,10 @@ EXTRA_DIST = ./UPnP_Programming_Guide.pdf \ ./html/ixml/ixmlCloneDOMString.html \ ./html/ixml/ixmlFreeDOMString.html -if WITH_DOCDIR - docsdir = @DOCDIR@ - nobase_docs_DATA = ./UPnP_Programming_Guide.pdf \ +if WITH_DOCUMENTATION + docsdir = @docdir@ + nobase_docs_DATA = \ + ./UPnP_Programming_Guide.pdf \ ./IXML_Programming_Guide.pdf \ ./html/upnp/icon1.gif \ ./html/upnp/icon2.gif \ @@ -506,3 +510,4 @@ if WITH_DOCDIR ./html/ixml/ixmlCloneDOMString.html \ ./html/ixml/ixmlFreeDOMString.html endif + diff --git a/ixml/src/ixml.c b/ixml/src/ixml.c index 8dd1f59..32388bb 100644 --- a/ixml/src/ixml.c +++ b/ixml/src/ixml.c @@ -146,7 +146,7 @@ ixmlPrintDomTreeRecursive( IN IXML_Node * nodeptr, if( ( child != NULL ) && ( ixmlNode_getNodeType( child ) == eELEMENT_NODE ) ) { - ixml_membuf_append_str( buf, ">\n" ); + ixml_membuf_append_str( buf, ">\r\n" ); } else { ixml_membuf_append_str( buf, ">" ); } @@ -164,7 +164,7 @@ ixmlPrintDomTreeRecursive( IN IXML_Node * nodeptr, && ixmlNode_getNodeType( sibling ) == eTEXT_NODE ) { ixml_membuf_append_str( buf, ">" ); } else { - ixml_membuf_append_str( buf, ">\n" ); + ixml_membuf_append_str( buf, ">\r\n" ); } ixmlPrintDomTreeRecursive( ixmlNode_getNextSibling ( nodeptr ), buf ); @@ -227,7 +227,7 @@ ixmlPrintDomTree( IN IXML_Node * nodeptr, child = ixmlNode_getFirstChild( nodeptr ); if( ( child != NULL ) && ( ixmlNode_getNodeType( child ) == eELEMENT_NODE ) ) { - ixml_membuf_append_str( buf, ">\n" ); + ixml_membuf_append_str( buf, ">\r\n" ); } else { ixml_membuf_append_str( buf, ">" ); } @@ -239,7 +239,7 @@ ixmlPrintDomTree( IN IXML_Node * nodeptr, // Done with children. Output the end tag. ixml_membuf_append_str( buf, "\n" ); + ixml_membuf_append_str( buf, ">\r\n" ); break; default: @@ -372,7 +372,7 @@ ixmlPrintDocument(IXML_Document *doc) } ixml_membuf_init( buf ); - ixml_membuf_append_str( buf, "\n" ); + ixml_membuf_append_str( buf, "\r\n" ); ixmlPrintDomTree( rootNode, buf ); return buf->buf; @@ -421,7 +421,7 @@ ixmlDocumenttoString(IXML_Document *doc) } ixml_membuf_init( buf ); - ixml_membuf_append_str( buf, "\n" ); + ixml_membuf_append_str( buf, "\r\n" ); ixmlDomTreetoString( rootNode, buf ); return buf->buf; diff --git a/ixml/src/ixmlparser.c b/ixml/src/ixmlparser.c index 717168d..b0c5fac 100644 --- a/ixml/src/ixmlparser.c +++ b/ixml/src/ixmlparser.c @@ -241,6 +241,21 @@ static BOOL Parser_hasDefaultNamespace( Parser * xmlParser, static int Parser_getChar( IN const char *src, INOUT int *cLen ); +/*==============================================================================* +* safe_strdup +* strdup that handles NULL input. +* +*===============================================================================*/ +static char * +safe_strdup(const char *s) +{ + assert(s != NULL); + if (s == NULL) { + return strdup(""); + } + return strdup(s); +} + /*==============================================================================* * Parser_isCharInTable * will determine whether character c is in the table of tbl @@ -525,14 +540,14 @@ Parser_pushElement( IN Parser * xmlParser, memset( pNewStackElement, 0, sizeof( IXML_ElementStack ) ); // the element member includes both prefix and name - pNewStackElement->element = strdup( newElement->nodeName ); + pNewStackElement->element = safe_strdup( newElement->nodeName ); if( pNewStackElement->element == NULL ) { free( pNewStackElement ); return IXML_INSUFFICIENT_MEMORY; } if( newElement->prefix != 0 ) { - pNewStackElement->prefix = strdup( newElement->prefix ); + pNewStackElement->prefix = safe_strdup( newElement->prefix ); if( pNewStackElement->prefix == NULL ) { Parser_freeElementStackItem( pNewStackElement ); free( pNewStackElement ); @@ -542,7 +557,7 @@ Parser_pushElement( IN Parser * xmlParser, if( newElement->namespaceURI != 0 ) { pNewStackElement->namespaceUri = - strdup( newElement->namespaceURI ); + safe_strdup( newElement->namespaceURI ); if( pNewStackElement->namespaceUri == NULL ) { Parser_freeElementStackItem( pNewStackElement ); free( pNewStackElement ); @@ -634,7 +649,7 @@ Parser_readFileOrBuffer( IN Parser * xmlParser, fclose( xmlFilePtr ); } } else { - xmlParser->dataBuffer = strdup( xmlFileName ); + xmlParser->dataBuffer = safe_strdup( xmlFileName ); if( xmlParser->dataBuffer == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1610,7 +1625,7 @@ Parser_addNamespace( IN Parser * xmlParser ) // it would be wrong that pNode->namespace != NULL. assert( pNode->namespaceURI == NULL ); - pNode->namespaceURI = strdup( pCur->namespaceUri ); + pNode->namespaceURI = safe_strdup( pCur->namespaceUri ); if( pNode->namespaceURI == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1626,7 +1641,7 @@ Parser_addNamespace( IN Parser * xmlParser ) namespaceUri = Parser_getNameSpace( xmlParser, pCur->prefix ); if( namespaceUri != NULL ) { - pNode->namespaceURI = strdup( namespaceUri ); + pNode->namespaceURI = safe_strdup( namespaceUri ); if( pNode->namespaceURI == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1661,7 +1676,7 @@ Parser_setNodePrefixAndLocalName( IN IXML_Node * node ) pStrPrefix = strchr( node->nodeName, ':' ); if( pStrPrefix == NULL ) { node->prefix = NULL; - node->localName = strdup( node->nodeName ); + node->localName = safe_strdup( node->nodeName ); if( node->localName == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1678,7 +1693,7 @@ Parser_setNodePrefixAndLocalName( IN IXML_Node * node ) memset( node->prefix, 0, nPrefix + 1 ); strncpy( node->prefix, node->nodeName, nPrefix ); - node->localName = strdup( pLocalName ); + node->localName = safe_strdup( pLocalName ); if( node->localName == NULL ) { free( node->prefix ); node->prefix = NULL; //no need to free really, main loop will frees it @@ -1718,7 +1733,7 @@ Parser_xmlNamespace( IN Parser * xmlParser, } ///here it goes to segfault on "" when not copying if(newNode->nodeValue){ - pCur->namespaceUri = strdup( newNode->nodeValue ); + pCur->namespaceUri = safe_strdup( newNode->nodeValue ); if( pCur->namespaceUri == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1738,7 +1753,7 @@ Parser_xmlNamespace( IN Parser * xmlParser, if( ( pCur->prefix != NULL ) && ( strcmp( pCur->prefix, newNode->localName ) == 0 ) ) { - pCur->namespaceUri = strdup( newNode->nodeValue ); + pCur->namespaceUri = safe_strdup( newNode->nodeValue ); if( pCur->namespaceUri == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1765,13 +1780,13 @@ Parser_xmlNamespace( IN Parser * xmlParser, } memset( pNewNs, 0, sizeof( IXML_NamespaceURI ) ); - pNewNs->prefix = strdup( newNode->localName ); + pNewNs->prefix = safe_strdup( newNode->localName ); if( pNewNs->prefix == NULL ) { free( pNewNs ); return IXML_INSUFFICIENT_MEMORY; } - pNewNs->nsURI = strdup( newNode->nodeValue ); + pNewNs->nsURI = safe_strdup( newNode->nodeValue ); if( pNewNs->nsURI == NULL ) { Parser_freeNsURI( pNewNs ); free( pNewNs ); @@ -1789,7 +1804,7 @@ Parser_xmlNamespace( IN Parser * xmlParser, free( pNs->nsURI ); } - pNs->nsURI = strdup( newNode->nodeValue ); + pNs->nsURI = safe_strdup( newNode->nodeValue ); if( pNs->nsURI == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1826,7 +1841,7 @@ Parser_processSTag( IN Parser * xmlParser, pCurToken = ( xmlParser->tokenBuf ).buf; if( pCurToken != NULL ) { - node->nodeName = strdup( pCurToken ); + node->nodeName = safe_strdup( pCurToken ); if( node->nodeName == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -1977,7 +1992,7 @@ Parser_processCDSect( IN char **pSrc, strncpy( node->nodeValue, pCDataStart, tokenLength ); node->nodeValue[tokenLength] = '\0'; - node->nodeName = strdup( CDATANODENAME ); + node->nodeName = safe_strdup( CDATANODENAME ); if( node->nodeName == NULL ) { // no need to free node->nodeValue at all, bacause node contents // will be freed by the main loop. @@ -2008,7 +2023,7 @@ Parser_setElementNamespace( IN IXML_Element * newElement, if( newElement->n.namespaceURI != NULL ) { return IXML_SYNTAX_ERR; } else { - ( newElement->n ).namespaceURI = strdup( nsURI ); + ( newElement->n ).namespaceURI = safe_strdup( nsURI ); if( ( newElement->n ).namespaceURI == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -2107,7 +2122,7 @@ Parser_processContent( IN Parser * xmlParser, pCurToken = ( xmlParser->tokenBuf ).buf; if( pCurToken != NULL ) { - node->nodeValue = strdup( pCurToken ); + node->nodeValue = safe_strdup( pCurToken ); if( node->nodeValue == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -2115,7 +2130,7 @@ Parser_processContent( IN Parser * xmlParser, return IXML_SYNTAX_ERR; } - node->nodeName = strdup( TEXTNODENAME ); + node->nodeName = safe_strdup( TEXTNODENAME ); if( node->nodeName == NULL ) { return IXML_SYNTAX_ERR; } @@ -2152,7 +2167,7 @@ Parser_processETag( IN Parser * xmlParser, if( pCurToken == NULL ) { return IXML_SYNTAX_ERR; } - node->nodeName = strdup( pCurToken ); + node->nodeName = safe_strdup( pCurToken ); if( node->nodeName == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -2320,7 +2335,7 @@ Parser_processAttribute( IN Parser * xmlParser, return IXML_SYNTAX_ERR; } // copy in the attribute name - node->nodeName = strdup( pCurToken ); + node->nodeName = safe_strdup( pCurToken ); if( node->nodeName == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -2373,7 +2388,7 @@ Parser_processAttribute( IN Parser * xmlParser, pCurToken = ( xmlParser->tokenBuf ).buf; if( pCurToken != NULL ) { // attribute has value, like a="c" - node->nodeValue = strdup( pCurToken ); + node->nodeValue = safe_strdup( pCurToken ); if( node->nodeValue == NULL ) { return IXML_INSUFFICIENT_MEMORY; } @@ -2456,7 +2471,7 @@ Parser_getNextNode( IN Parser * xmlParser, goto ErrorHandler; } - node->nodeName = strdup( lastElement ); + node->nodeName = safe_strdup( lastElement ); if( node->nodeName == NULL ) { return IXML_INSUFFICIENT_MEMORY; } diff --git a/libupnp.spec b/libupnp.spec index c087e43..5393123 100644 --- a/libupnp.spec +++ b/libupnp.spec @@ -1,15 +1,14 @@ -Version: 1.4.1 +Version: 1.4.2 Summary: Universal Plug and Play (UPnP) SDK Name: libupnp Release: 1%{?dist} License: BSD Group: System Environment/Libraries URL: http://www.libupnp.org/ -Source: http://puzzle.dl.sourceforge.net/sourceforge/pupnp/%{name}-%{version}.tar.gz +Source: http://puzzle.dl.sourceforge.net/sourceforge/pupnp/%{name}-%{version}.tar.bz2 Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -%define docdir %{_docdir}/%{name}-%{version}-%{release} -%define docdeveldir %{_docdir}/%{name}-devel-%{version}-%{release} +%define docdeveldir %{_docdir}/%{name}-devel-%{version} %description The Universal Plug and Play (UPnP) SDK for Linux provides @@ -29,7 +28,7 @@ the UPnP SDK libraries. %setup -q %build -%configure --with-docdir=%{docdir}/ +%configure --with-documentation make %{?_smp_mflags} %install @@ -78,6 +77,9 @@ make install DESTDIR=$RPM_BUILD_ROOT rm -rf %{buildroot} %changelog +* Fri Feb 02 2007 Eric Tanguy - 1.4.2-1 +- Update to version 1.4.2 + * Wed Jul 05 2006 Eric Tanguy - 1.4.1-1 - Update to version 1.4.1 @@ -117,3 +119,4 @@ rm -rf %{buildroot} * Thu Dec 22 2005 Eric Tanguy 1.2.1a-1 - Modify spec file from http://rpm.pbone.net/index.php3/stat/4/idpl/2378737/com/libupnp-1.2.1a_DSM320-3.i386.rpm.html + diff --git a/threadutil/inc/ThreadPool.h b/threadutil/inc/ThreadPool.h index c8ae478..166d6f1 100644 --- a/threadutil/inc/ThreadPool.h +++ b/threadutil/inc/ThreadPool.h @@ -61,32 +61,33 @@ typedef enum priority {LOW_PRIORITY, #define DEFAULT_JOBS_PER_THREAD 10 //default jobs per thread used by TPAttrInit #define DEFAULT_STARVATION_TIME 500 //default starvation time used by TPAttrInit #define DEFAULT_IDLE_TIME 10 * 1000 //default idle time used by TPAttrInit -#define DEFAULT_FREE_ROUTINE NULL //default free routine used TPJobInit +#define DEFAULT_FREE_ROUTINE NULL //default free routine used TPJobInit +#define DEFAULT_MAX_JOBS_TOTAL 100 //default max jobs used TPAttrInit #define STATS 1 //always include stats because code change is minimal -//Statistics +//Statistics #ifdef WIN32 // todo: check why STATSONLY fails during compilation #undef STATS #endif #ifdef STATS -#define STATSONLY(x) x + #define STATSONLY(x) x #else -#define STATSONLY(x) + #define STATSONLY(x) #endif #ifdef _DEBUG -#define DEBUG 1 + #define DEBUG 1 #endif //DEBUGGING #ifndef WIN32 #ifdef DEBUG - #define DBGONLY(x) x + #define DBGONLY(x) x #else - #define DBGONLY(x) + #define DBGONLY(x) #endif #endif @@ -97,7 +98,7 @@ typedef enum priority {LOW_PRIORITY, #include "ithread.h" #include #include -#define EXPORT +#define EXPORT typedef int PolicyType; #define DEFAULT_POLICY SCHED_OTHER #define DEFAULT_SCHED_PARAM 0 //default priority @@ -114,28 +115,30 @@ typedef void (*free_routine)(void *arg); * Name: ThreadPoolAttr * * Description: - * Attributes for thread pool. Used to set and change parameters of + * Attributes for thread pool. Used to set and change parameters of * thread pool *****************************************************************************/ typedef struct THREADPOOLATTR { - int minThreads; //minThreads, ThreadPool will always maintain at least - //this many threads - - int maxThreads; //maxThreads, ThreadPool will never have more than this - //number of threads - - int maxIdleTime; //maxIdleTime (in milliseconds) - // this is the maximum time a thread will remain idle - // before dying + int minThreads; // minThreads, ThreadPool will always maintain at least + // this many threads - int jobsPerThread; //jobs per thread to maintain - - int starvationTime; //the time a low priority or med priority - //job waits before getting bumped - //up a priority (in milliseconds) - - PolicyType schedPolicy; //scheduling policy to use + int maxThreads; // maxThreads, ThreadPool will never have more than this + // number of threads + + int maxIdleTime; // maxIdleTime (in milliseconds) + // this is the maximum time a thread will remain idle + // before dying + + int jobsPerThread; // jobs per thread to maintain + + int maxJobsTotal; // maximum number of jobs that can be queued totally. + + int starvationTime; // the time a low priority or med priority + // job waits before getting bumped + // up a priority (in milliseconds) + + PolicyType schedPolicy; // scheduling policy to use } ThreadPoolAttr; @@ -152,7 +155,7 @@ typedef struct THREADPOOLJOB free_routine free_func; //free function struct timeb requestTime; //time of request int priority; //priority of request - int jobId; //id + int jobId; //id } ThreadPoolJob; /**************************************************************************** @@ -168,20 +171,20 @@ typedef struct TPOOLSTATS { double totalTimeHQ; //total time spent by all jobs in high priority Q int totalJobsHQ; //total jobs in HQ run so far - double avgWaitHQ; //average wait in HQ + double avgWaitHQ; //average wait in HQ double totalTimeMQ; //total time spent by all jobs in med priority Q int totalJobsMQ; //total jobs in MQ run so far double avgWaitMQ; //average wait in MQ double totalTimeLQ; //total time spent by all jobs in low priority Q int totalJobsLQ; //total jobs in LQ run so far - double avgWaitLQ; //average wait in LQ + double avgWaitLQ; //average wait in LQ double totalWorkTime; //total time spent working for all threads double totalIdleTime; //total time spent idle for all threads int workerThreads; //number of current workerThreads int idleThreads; //number of current idle threads int persistentThreads; //number of persistent threads int totalThreads; //total number of current threads - int maxThreads; //max threads so far + int maxThreads; //max threads so far int currentJobsHQ; // current jobs in Q int currentJobsLQ; //current jobs in Q int currentJobsMQ; //current jobs in Q @@ -521,6 +524,19 @@ int TPAttrSetStarvationTime(ThreadPoolAttr *attr, int starvationTime); int TPAttrSetSchedPolicy(ThreadPoolAttr *attr, PolicyType schedPolicy); +/**************************************************************************** + * Function: TPAttrSetMaxJobsTotal + * + * Description: + * Sets the maximum number jobs that can be qeued totally. + * Parameters: + * attr - must be valid thread pool attributes. + * maxJobsTotal - maximum number of jobs + * Returns: + * Always returns 0. + *****************************************************************************/ +int TPAttrSetMaxJobsTotal(ThreadPoolAttr *attr, int maxJobsTotal); + /**************************************************************************** * Function: ThreadPoolGetStats * diff --git a/threadutil/src/ThreadPool.c b/threadutil/src/ThreadPool.c index e017464..16701e5 100644 --- a/threadutil/src/ThreadPool.c +++ b/threadutil/src/ThreadPool.c @@ -906,6 +906,7 @@ tp->stats.totalJobsLQ++; tp->stats.totalTimeLQ += diff; break; default: int rc = EOUTOFMEM; int tempId = -1; + int totalJobs; ThreadPoolJob *temp = NULL; @@ -922,6 +923,13 @@ tp->stats.totalJobsLQ++; tp->stats.totalTimeLQ += diff; break; default: || ( job->priority == MED_PRIORITY ) || ( job->priority == HIGH_PRIORITY ) ); + totalJobs = tp->highJobQ.size + tp->lowJobQ.size + tp->medJobQ.size; + if (totalJobs >= tp->attr.maxJobsTotal) { + fprintf(stderr, "total jobs = %d, too many jobs", totalJobs); + ithread_mutex_unlock( &tp->mutex ); + return rc; + } + if( jobId == NULL ) jobId = &tempId; @@ -1267,6 +1275,7 @@ tp->stats.totalJobsLQ++; tp->stats.totalTimeLQ += diff; break; default: attr->minThreads = DEFAULT_MIN_THREADS; attr->schedPolicy = DEFAULT_POLICY; attr->starvationTime = DEFAULT_STARVATION_TIME; + attr->maxJobsTotal = DEFAULT_MAX_JOBS_TOTAL; return 0; } @@ -1518,6 +1527,29 @@ tp->stats.totalJobsLQ++; tp->stats.totalTimeLQ += diff; break; default: stats->totalIdleTime );} #endif + /**************************************************************************** + * Function: TPAttrSetMaxJobsTotal + * + * Description: + * Sets the maximum number jobs that can be qeued totally. + * Parameters: + * attr - must be valid thread pool attributes. + * maxJobsTotal - maximum number of jobs + * Returns: + * Always returns 0. + *****************************************************************************/ + int TPAttrSetMaxJobsTotal( ThreadPoolAttr * attr, + int maxJobsTotal ) { + assert( attr != NULL ); + + if( attr == NULL ) { + return EINVAL; + } + + attr->maxJobsTotal = maxJobsTotal; + return 0; + } + /**************************************************************************** * Function: ThreadPoolGetStats * diff --git a/upnp/Makefile.am b/upnp/Makefile.am index d49f8cd..1a7cdc0 100644 --- a/upnp/Makefile.am +++ b/upnp/Makefile.am @@ -132,8 +132,7 @@ upnp_tv_ctrlpt_SOURCES = \ sample/tvctrlpt/upnp_tv_ctrlpt.h \ sample/tvctrlpt/linux/upnp_tv_ctrlpt_main.c -if WITH_DOCDIR - docdir = @DOCDIR@ +if WITH_DOCUMENTATION examplesdir = $(docdir)/examples examples_DATA = $(upnp_tv_ctrlpt_SOURCES) $(upnp_tv_device_SOURCES) endif diff --git a/upnp/inc/upnp.h b/upnp/inc/upnp.h index 933d656..f024202 100644 --- a/upnp/inc/upnp.h +++ b/upnp/inc/upnp.h @@ -36,6 +36,14 @@ //@{ +#if defined MYLIB_LARGEFILE_SENSITIVE && _FILE_OFFSET_BITS+0 != 64 + #if defined __GNUC__ + #warning libupnp requires largefile mode - use AC_SYS_LARGEFILE + #else + #error libupnp requires largefile mode - use AC_SYS_LARGEFILE + #endif +#endif + #include #ifdef __FreeBSD__ #include @@ -65,6 +73,7 @@ #define UpnpCloseSocket close #else #define UpnpCloseSocket closesocket + #define fseeko fseek #endif #define UPNP_SOCKETERROR -1 #define UPNP_INVALID_SOCKET -1 @@ -79,6 +88,8 @@ #include #endif +#include + #define NUM_HANDLE 200 #define LINE_SIZE 180 #define NAME_SIZE 256 @@ -875,7 +886,7 @@ struct File_Info /** The length of the file. A length less than 0 indicates the size * is unknown, and data will be sent until 0 bytes are returned from * a read call. */ - int file_length; + off_t file_length; /** The time at which the contents of the file was modified; * The time system is always local (not GMT). */ @@ -969,7 +980,7 @@ struct UpnpVirtualDirCallbacks int (*seek) ( IN UpnpWebFileHandle fileHnd, /** The handle of the file to move the file pointer. */ - IN long offset, /** The number of bytes to move in the + IN off_t offset, /** The number of bytes to move in the file. Positive values move foward and negative values move backward. Note that this must be positive if the @@ -2707,4 +2718,3 @@ EXPORT_SPEC void UpnpFree( //@} The API #endif - diff --git a/upnp/sample/tvdevice/upnp_tv_device.c b/upnp/sample/tvdevice/upnp_tv_device.c index cec09f1..ba29f69 100644 --- a/upnp/sample/tvdevice/upnp_tv_device.c +++ b/upnp/sample/tvdevice/upnp_tv_device.c @@ -1974,9 +1974,7 @@ TvDeviceStart( char *ip_address, ip_address = UpnpGetServerIpAddress( ); } - if( port == 0 ) { port = UpnpGetServerPort( ); - } SampleUtil_Print( "UPnP Initialized\n \t ipaddress= %s port = %d\n", ip_address, port ); diff --git a/upnp/src/api/upnpapi.c b/upnp/src/api/upnpapi.c index 60635cc..b83c7d6 100644 --- a/upnp/src/api/upnpapi.c +++ b/upnp/src/api/upnpapi.c @@ -244,6 +244,7 @@ int UpnpInit( IN const char *HostIP, TPAttrSetMinThreads( &attr, MIN_THREADS ); TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD ); TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME ); + TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL ); if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; @@ -955,7 +956,7 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, char aliasStr[LINE_SIZE]; char *temp_str = NULL; FILE *fp = NULL; - unsigned fileLen; + off_t fileLen; unsigned num_read; time_t last_modified; struct stat file_info; @@ -3339,19 +3340,20 @@ UpnpDownloadXmlDoc( const char *url, return ret_code; } - /* TODO: MoNKi: Do not check this?? Some routers (Linksys WRT54GS) sends - "CONTENT-TYPE: application/octet-stream". If the data sended is not - an xml file, ixmlParseBufferEx will fail and the function will return - UPNP_E_INVALID_DESC too.*/ - if( strncasecmp( content_type, "text/xml", strlen( "text/xml" ) ) ) { + DBGONLY( + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Not text/xml\n" ); + ) + // Linksys WRT54G router returns + // "CONTENT-TYPE: application/octet-stream". + // Let's be nice to Linksys and try to parse document anyway. + // If the data sended is not a xml file, ixmlParseBufferEx + // will fail and the function will return UPNP_E_INVALID_DESC too. +#if 0 free( xml_buf ); - DBGONLY( UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "Not text/xml\n" ); - ) - return UPNP_E_INVALID_DESC; + return UPNP_E_INVALID_DESC; +#endif } - // end of TODO Do not check this ret_code = ixmlParseBufferEx( xml_buf, xmlDoc ); free( xml_buf ); diff --git a/upnp/src/api/upnptools.c b/upnp/src/api/upnptools.c index a9edf69..46329f3 100644 --- a/upnp/src/api/upnptools.c +++ b/upnp/src/api/upnptools.c @@ -196,11 +196,12 @@ addToAction( IN int response, if( response ) { sprintf( ActBuff, - "", - ActionName, ServType, ActionName ); + "\r\n", + ActionName, ServType, ActionName ); } else { - sprintf( ActBuff, "", - ActionName, ServType, ActionName ); + sprintf( ActBuff, + "\r\n", + ActionName, ServType, ActionName ); } rc = ixmlParseBufferEx( ActBuff, ActionDoc ); @@ -274,11 +275,13 @@ makeAction( IN int response, } if( response ) { - sprintf( ActBuff, "", - ActionName, ServType, ActionName ); + sprintf( ActBuff, + "\r\n", + ActionName, ServType, ActionName ); } else { - sprintf( ActBuff, "", - ActionName, ServType, ActionName ); + sprintf( ActBuff, + "\r\n", + ActionName, ServType, ActionName ); } if( ixmlParseBufferEx( ActBuff, &ActionDoc ) != IXML_SUCCESS ) { diff --git a/upnp/src/gena/gena_ctrlpt.c b/upnp/src/gena/gena_ctrlpt.c index 81ed739..b949db3 100644 --- a/upnp/src/gena/gena_ctrlpt.c +++ b/upnp/src/gena/gena_ctrlpt.c @@ -219,10 +219,11 @@ gena_unsubscribe( IN char *url, // make request msg membuffer_init( &request ); request.size_inc = 30; - return_code = http_MakeMessage( &request, 1, 1, - "q" "ssc" "U" "c", - HTTPMETHOD_UNSUBSCRIBE, &dest_url, - "SID: ", sid ); + return_code = http_MakeMessage( + &request, 1, 1, + "q" "ssc" "Uc", + HTTPMETHOD_UNSUBSCRIBE, &dest_url, + "SID: ", sid ); //Not able to make the message so destroy the existing buffer if( return_code != 0 ) { @@ -305,20 +306,21 @@ gena_subscribe( IN char *url, request.size_inc = 30; if( renewal_sid ) { // renew subscription - return_code = http_MakeMessage( &request, 1, 1, - "q" "ssc" "ssc" "c", - HTTPMETHOD_SUBSCRIBE, &dest_url, - "SID: ", renewal_sid, - "TIMEOUT: Second-", timeout_str ); + return_code = http_MakeMessage( + &request, 1, 1, + "q" "ssc" "sscc", + HTTPMETHOD_SUBSCRIBE, &dest_url, + "SID: ", renewal_sid, + "TIMEOUT: Second-", timeout_str ); } else { // subscribe - return_code = http_MakeMessage( &request, 1, 1, - "q" "sssdsscc", - HTTPMETHOD_SUBSCRIBE, &dest_url, - "CALLBACK: \r\n" "NT: upnp:event\r\n" - "TIMEOUT: Second-", timeout_str ); + return_code = http_MakeMessage( + &request, 1, 1, + "q" "sssdsc" "sc" "sscc", + HTTPMETHOD_SUBSCRIBE, &dest_url, + "CALLBACK: ", + "NT: upnp:event", + "TIMEOUT: Second-", timeout_str ); } if( return_code != 0 ) { return return_code; diff --git a/upnp/src/gena/gena_device.c b/upnp/src/gena/gena_device.c index 8c74483..7aefcc6 100644 --- a/upnp/src/gena/gena_device.c +++ b/upnp/src/gena/gena_device.c @@ -219,9 +219,11 @@ notify_send_and_recv( IN uri_type * destination_url, } // make start line and HOST header membuffer_init( &start_msg ); - if( http_MakeMessage( &start_msg, 1, 1, - "q" "s", - HTTPMETHOD_NOTIFY, &url, mid_msg->buf ) != 0 ) { + if (http_MakeMessage( + &start_msg, 1, 1, + "q" "s", + HTTPMETHOD_NOTIFY, &url, + mid_msg->buf ) != 0 ) { membuffer_destroy( &start_msg ); sock_destroy( &info, SD_BOTH ); return UPNP_E_OUTOF_MEMORY; @@ -296,11 +298,12 @@ genaNotify( IN char *headers, // make 'end' msg (the part that won't vary with the destination) endmsg.size_inc = 30; - if( http_MakeMessage( &mid_msg, 1, 1, - "s" "ssc" "sdcc", - headers, - "SID: ", sub->sid, - "SEQ: ", sub->ToSendEventKey ) != 0 ) { + if( http_MakeMessage( + &mid_msg, 1, 1, + "s" "ssc" "sdcc", + headers, + "SID: ", sub->sid, + "SEQ: ", sub->ToSendEventKey ) != 0 ) { membuffer_destroy( &mid_msg ); return UPNP_E_OUTOF_MEMORY; } @@ -1165,10 +1168,14 @@ respond_ok( IN SOCKINFO * info, membuffer_init( &response ); response.size_inc = 30; - if( http_MakeMessage( &response, major, minor, - "R" "D" "S" "N" "Xc" "ssc" "sc" "c", - HTTP_OK, 0, X_USER_AGENT, - "SID: ", sub->sid, timeout_str ) != 0 ) { + if( http_MakeMessage( + &response, major, minor, + "R" "D" "S" "N" "Xc" "ssc" "scc", + HTTP_OK, + (off_t)0, + X_USER_AGENT, + "SID: ", sub->sid, + timeout_str ) != 0 ) { membuffer_destroy( &response ); error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return UPNP_E_OUTOF_MEMORY; diff --git a/upnp/src/genlib/miniserver/miniserver.c b/upnp/src/genlib/miniserver/miniserver.c index fbc0d6e..433a85b 100644 --- a/upnp/src/genlib/miniserver/miniserver.c +++ b/upnp/src/genlib/miniserver/miniserver.c @@ -651,6 +651,11 @@ get_miniserver_sockets( MiniServerSockArray * out, sizeof( struct sockaddr_in ) ); if( sockError == UPNP_SOCKETERROR ) { +#ifdef WIN32 + errCode = WSAGetLastError(); +#else + errCode = errno; +#endif if( errno == EADDRINUSE ) errCode = 1; } else diff --git a/upnp/src/genlib/net/http/httpreadwrite.c b/upnp/src/genlib/net/http/httpreadwrite.c index 5635b96..1c53b8f 100644 --- a/upnp/src/genlib/net/http/httpreadwrite.c +++ b/upnp/src/genlib/net/http/httpreadwrite.c @@ -306,8 +306,8 @@ http_SendMessage( IN SOCKINFO * info, char *filename = NULL; FILE *Fp; int num_read, - num_written, - amount_to_be_read = 0; + num_written; + off_t amount_to_be_read = 0; va_list argp; char *file_buf = NULL, *ChunkBuf = NULL; @@ -367,7 +367,7 @@ http_SendMessage( IN SOCKINFO * info, return UPNP_E_FILE_READ_ERROR; } } else if( Instr && Instr->IsRangeActive ) { - if( fseek( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) { + if( fseeko( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) { free( ChunkBuf ); return UPNP_E_FILE_READ_ERROR; } @@ -640,10 +640,11 @@ http_Download( IN const char *url_str, "HOSTNAME : %s Length : %d\n", hoststr, hostlen ); ) - ret_code = http_MakeMessage( &request, 1, 1, "QsbcDCUc", - HTTPMETHOD_GET, url.pathquery.buff, - url.pathquery.size, "HOST: ", hoststr, - hostlen ); + ret_code = http_MakeMessage( + &request, 1, 1, + "QsbcDCUc", + HTTPMETHOD_GET, url.pathquery.buff, url.pathquery.size, + "HOST: ", hoststr, hostlen ); if( ret_code != 0 ) { DBGONLY( UpnpPrintf ( UPNP_INFO, HTTP, __FILE__, __LINE__, @@ -796,21 +797,27 @@ MakePostMessage( const char *url_str, ) if( contentLength >= 0 ) { - ret_code = http_MakeMessage( request, 1, 1, "QsbcDCUTNc", - HTTPMETHOD_POST, url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType, - contentLength ); + ret_code = http_MakeMessage( + request, 1, 1, + "QsbcDCUTNc", + HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size, + "HOST: ", hoststr, hostlen, + contentType, + (off_t)contentLength ); } else if( contentLength == UPNP_USING_CHUNKED ) { - ret_code = http_MakeMessage( request, 1, 1, "QsbcDCUTKc", - HTTPMETHOD_POST, url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType ); + ret_code = http_MakeMessage( + request, 1, 1, + "QsbcDCUTKc", + HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size, + "HOST: ", hoststr, hostlen, + contentType ); } else if( contentLength == UPNP_UNTIL_CLOSE ) { - ret_code = http_MakeMessage( request, 1, 1, "QsbcDCUTc", - HTTPMETHOD_POST, url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType ); + ret_code = http_MakeMessage( + request, 1, 1, + "QsbcDCUTc", + HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size, + "HOST: ", hoststr, hostlen, + contentType ); } else { ret_code = UPNP_E_INVALID_PARAM; } @@ -1131,9 +1138,11 @@ MakeGetMessage( const char *url_str, querylen = url->pathquery.size; } - ret_code = http_MakeMessage( request, 1, 1, "QsbcDCUc", - HTTPMETHOD_GET, querystr, querylen, - "HOST: ", hoststr, hostlen ); + ret_code = http_MakeMessage( + request, 1, 1, + "QsbcDCUc", + HTTPMETHOD_GET, querystr, querylen, + "HOST: ", hoststr, hostlen ); if( ret_code != 0 ) { DBGONLY( UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, @@ -1729,8 +1738,11 @@ http_SendStatusResponse( IN SOCKINFO * info, membuffer_init( &membuf ); membuf.size_inc = 70; - ret = http_MakeMessage( &membuf, response_major, response_minor, "RSCB", http_status_code, // response start line - http_status_code ); // body + ret = http_MakeMessage( + &membuf, response_major, response_minor, + "RSCB", + http_status_code, // response start line + http_status_code ); // body if( ret == 0 ) { timeout = HTTP_DEFAULT_TIMEOUT; ret = http_SendMessage( info, &timeout, "b", @@ -1757,28 +1769,30 @@ http_SendStatusResponse( IN SOCKINFO * info, * specified in the input parameters. * * fmt types: -* 's': arg = const char* C_string +* 'B': arg = int status_code +* appends content-length, content-type and HTML body for given code * 'b': arg1 = const char* buf; arg2 = size_t buf_length * memory ptr -* 'c': (no args) appends CRLF "\r\n" -* 'd': arg = int number // appends decimal number -* 't': arg = time_t * gmt_time // appends time in RFC 1123 fmt -* 'D': (no args) appends HTTP DATE: header -* 'S': (no args) appends HTTP SERVER: header -* 'U': (no args) appends HTTP USER-AGENT: header * 'C': (no args) appends a HTTP CONNECTION: close header * depending on major,minor version +* 'c': (no args) appends CRLF "\r\n" +* 'D': (no args) appends HTTP DATE: header +* 'd': arg = int number // appends decimal number +* 'G': arg = range information // add range header +* 'h': arg = off_t number // appends off_t number +* 'K': (no args) // add chunky header * 'N': arg1 = int content_length // content-length header +* 'q': arg1 = http_method_t, arg2 = (uri_type *) // request start line and HOST header * 'Q': arg1 = http_method_t; arg2 = char* url; * arg3 = int url_length // start line of request * 'R': arg = int status_code // adds a response start line -* 'B': arg = int status_code -* appends content-length, content-type and HTML body for given code +* 'S': (no args) appends HTTP SERVER: header +* 's': arg = const char* C_string * 'T': arg = char * content_type; format e.g: "text/html"; * content-type header -* --- PATCH START - Sergey 'Jin' Bostandzhyan -* 'X': arg = const char useragent; "redsonic" HTTP X-User-Agent: useragent -* --- PATCH END --- +* 't': arg = time_t * gmt_time // appends time in RFC 1123 fmt +* 'U': (no args) appends HTTP USER-AGENT: header +* 'X': arg = const char useragent; "redsonic" HTTP X-User-Agent: useragent * * Return : int; * 0 - On Success @@ -1797,6 +1811,7 @@ http_MakeMessage( INOUT membuffer * buf, char c; char *s = NULL; int num; + off_t bignum; size_t length; time_t *loc_time; time_t curr_time; @@ -1884,6 +1899,16 @@ http_MakeMessage( INOUT membuffer * buf, } } + else if( c == 'h' ) // off_t + { + bignum = ( off_t )va_arg( argp, off_t ); + + sprintf( tempbuf, "%lld", bignum ); + if( membuffer_append( buf, tempbuf, strlen( tempbuf ) ) != 0 ) { + goto error_handler; + } + } + else if( c == 't' || c == 'D' ) // date { if( c == 'D' ) { @@ -1925,12 +1950,13 @@ http_MakeMessage( INOUT membuffer * buf, else if( c == 'N' ) { // content-length header - num = ( int )va_arg( argp, int ); + bignum = ( off_t )va_arg( argp, off_t ); - assert( num >= 0 ); - if( http_MakeMessage - ( buf, http_major_version, http_minor_version, "sdc", - "CONTENT-LENGTH: ", num ) != 0 ) { + assert( bignum >= 0 ); + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "shc", + "CONTENT-LENGTH: ", bignum ) != 0 ) { goto error_handler; } } @@ -1940,14 +1966,14 @@ http_MakeMessage( INOUT membuffer * buf, temp_str = ( c == 'S' ) ? "SERVER: " : "USER-AGENT: "; get_sdk_info( tempbuf ); - if( http_MakeMessage - ( buf, http_major_version, http_minor_version, "ss", - temp_str, tempbuf ) != 0 ) { + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "ss", + temp_str, tempbuf ) != 0 ) { goto error_handler; } } -/* --- PATCH START - Sergey 'Jin' Bostandzhyan */ else if( c == 'X' ) // C string { s = ( char * )va_arg( argp, char * ); @@ -1962,9 +1988,6 @@ http_MakeMessage( INOUT membuffer * buf, } } -/* --- PATCH END --- */ - - else if( c == 'R' ) { // response start line // e.g.: 'HTTP/1.1 200 OK' @@ -1979,9 +2002,11 @@ http_MakeMessage( INOUT membuffer * buf, // str status_msg = http_get_code_text( status_code ); - if( http_MakeMessage - ( buf, http_major_version, http_minor_version, "ssc", - tempbuf, status_msg ) != 0 ) { + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "ssc", + tempbuf, + status_msg ) != 0 ) { goto error_handler; } } @@ -1996,11 +2021,14 @@ http_MakeMessage( INOUT membuffer * buf, "

", status_code, http_get_code_text( status_code ), "

" ); - num = strlen( tempbuf ); + bignum = strlen( tempbuf ); - if( http_MakeMessage( buf, http_major_version, http_minor_version, "NTcs", num, // content-length - "text/html", // content-type - tempbuf ) != 0 ) // body + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "NTcs", + bignum, // content-length + "text/html", // content-type + tempbuf ) != 0 ) // body { goto error_handler; } @@ -2009,17 +2037,18 @@ http_MakeMessage( INOUT membuffer * buf, else if( c == 'Q' ) { // request start line // GET /foo/bar.html HTTP/1.1\r\n - // method = ( http_method_t ) va_arg( argp, http_method_t ); method_str = method_to_str( method ); url_str = ( const char * )va_arg( argp, const char * ); num = ( int )va_arg( argp, int ); // length of url_str - if( http_MakeMessage( buf, http_major_version, http_minor_version, "ssbsdsdc", method_str, // method - " ", url_str, num, // url - " HTTP/", http_major_version, ".", - http_minor_version ) != 0 ) { + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "ssbsdsdc", + method_str, // method + " ", url_str, num, // url + " HTTP/", http_major_version, ".", http_minor_version ) != 0 ) { goto error_handler; } } @@ -2036,10 +2065,11 @@ http_MakeMessage( INOUT membuffer * buf, goto error_handler; } - if( http_MakeMessage - ( buf, http_major_version, http_minor_version, "Q" "sbc", - method, url.pathquery.buff, url.pathquery.size, "HOST: ", - url.hostport.text.buff, url.hostport.text.size ) != 0 ) { + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "Q" "sbc", + method, url.pathquery.buff, url.pathquery.size, + "HOST: ", url.hostport.text.buff, url.hostport.text.size ) != 0 ) { goto error_handler; } } @@ -2048,9 +2078,10 @@ http_MakeMessage( INOUT membuffer * buf, // content type header temp_str = ( const char * )va_arg( argp, const char * ); // type/subtype format - if( http_MakeMessage - ( buf, http_major_version, http_minor_version, "ssc", - "CONTENT-TYPE: ", temp_str ) != 0 ) { + if (http_MakeMessage( + buf, http_major_version, http_minor_version, + "ssc", + "CONTENT-TYPE: ", temp_str ) != 0 ) { goto error_handler; } } @@ -2174,16 +2205,13 @@ MakeGetMessageEx( const char *url_str, hostlen ); ) - errCode = http_MakeMessage( request, - 1, - 1, - "QsbcGDCUc", - HTTPMETHOD_GET, - url->pathquery.buff, - url->pathquery.size, - "HOST: ", - hoststr, - hostlen, pRangeSpecifier ); + errCode = http_MakeMessage( + request, 1, 1, + "QsbcGDCUc", + HTTPMETHOD_GET, + url->pathquery.buff, url->pathquery.size, + "HOST: ", hoststr, hostlen, + pRangeSpecifier ); if( errCode != 0 ) { DBGONLY( UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, diff --git a/upnp/src/genlib/net/http/webserver.c b/upnp/src/genlib/net/http/webserver.c index 0155a94..2c93591 100644 --- a/upnp/src/genlib/net/http/webserver.c +++ b/upnp/src/genlib/net/http/webserver.c @@ -632,7 +632,7 @@ get_file_info( IN const char *filename, rc = get_content_type( filename, &info->content_type ); DBGONLY( UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, - "file info: %s, length: %d, last_mod=%s readable=%d\n", + "file info: %s, length: %lld, last_mod=%s readable=%d\n", filename, info->file_length, asctime( gmtime( &info->last_modified ) ), info->is_readable ); ) @@ -871,8 +871,8 @@ StrTok( char **Src, ************************************************************************/ int GetNextRange( char **SrcRangeStr, - int *FirstByte, - int *LastByte ) + off_t *FirstByte, + off_t *LastByte ) { char *Ptr, *Tok; @@ -936,11 +936,11 @@ GetNextRange( char **SrcRangeStr, ************************************************************************/ int CreateHTTPRangeResponseHeader( char *ByteRangeSpecifier, - long FileLength, + off_t FileLength, OUT struct SendInstruction *Instr ) { - int FirstByte, + off_t FirstByte, LastByte; char *RangeInput, *Ptr; @@ -984,26 +984,26 @@ CreateHTTPRangeResponseHeader( char *ByteRangeSpecifier, Instr->RangeOffset = FirstByte; Instr->ReadSendSize = LastByte - FirstByte + 1; - sprintf( Instr->RangeHeader, "CONTENT-RANGE: bytes %d-%d/%ld\r\n", FirstByte, LastByte, FileLength ); //Data between two range. + sprintf( Instr->RangeHeader, "CONTENT-RANGE: bytes %lld-%lld/%lld\r\n", FirstByte, LastByte, FileLength ); //Data between two range. } else if( FirstByte >= 0 && LastByte == -1 && FirstByte < FileLength ) { Instr->RangeOffset = FirstByte; Instr->ReadSendSize = FileLength - FirstByte; sprintf( Instr->RangeHeader, - "CONTENT-RANGE: bytes %d-%ld/%ld\r\n", FirstByte, + "CONTENT-RANGE: bytes %lld-%lld/%lld\r\n", FirstByte, FileLength - 1, FileLength ); } else if( FirstByte == -1 && LastByte > 0 ) { if( LastByte >= FileLength ) { Instr->RangeOffset = 0; Instr->ReadSendSize = FileLength; sprintf( Instr->RangeHeader, - "CONTENT-RANGE: bytes 0-%ld/%ld\r\n", + "CONTENT-RANGE: bytes 0-%lld/%lld\r\n", FileLength - 1, FileLength ); } else { Instr->RangeOffset = FileLength - LastByte; Instr->ReadSendSize = LastByte; sprintf( Instr->RangeHeader, - "CONTENT-RANGE: bytes %ld-%ld/%ld\r\n", + "CONTENT-RANGE: bytes %lld-%lld/%lld\r\n", FileLength - LastByte + 1, FileLength, FileLength ); } @@ -1042,7 +1042,7 @@ CreateHTTPRangeResponseHeader( char *ByteRangeSpecifier, int CheckOtherHTTPHeaders( IN http_message_t * Req, OUT struct SendInstruction *RespInstr, - int FileSize ) + off_t FileSize ) { http_header_t *header; ListNode *node; @@ -1184,7 +1184,6 @@ process_request( IN http_message_t * req, int code; int err_code; - //membuffer content_type; char *request_doc; struct File_Info finfo; xboolean using_alias; @@ -1208,7 +1207,6 @@ process_request( IN http_message_t * req, // init request_doc = NULL; finfo.content_type = NULL; - //membuffer_init( &content_type ); alias_grabbed = FALSE; err_code = HTTP_INTERNAL_SERVER_ERROR; // default error using_virtual_dir = FALSE; @@ -1362,7 +1360,7 @@ process_request( IN http_message_t * req, RespInstr->ReadSendSize = finfo.file_length; - //Check other header field. + // Check other header field. if( ( err_code = CheckOtherHTTPHeaders( req, RespInstr, finfo.file_length ) ) != HTTP_OK ) { @@ -1376,85 +1374,80 @@ process_request( IN http_message_t * req, } if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { - -/* - PATCH START - Sergey 'Jin' Bostandzhyan - * added X-User-Agent header - */ - - //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT - //Transfer-Encoding: chunked - // K means add chunky header ang G means range header. - if( http_MakeMessage( headers, resp_major, resp_minor, "RTGKDstcSXcCc", HTTP_PARTIAL_CONTENT, // status code - // RespInstr->ReadSendSize,// content length - finfo.content_type, - // content_type.buf, // content type - RespInstr, // Range - "LAST-MODIFIED: ", - &finfo.last_modified, - X_USER_AGENT) != 0 ) { + // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT + // Transfer-Encoding: chunked + if (http_MakeMessage( + headers, resp_major, resp_minor, + "R" "T" "GKD" "s" "tcS" "XcCc", + HTTP_PARTIAL_CONTENT, // status code + finfo.content_type, // content type + RespInstr, // range info + "LAST-MODIFIED: ", + &finfo.last_modified, + X_USER_AGENT) != 0 ) { goto error_handler; } } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) { - //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT - //Transfer-Encoding: chunked - // K means add chunky header ang G means range header. - if( http_MakeMessage( headers, resp_major, resp_minor, "RNTGDstcSXcCc", HTTP_PARTIAL_CONTENT, // status code - RespInstr->ReadSendSize, // content length - finfo.content_type, - //content_type.buf, // content type - RespInstr, //Range Info - "LAST-MODIFIED: ", - &finfo.last_modified, - X_USER_AGENT) != 0 ) { + // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT + // Transfer-Encoding: chunked + if (http_MakeMessage( + headers, resp_major, resp_minor, + "R" "N" "T" "GD" "s" "tcS" "XcCc", + HTTP_PARTIAL_CONTENT, // status code + RespInstr->ReadSendSize, // content length + finfo.content_type, // content type + RespInstr, // range info + "LAST-MODIFIED: ", + &finfo.last_modified, + X_USER_AGENT) != 0 ) { goto error_handler; } } else if( !RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { - - //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT - //Transfer-Encoding: chunked - // K means add chunky header ang G means range header. - if( http_MakeMessage( headers, resp_major, resp_minor, "RKTDstcSXcCc", HTTP_OK, // status code - //RespInstr->ReadSendSize,// content length - finfo.content_type, - // content_type.buf, // content type - "LAST-MODIFIED: ", - &finfo.last_modified, - X_USER_AGENT) != 0 ) { + // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT + // Transfer-Encoding: chunked + if (http_MakeMessage( + headers, resp_major, resp_minor, + "RK" "TD" "s" "tcS" "XcCc", + HTTP_OK, // status code + finfo.content_type, // content type + "LAST-MODIFIED: ", + &finfo.last_modified, + X_USER_AGENT) != 0 ) { goto error_handler; } - } else { - if( RespInstr->ReadSendSize >= 0 ) { - //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT - //Transfer-Encoding: chunked - // K means add chunky header ang G means range header. - if( http_MakeMessage( headers, resp_major, resp_minor, "RNTDstcSXcCc", HTTP_OK, // status code - RespInstr->ReadSendSize, // content length - finfo.content_type, - //content_type.buf, // content type - "LAST-MODIFIED: ", - &finfo.last_modified, - X_USER_AGENT) != 0 ) { + } else { // !RespInstr->IsRangeActive && !RespInstr->IsChunkActive + if (RespInstr->ReadSendSize >= 0) { + // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT + // Transfer-Encoding: chunked + if (http_MakeMessage( + headers, resp_major, resp_minor, + "R" "N" "TD" "s" "tcS" "XcCc", + HTTP_OK, // status code + RespInstr->ReadSendSize, // content length + finfo.content_type, // content type + "LAST-MODIFIED: ", + &finfo.last_modified, + X_USER_AGENT) != 0 ) { goto error_handler; } } else { - //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT - //Transfer-Encoding: chunked - // K means add chunky header ang G means range header. - if( http_MakeMessage( headers, resp_major, resp_minor, "RTDstcSXcCc", HTTP_OK, // status code - //RespInstr->ReadSendSize,// content length - finfo.content_type, - //content_type.buf, // content type - "LAST-MODIFIED: ", - &finfo.last_modified, - X_USER_AGENT) != 0 ) { + // Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT + // Transfer-Encoding: chunked + if (http_MakeMessage( + headers, resp_major, resp_minor, + "R" "TD" "s" "tcS" "XcCc", + HTTP_OK, // status code + finfo.content_type, // content type + "LAST-MODIFIED: ", + &finfo.last_modified, + X_USER_AGENT) != 0 ) { goto error_handler; } } } -/* -- PATCH END -- */ if( req->method == HTTPMETHOD_HEAD ) { *rtype = RESP_HEADERS; @@ -1468,8 +1461,8 @@ process_request( IN http_message_t * req, *rtype = RESP_FILEDOC; } - //simple get http 0.9 as specified in http 1.0 - //don't send headers + // simple get http 0.9 as specified in http 1.0 + // don't send headers if( req->method == HTTPMETHOD_SIMPLEGET ) { membuffer_destroy( headers ); } @@ -1479,7 +1472,6 @@ process_request( IN http_message_t * req, error_handler: free( request_doc ); ixmlFreeDOMString( finfo.content_type ); - // membuffer_destroy( &content_type ); if( err_code != UPNP_E_SUCCESS && alias_grabbed ) { alias_release( alias ); } @@ -1738,12 +1730,12 @@ web_server_callback( IN http_parser_t * parser, &RespInstr ); //Send response. -/* - PATCH START - Sergey 'Jin' Bostandzhyan - * added X-User-Agent header - */ - http_MakeMessage( &headers, 1, 1, "RTDSXcCc", ret, - "text/html", X_USER_AGENT ); -/* - PATCH END --- */ + http_MakeMessage( + &headers, 1, 1, + "RTDSXcCc", + ret, + "text/html", + X_USER_AGENT ); http_SendMessage( info, &timeout, "b", headers.buf, headers.length ); diff --git a/upnp/src/inc/config.h b/upnp/src/inc/config.h index 7d97239..279d2d3 100644 --- a/upnp/src/inc/config.h +++ b/upnp/src/inc/config.h @@ -95,6 +95,17 @@ #define MAX_THREADS 12 //@} +/** @name MAX_JOBS_TOTAL + * The {\tt MAX_JOBS_TOTAL} constant determines the maximum number of jobs + * that can be queued. If this limit is reached further jobs will be thrown + * to avoid memory exhaustion. The default value 100. + * (Added by Axis.) + */ + +//@{ +#define MAX_JOBS_TOTAL 100 +//@} + /** @name DEFAULT_SOAP_CONTENT_LENGTH * SOAP messages will read at most {\tt DEFAULT_SOAP_CONTENT_LENGTH} bytes. * This prevents devices that have a misbehaving web server to send diff --git a/upnp/src/inc/httpreadwrite.h b/upnp/src/inc/httpreadwrite.h index ee8b79c..1d47658 100644 --- a/upnp/src/inc/httpreadwrite.h +++ b/upnp/src/inc/httpreadwrite.h @@ -475,6 +475,7 @@ int http_SendStatusResponse( IN SOCKINFO *info, IN int http_status_code, * memory ptr * 'c': (no args) appends CRLF "\r\n" * 'd': arg = int number // appends decimal number +* 'h': arg = off_t number // appends off_t number * 't': arg = time_t * gmt_time // appends time in RFC 1123 fmt * 'D': (no args) appends HTTP DATE: header * 'S': (no args) appends HTTP SERVER: header diff --git a/upnp/src/inc/ssdplib.h b/upnp/src/inc/ssdplib.h index 9218c3b..7fa8e48 100644 --- a/upnp/src/inc/ssdplib.h +++ b/upnp/src/inc/ssdplib.h @@ -80,7 +80,7 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1, #define SSDP_IP "239.255.255.250" #define SSDP_PORT 1900 #define NUM_TRY 3 -#define NUM_COPY 2 +#define NUM_COPY 1 #define THREAD_LIMIT 50 #define COMMAND_LEN 300 diff --git a/upnp/src/inc/webserver.h b/upnp/src/inc/webserver.h index 0f9bc55..774c036 100644 --- a/upnp/src/inc/webserver.h +++ b/upnp/src/inc/webserver.h @@ -48,8 +48,8 @@ struct SendInstruction int IsRangeActive; int IsTrailers; char RangeHeader[200]; - long RangeOffset; - long ReadSendSize; // Read from local source and send on the network. + off_t RangeOffset; + off_t ReadSendSize; // Read from local source and send on the network. long RecvWriteSize; // Recv from the network and write into local file. //Later few more member could be added depending on the requirement. diff --git a/upnp/src/soap/soap_ctrlpt.c b/upnp/src/soap/soap_ctrlpt.c index 776e0db..156a143 100644 --- a/upnp/src/soap/soap_ctrlpt.c +++ b/upnp/src/soap/soap_ctrlpt.c @@ -602,12 +602,15 @@ SoapSendAction( IN char *action_url, char *upnp_error_str; xboolean got_response = FALSE; + off_t content_length; char *xml_start = -// "\n" required?? - "\n" + "\r\n" ""; - char *xml_end = "\n" "\n"; + char *xml_end = + "\r\n" + "\r\n\r\n"; int xml_start_len; int xml_end_len; int action_str_len; @@ -645,18 +648,23 @@ SoapSendAction( IN char *action_url, url.hostport.text.size, url.hostport.text.buff ); ) - xml_start_len = strlen( xml_start ); + xml_start_len = strlen( xml_start ); xml_end_len = strlen( xml_end ); action_str_len = strlen( action_str ); // make request msg request.size_inc = 50; - if( http_MakeMessage( &request, 1, 1, "q" "N" "s" "sssbs" "U" "c" "bbb", SOAPMETHOD_POST, &url, xml_start_len + action_str_len + xml_end_len, // content-length - ContentTypeHeader, - "SOAPACTION: \"", service_type, "#", name.buf, - name.length, "\"\r\n", xml_start, xml_start_len, - action_str, action_str_len, xml_end, - xml_end_len ) != 0 ) { + content_length = xml_start_len + action_str_len + xml_end_len; + if (http_MakeMessage( + &request, 1, 1, + "q" "N" "s" "sssbsc" "Uc" "b" "b" "b", + SOAPMETHOD_POST, &url, + content_length, + ContentTypeHeader, + "SOAPACTION: \"", service_type, "#", name.buf, name.length, "\"", + xml_start, xml_start_len, + action_str, action_str_len, + xml_end, xml_end_len ) != 0 ) { goto error_handler; } @@ -737,20 +745,26 @@ SoapSendActionEx( IN char *action_url, xboolean got_response = FALSE; char *xml_start = -// "\n" required?? - "\n"; - char *xml_body_start = ""; - char *xml_end = "\n" "\n"; + "\r\n"; + char *xml_header_start = + "\r\n"; + char *xml_header_end = + "\r\n"; + char *xml_body_start = + ""; + char *xml_end = + "\r\n" + "\r\n"; int xml_start_len; - int xml_end_len; - char *xml_header_start = "\n"; - char *xml_header_end = "\n"; int xml_header_start_len; - int xml_header_end_len; int xml_header_str_len; - int action_str_len; + int xml_header_end_len; int xml_body_start_len; + int action_str_len; + int xml_end_len; + off_t content_length; *response_node = NULL; // init @@ -790,7 +804,7 @@ SoapSendActionEx( IN char *action_url, url.hostport.text.size, url.hostport.text.buff ); ) - xml_start_len = strlen( xml_start ); + xml_start_len = strlen( xml_start ); xml_body_start_len = strlen( xml_body_start ); xml_end_len = strlen( xml_end ); action_str_len = strlen( action_str ); @@ -801,17 +815,24 @@ SoapSendActionEx( IN char *action_url, // make request msg request.size_inc = 50; - if( http_MakeMessage( &request, 1, 1, "q" "N" "s" "sssbs" "U" "c" "bbbbbbb", SOAPMETHOD_POST, &url, xml_start_len + xml_header_start_len + xml_header_str_len + xml_header_end_len + xml_body_start_len + action_str_len + xml_end_len, // content-length - ContentTypeHeader, - "SOAPACTION: \"", service_type, "#", name.buf, - name.length, "\"\r\n", - xml_start, xml_start_len, - xml_header_start, xml_header_start_len, - xml_header_str, xml_header_str_len, - xml_header_end, xml_header_end_len, - xml_body_start, xml_body_start_len, - action_str, action_str_len, - xml_end, xml_end_len ) != 0 ) { + content_length = + xml_start_len + + xml_header_start_len + xml_header_str_len + xml_header_end_len + + xml_body_start_len + action_str_len + xml_end_len; + if (http_MakeMessage( + &request, 1, 1, + "q" "N" "s" "sssbsc" "Uc" "bbbbbbb", + SOAPMETHOD_POST, &url, + content_length, + ContentTypeHeader, + "SOAPACTION: \"", service_type, "#", name.buf, name.length, "\"", + xml_start, xml_start_len, + xml_header_start, xml_header_start_len, + xml_header_str, xml_header_str_len, + xml_header_end, xml_header_end_len, + xml_body_start, xml_body_start_len, + action_str, action_str_len, + xml_end, xml_end_len ) != 0 ) { goto error_handler; } @@ -882,16 +903,20 @@ SoapGetServiceVarStatus( IN char *action_url, http_parser_t response; int upnp_error_code; + off_t content_length; char *xml_start = -// "\n" required?? - "\n" - "\n" - "\n" + "\r\n" + "\r\n" + "\r\n" ""; - char *xml_end = "\n" - "\n" "\n" "\n"; + char *xml_end = + "\r\n" + "\r\n" + "\r\n" + "\r\n"; *var_value = NULL; // return NULL in case of an error @@ -903,11 +928,16 @@ SoapGetServiceVarStatus( IN char *action_url, } // make headers request.size_inc = 50; - if( http_MakeMessage( &request, 1, 1, "Q" "sbc" "N" "s" "s" "U" "c" "sss", SOAPMETHOD_POST, path.buf, path.length, "HOST: ", host.buf, host.length, strlen( xml_start ) + strlen( var_name ) + strlen( xml_end ), // content-length - ContentTypeHeader, - "SOAPACTION: \"urn:schemas" - "-upnp-org:control-1-0#QueryStateVariable\"\r\n", - xml_start, var_name, xml_end ) != 0 ) { + content_length = strlen( xml_start ) + strlen( var_name ) + strlen( xml_end ); + if (http_MakeMessage( + &request, 1, 1, + "Q" "sbc" "N" "s" "s" "Ucc" "sss", + SOAPMETHOD_POST, path.buf, path.length, + "HOST: ", host.buf, host.length, + content_length, + ContentTypeHeader, + "SOAPACTION: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"", + xml_start, var_name, xml_end ) != 0 ) { return UPNP_E_OUTOF_MEMORY; } // send msg and get reply diff --git a/upnp/src/soap/soap_device.c b/upnp/src/soap/soap_device.c index da332a4..f8b6350 100644 --- a/upnp/src/soap/soap_device.c +++ b/upnp/src/soap/soap_device.c @@ -189,7 +189,7 @@ send_error_response( IN SOCKINFO * info, IN const char *err_msg, IN http_message_t * hmsg ) { - int content_length; + off_t content_length; int timeout_secs = SOAP_TIMEOUT; int major, minor; @@ -228,20 +228,19 @@ send_error_response( IN SOCKINFO * info, // make headers membuffer_init( &headers ); -/* -- PATCH START - Sergey 'Jin' Bostandzhyan */ - if( http_MakeMessage( &headers, major, minor, - "RNsDsSXc" "sssss", - 500, - content_length, - ContentTypeHeader, - "EXT:\r\n", - X_USER_AGENT, - start_body, err_code_str, mid_body, err_msg, - end_body ) != 0 ) { + if (http_MakeMessage( + &headers, major, minor, + "RNsDsSXcc" "sssss", + 500, + content_length, + ContentTypeHeader, + "EXT:\r\n", + X_USER_AGENT, + start_body, err_code_str, mid_body, err_msg, + end_body ) != 0 ) { membuffer_destroy( &headers ); return; // out of mem } -/*-- PATCH END - */ // send err msg http_SendMessage( info, &timeout_secs, "b", headers.buf, headers.length ); @@ -268,12 +267,11 @@ send_var_query_response( IN SOCKINFO * info, IN const char *var_value, IN http_message_t * hmsg ) { - int content_length; + off_t content_length; int timeout_secs = SOAP_TIMEOUT; - int major, - minor; + int major; + int minor; const char *start_body = -// "\n" required?? "\n" @@ -297,19 +295,18 @@ send_var_query_response( IN SOCKINFO * info, // make headers membuffer_init( &response ); -/* -- PATCH START - Sergey 'Jin' Bostandzhyan */ - if( http_MakeMessage( &response, major, minor, - "RNsDsSXcc" "sss", - HTTP_OK, - content_length, - ContentTypeHeader, - "EXT:\r\n", - X_USER_AGENT, - start_body, var_value, end_body ) != 0 ) { + if (http_MakeMessage( + &response, major, minor, + "RNsDsSXcc" "sss", + HTTP_OK, + content_length, + ContentTypeHeader, + "EXT:\r\n", + X_USER_AGENT, + start_body, var_value, end_body ) != 0 ) { membuffer_destroy( &response ); return; // out of mem } -/* -- PATCH END - */ // send msg http_SendMessage( info, &timeout_secs, "b", @@ -695,7 +692,7 @@ send_action_response( IN SOCKINFO * info, int major, minor; int err_code; - int content_length; + off_t content_length; int ret_code; int timeout_secs = SOAP_TIMEOUT; static char *start_body = @@ -717,17 +714,22 @@ send_action_response( IN SOCKINFO * info, goto error_handler; } - content_length = strlen( start_body ) + strlen( xml_response ) + + content_length = + strlen( start_body ) + + strlen( xml_response ) + strlen( end_body ); // make headers -/* -- PATCH START - Sergey 'Jin' Bostandzhyan */ - if( http_MakeMessage( &headers, major, minor, "RNsDsSXcc", HTTP_OK, // status code - content_length, ContentTypeHeader, "EXT:\r\n", X_USER_AGENT // EXT header - ) != 0 ) { + if (http_MakeMessage( + &headers, major, minor, + "RNsDsSXcc", + HTTP_OK, // status code + content_length, + ContentTypeHeader, + "EXT:\r\n", + X_USER_AGENT) != 0 ) { goto error_handler; } -/* -- PATCH END - */ // send whole msg ret_code = http_SendMessage( info, &timeout_secs, "bbbb", diff --git a/upnp/src/ssdp/ssdp_device.c b/upnp/src/ssdp/ssdp_device.c index 9f74838..967a7d1 100644 --- a/upnp/src/ssdp/ssdp_device.c +++ b/upnp/src/ssdp/ssdp_device.c @@ -234,7 +234,17 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, for( Index = 0; Index < NumPacket; Index++ ) { int rc; - + // The reason to keep this loop is purely historical/documentation, + // according to section 9.2 of HTTPU spec: + // + // "If a multicast resource would send a response(s) to any copy of the + // request, it SHOULD send its response(s) to each copy of the request + // it receives. It MUST NOT repeat its response(s) per copy of the + // reuqest." + // + // http://www.upnp.org/download/draft-goland-http-udp-04.txt + // + // So, NUM_COPY has been changed from 2 to 1. NumCopy = 0; while( NumCopy < NUM_COPY ) { DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, @@ -295,16 +305,16 @@ CreateServicePacket( IN int msg_type, *packet = NULL; if( msg_type == MSGTYPE_REPLY ) { -/* -- PATCH START - Sergey 'Jin' Bostandzhyan */ - ret_code = http_MakeMessage( &buf, 1, 1, - "R" "sdc" "D" "s" "ssc" "S" "Xc" "ssc" - "ssc" "c", HTTP_OK, - "CACHE-CONTROL: max-age=", duration, - "EXT:\r\n", "LOCATION: ", location, - X_USER_AGENT, - "ST: ", nt, "USN: ", usn ); -/* -- PATCH END - */ - + ret_code = http_MakeMessage( + &buf, 1, 1, + "R" "sdc" "D" "sc" "ssc" "S" "Xc" "ssc" "sscc", + HTTP_OK, + "CACHE-CONTROL: max-age=", duration, + "EXT:", + "LOCATION: ", location, + X_USER_AGENT, + "ST: ", nt, + "USN: ", usn); if( ret_code != 0 ) { return; } @@ -320,15 +330,17 @@ CreateServicePacket( IN int msg_type, // NOTE: The CACHE-CONTROL and LOCATION headers are not present in // a shutdown msg, but are present here for MS WinMe interop. -/* -- PATCH START - Sergey 'Jin' Bostandzhyan */ - ret_code = http_MakeMessage( &buf, 1, 1, - "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" - "S" "Xc" "ssc" "c", HTTPMETHOD_NOTIFY, "*", - 1, "HOST: ", SSDP_IP, ":", SSDP_PORT, - "CACHE-CONTROL: max-age=", duration, - "LOCATION: ", location, "NT: ", nt, - "NTS: ", nts, X_USER_AGENT, "USN: ", usn ); -/* -- PATCH END - */ + ret_code = http_MakeMessage( + &buf, 1, 1, + "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", + HTTPMETHOD_NOTIFY, "*", + 1, "HOST: ", SSDP_IP, ":", SSDP_PORT, + "CACHE-CONTROL: max-age=", duration, + "LOCATION: ", location, + "NT: ", nt, + "NTS: ", nts, + X_USER_AGENT, + "USN: ", usn ); if( ret_code != 0 ) { return; } diff --git a/upnp/src/ssdp/ssdp_server.c b/upnp/src/ssdp/ssdp_server.c index d154a5a..fd3ee8a 100644 --- a/upnp/src/ssdp/ssdp_server.c +++ b/upnp/src/ssdp/ssdp_server.c @@ -922,6 +922,7 @@ get_ssdp_sockets( MiniServerSockArray * out ) struct ip_mreq ssdpMcastAddr; struct sockaddr_in ssdpAddr; int option = 1; + struct in_addr addr; CLIENTONLY( if( ( ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == UPNP_INVALID_SOCKET ) { @@ -997,7 +998,7 @@ get_ssdp_sockets( MiniServerSockArray * out ) } memset( ( void * )&ssdpMcastAddr, 0, sizeof( struct ip_mreq ) ); - ssdpMcastAddr.imr_interface.s_addr = htonl( INADDR_ANY ); + ssdpMcastAddr.imr_interface.s_addr = inet_addr( LOCAL_HOST ); ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr( SSDP_IP ); if( setsockopt( ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( char * )&ssdpMcastAddr, @@ -1012,6 +1013,17 @@ get_ssdp_sockets( MiniServerSockArray * out ) CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) ); return UPNP_E_SOCKET_ERROR; } + + /* Set multicast interface. */ + memset( ( void * )&addr, 0, sizeof( struct in_addr )); + addr.s_addr = inet_addr(LOCAL_HOST); + if (setsockopt(ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&addr, sizeof addr) != 0) { + DBGONLY(UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, + "Couldn't set multicast interface.\n" )); + /* This is probably not a critical error, so let's continue. */ + } + // result is not checked becuase it will fail in WinMe and Win9x. setsockopt( ssdpSock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );