From 13b89f7e2994f9ee8a77c38538650a7e882d908b Mon Sep 17 00:00:00 2001 From: David Date: Tue, 26 Nov 2013 15:08:36 -0500 Subject: [PATCH] Check in 1.2.7 --- CMakeLists.txt | 4 +- configure | 20 +- configure.in | 4 +- dist/VERSION | 2 +- dist/admin/html.open/classes/ows/DTblDef.php | 2 +- dist/admin/html.open/classes/ws/DTblDef.php | 2 +- .../utility/build_php/buildconf.inc.php | 11 +- dist/conf/httpd_config.conf.in | 8 +- dist/conf/httpd_config.xml.in | 16 +- dist/conf/mime.properties | 5 + dist/docs/ServerStat_Help.html | 21 +- dist/docs/admin.html | 11 +- src/config.h.cmake | 2 +- src/edio/bufferedos.cpp | 2 +- src/edio/kqueuer.cpp | 4 +- src/extensions/fcgi/fcgiconnection.cpp | 2 +- src/extensions/localworker.cpp | 2 +- src/http/datetime.cpp | 2 +- src/http/hiostream.cpp | 14 ++ src/http/hiostream.h | 6 +- src/http/httpcgitool.cpp | 2 +- src/http/httpcontext.cpp | 2 +- src/http/httplistener.cpp | 6 +- src/http/httpreq.h | 4 +- src/http/ntwkiolink.cpp | 32 +++- src/http/ntwkiolink.h | 1 + src/http/staticfilehandler.cpp | 2 +- src/spdy/spdyconnection.cpp | 180 +++++++++++------- src/spdy/spdyconnection.h | 55 ++++-- src/spdy/spdyprotocol.cpp | 28 +-- src/spdy/spdyprotocol.h | 24 +-- src/spdy/spdystream.cpp | 127 +++++++----- src/spdy/spdystream.h | 10 +- src/ssi/ssiruntime.h | 6 +- src/sslpp/sslconnection.cpp | 11 +- src/sslpp/sslcontext.cpp | 6 +- src/util/ghash.cpp | 2 +- src/util/sysinfo/linux_nicdetect.cpp | 10 +- v1.2 | 1 + 39 files changed, 406 insertions(+), 243 deletions(-) create mode 100644 v1.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index e3060e81b..7c6877e25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ Project(openlitespeed) INCLUDE( ${PROJECT_SOURCE_DIR}/CMakeModules/common.cmake) set(openlitespeed_MAJOR_VERSION 1) -set(openlitespeed_MINOR_VERSION 1) -set(openlitespeed_PATCH_VERSION 0) +set(openlitespeed_MINOR_VERSION 2) +set(openlitespeed_PATCH_VERSION 7) set(openlitespeed_VERSION ${FOOBAR_MAJOR_VERSION}.${FOOBAR_MINOR_VERSION}.${FOOBAR_PATCH_VERSION}) diff --git a/configure b/configure index 457ec7c3e..d3ebf0a0a 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for openlitespeed 1.2.6. +# Generated by GNU Autoconf 2.69 for openlitespeed 1.2.7. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='openlitespeed' PACKAGE_TARNAME='openlitespeed' -PACKAGE_VERSION='1.2.6' -PACKAGE_STRING='openlitespeed 1.2.6' +PACKAGE_VERSION='1.2.7' +PACKAGE_STRING='openlitespeed 1.2.7' PACKAGE_BUGREPORT='info@litespeedtech.com' PACKAGE_URL='http://www.litespeedtech.com/' @@ -1307,7 +1307,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures openlitespeed 1.2.6 to adapt to many kinds of systems. +\`configure' configures openlitespeed 1.2.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1373,7 +1373,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of openlitespeed 1.2.6:";; + short | recursive ) echo "Configuration of openlitespeed 1.2.7:";; esac cat <<\_ACEOF @@ -1495,7 +1495,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -openlitespeed configure 1.2.6 +openlitespeed configure 1.2.7 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2132,7 +2132,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by openlitespeed $as_me 1.2.6, which was +It was created by openlitespeed $as_me 1.2.7, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2959,7 +2959,7 @@ fi # Define the identity of the package. PACKAGE='openlitespeed' - VERSION='1.2.6' + VERSION='1.2.7' # Some tools Automake needs. @@ -7635,7 +7635,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by openlitespeed $as_me 1.2.6, which was +This file was extended by openlitespeed $as_me 1.2.7, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7702,7 +7702,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -openlitespeed config.status 1.2.6 +openlitespeed config.status 1.2.7 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index 3b66060a4..3de358954 100644 --- a/configure.in +++ b/configure.in @@ -5,8 +5,8 @@ m4_include(ax_lib_expat.m4) dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([openlitespeed],[1.2.6],[info@litespeedtech.com],[openlitespeed],[http://www.litespeedtech.com/]) -AM_INIT_AUTOMAKE([1.2.6 foreign no-define ]) +AC_INIT([openlitespeed],[1.2.7],[info@litespeedtech.com],[openlitespeed],[http://www.litespeedtech.com/]) +AM_INIT_AUTOMAKE([1.2.7 foreign no-define ]) AM_CONFIG_HEADER(src/config.h:src/config.h.in) diff --git a/dist/VERSION b/dist/VERSION index 3c43790f5..c04c650a7 100644 --- a/dist/VERSION +++ b/dist/VERSION @@ -1 +1 @@ -1.2.6 +1.2.7 diff --git a/dist/admin/html.open/classes/ows/DTblDef.php b/dist/admin/html.open/classes/ows/DTblDef.php index 2e66bfbd4..f196d7ee2 100644 --- a/dist/admin/html.open/classes/ows/DTblDef.php +++ b/dist/admin/html.open/classes/ows/DTblDef.php @@ -543,7 +543,7 @@ protected function add_SERV_TUNING_GZIP($id) new DAttr('gzipCompressLevel', 'uint', 'Compression Level (Dynamic Content)', 'text', true, 1, 9), new DAttr('compressibleTypes', 'parse', 'Compressible Types', 'textarea', true, $parseFormat, $parseHelp, 'rows="5" cols="50"', 1), new DAttr('gzipAutoUpdateStatic', 'bool', 'Auto Update Static File', 'radio'), - new DAttr('gzipCacheDir', 'cust', 'Static GZIP Cache Directory', 'text', false, 1, 'rw', $this->_options['text_size']), + new DAttr('gzipCacheDir', 'cust', 'Static GZIP Cache Directory', 'text', true, 1, 'rw', $this->_options['text_size']), new DAttr('gzipStaticCompressLevel', 'uint', 'Compression Level (Static File)', 'text', true, 1, 9), new DAttr('gzipMaxFileSize', 'uint', 'Max Static File Size (bytes)', 'text', true, '1K'), diff --git a/dist/admin/html.open/classes/ws/DTblDef.php b/dist/admin/html.open/classes/ws/DTblDef.php index 89d8efac0..7a1c11275 100644 --- a/dist/admin/html.open/classes/ws/DTblDef.php +++ b/dist/admin/html.open/classes/ws/DTblDef.php @@ -631,7 +631,7 @@ protected function add_SERV_TUNING_GZIP($id) new DAttr('gzipCompressLevel', 'uint', 'Compression Level (Dynamic Content)', 'text', true, 1, 9), new DAttr('compressibleTypes', 'parse', 'Compressible Types', 'textarea', true, $parseFormat, $parseHelp, 'rows="5" cols="50"', 1), new DAttr('gzipAutoUpdateStatic', 'bool', 'Auto Update Static File', 'radio'), - new DAttr('gzipCacheDir', 'cust', 'Static GZIP Cache Directory', 'text', false, 1, 'rw', $this->_options['text_size']), + new DAttr('gzipCacheDir', 'cust', 'Static GZIP Cache Directory', 'text', true, 1, 'rw', $this->_options['text_size']), new DAttr('gzipStaticCompressLevel', 'uint', 'Compression Level (Static File)', 'text', true, 1, 9), new DAttr('gzipMaxFileSize', 'uint', 'Max Static File Size (bytes)', 'text', true, '1K'), diff --git a/dist/admin/html.open/utility/build_php/buildconf.inc.php b/dist/admin/html.open/utility/build_php/buildconf.inc.php index 06c35d969..d61c35d3e 100644 --- a/dist/admin/html.open/utility/build_php/buildconf.inc.php +++ b/dist/admin/html.open/utility/build_php/buildconf.inc.php @@ -11,18 +11,17 @@ $PHP_VER = array('5'=> array( - '5.5.3', - '5.4.19', + '5.5.6', + '5.4.22', '5.3.27', '5.2.17'), '4'=> array('4.4.9')); - - -define ('LSAPI_VERSION', '6.3'); + +define ('LSAPI_VERSION', '6.6'); define ('SUHOSIN_VERSION', '0.9.33'); define ('APC_VERSION', '3.1.9'); -define ('XCACHE_VERSION', '3.0.3'); +define ('XCACHE_VERSION', '3.1.0'); define ('MEMCACHE_VERSION', '2.2.7'); //define ('MEMCACHED_VERSION', '1.0.2'); diff --git a/dist/conf/httpd_config.conf.in b/dist/conf/httpd_config.conf.in index 8213b3fda..c2152be7c 100755 --- a/dist/conf/httpd_config.conf.in +++ b/dist/conf/httpd_config.conf.in @@ -146,8 +146,8 @@ extProcessor{ backlog 100 instances 1 priority 0 - memSoftLimit 480M - memHardLimit 500M + memSoftLimit 2047M + memHardLimit 2047M procSoftLimit 400 procHardLimit 500 } @@ -173,8 +173,8 @@ railsDefaults{ runOnStartUp 1 extMaxIdleTime 300 priority 3 - memSoftLimit 150M - memHardLimit 200M + memSoftLimit 2047M + memHardLimit 2047M procSoftLimit 500 procHardLimit 600 } diff --git a/dist/conf/httpd_config.xml.in b/dist/conf/httpd_config.xml.in index c080ef87a..ab036123e 100755 --- a/dist/conf/httpd_config.xml.in +++ b/dist/conf/httpd_config.xml.in @@ -85,10 +85,10 @@ 0 - 450M - 500M - 300 - 400 + 2047M + 2047M + 400 + 500 @@ -114,10 +114,10 @@ 1 300 3 - 550M - 600M - 300 - 400 + 2047M + 2047M + 400 + 500 diff --git a/dist/conf/mime.properties b/dist/conf/mime.properties index 8b5169730..a7d8f5442 100755 --- a/dist/conf/mime.properties +++ b/dist/conf/mime.properties @@ -132,3 +132,8 @@ xwd = image/x-xwindowdump xyz = chemical/x-pdb zip = application/zip z = application/compress +eot = application/vnd.ms-fontobject +ttf, ttc = application/x-font-ttf +otf = font/opentype +woff = application/x-font-woff + diff --git a/dist/docs/ServerStat_Help.html b/dist/docs/ServerStat_Help.html index 8ed8198d3..e5313cfb5 100644 --- a/dist/docs/ServerStat_Help.html +++ b/dist/docs/ServerStat_Help.html @@ -44,18 +44,18 @@
Version 1.2 Rev. 2
-

WebAdmin Console - Service Manager

This is a web interface to monitor and control the server and virtual hosts. -It provides the following features: -

    -
  • Display the current status of the server, listeners and virtual hosts.
  • -
  • Apply configuration changes with a graceful server restart.
  • -
  • Enable/disable the service of a particular virtual host.
  • -
  • View the server log through the log viewer.
  • -
  • Monitor real-time server statistics.
  • -
  • Download new versions or switch between installed versions.
  • +

    WebAdmin Console - Service Manager

    The Service Manager acts as a control room for monitoring the server and controlling certain +top-level functions. It provides the following features: +(The Service Manager can be accessed by clicking on the Actions menu or from home page.) +

      +
    • Monitor the current status of the server, listeners, and virtual hosts.
    • +
    • Apply configuration changes with a graceful restart.
    • +
    • Enable or disable a particular virtual host.
    • +
    • View the server log through the log viewer.
    • +
    • Monitor real-time server statistics.

    Table of Contents

    Server

    -Name - Server | PID | Actions | Apply Changes/Graceful Restart | Server Log Viewer | Real-Time Statistics | Toggle Debug Logging | Version Management | 

    +Name - Server | PID | Actions | Apply Changes/Graceful Restart | Server Log Viewer | Real-Time Statistics | Toggle Debug Logging | 

    Listeners

    Name - Listener | Status - Listener | Virtual Host Mappings | 

    Virtual Hosts

    @@ -68,7 +68,6 @@

    Table of Contents

    Server Log ViewerGo to top
    Description: The Server Log Viewer is a convenient tool for browsing the current server log to check for errors or problems. The log viewer searches the server log file in blocks for the specified log level. The default block size is 20KB. You can use the Begin, End, Next, and Prev buttons to navigate a large log file.
    Tips: The size of a dynamically generated page is limited by Max Dynamic Response Body Size. So if the block is too big, the page might be truncated.
    Real-Time StatisticsGo to top
    Description: The Real-Time Statistics link leads to a page with a real-time server status report. This is a convenient tool to monitor the system. The report shows a snapshot of your server statistics. The refresh rate for this snapshot is controlled by the Refresh Interval drop-down list in the upper righthand corner. The report contains the following sections:
    • Server Health shows the basic server statistics, uptime, load, and anti-DDoS blocked IPs.
    • Server lists current traffic throughput, connections, and requests statistics.
    • Virtual Host shows request processing statuses and external application statuses for each virtual host.
    • External Application lists the external applications currently running and their usage statistics. The CGI daemon process lscgid is always running as an external application.
    Many of the rows in the Real-Time Statistics feature a graph icon. Clicking on this icon will open a graph of that row's statistics updated in real-time. In the Server section, next to Requests, there is a link labeled (Details). This link takes you to the Requests Snapshot, where you can view detailed information on which clients are making certain kinds of requests or which aspects of your site are bottlenecking. The fields in the blue area allow you to filter the snapshot to isolate certain parts of your server or look for clients that are performing certain actions.
    Toggle Debug LoggingGo to top
    Description: Toggle Debug Logging toggles the value of Debug Level between NONE and HIGH. As debug logging has an impact on performance and can fill up the hard drive quickly, so Debug Level should usually be set to NONE on a production server. This feature can be used instead to turn debug logging on and off quickly in order to debug a problem on a production server. Debug logging turned on or off in this way will not change anything shown in your server configurations.
    Tips: Toggle Debug Logging will only work if Log Level is set to DEBUG. [Performance] Important! Debug logging includes detailed information for each request and response. Active debug logging will severely degrade service performance and potentially saturate disk space in a very short time. This feature should only be used for a short period of time when trying to diagnose server issues.
    See Also: Debug Level, Log Level
    -
    Version ManagementGo to top
    Description: Version Management (found by clicking on the the version number at the top of the page) is a convenient tool to manage LSWS versions. It shows license info and information on all installed versions and available new releases.
    • If is a new version has been released on the LiteSpeed website, and Check For Update is enabled, the new version will be listed with a Download link. If Download Updates is enabled, new versions will be automatically downloaded and the new version will be listed with an Upgrade link. Upgrade installs the new package and restarts the web server.
    • You return to a previous version by clicking the Switch To link. This will restart the web server with that version.
    • If you are sure that you no longer need an old installation, you can remove it by clicking the Delete link. This will permanently remove that copy.
    Please note, service will not be interrupted during an upgrade or restart.
    See Also: Download Updates, Check For Update
    Name - ListenerGo to top
    Description: The unique name that identifies this listener. This is the Listener Name you specified when setting up the listener.
    Status - ListenerGo to top
    Description: The current status of this listener. The status is either Running or Error.
    Tips: If the listener is in the Error state, you can view the server log to find out why.
    Virtual Host MappingsGo to top
    Description: Virtual Host Mappings shows currently established mappings to virtual hosts from this listener. The virtual host name is in brackets and is followed by the matching domain name(s) for this listener.
    Tips: If a virtual host has not been loaded successfully (fatal errors in the virtual host configuration), the mapping to that virtual host will not be displayed.
    diff --git a/dist/docs/admin.html b/dist/docs/admin.html index bc64a86ce..9c750cf9d 100644 --- a/dist/docs/admin.html +++ b/dist/docs/admin.html @@ -46,15 +46,16 @@
    Version 1.2 Rev. 2

    Administration

    -

    LiteSpeed web server can be controlled in three ways: through the WebAdmin interface, from the command line, or by sending signals.

    +

    LiteSpeed web server can be controlled in three ways: through the WebAdmin console, from the command line, or by sending signals.

      -
    1. Through the WebAdmin interface:

      +
    2. Through the WebAdmin console:

      +

      WebAdmin console is a centralized control panel to control and configure all LiteSpeed Web Server settings.

      Log on to the WebAdmin console (by default http://[your site's address]:7080/). - Select Select "General." Here you will find a control panel with links to perform common tasks: -server restart, server configuration reload, version management, log viewing, real-time monitoring, + Select "Service Manager". Here you will find a control panel with links to perform common tasks: +server restart, server configuration reload, log viewing, real-time monitoring, virtual host reload, and virtual host enable/disable.

      -

      More details on how to control LiteSpeed Web Server through the WebAdmin console Service Manager...

      +

      More details on how to control LiteSpeed Web Server through the WebAdmin console - Service Manager

      To change the login name and password for the WebAdmin interface, run the following command from the shell:
      [your install dir]/admin/misc/admpass.sh

    3. diff --git a/src/config.h.cmake b/src/config.h.cmake index e0c7ae92c..31f02a47a 100644 --- a/src/config.h.cmake +++ b/src/config.h.cmake @@ -1,7 +1,7 @@ #ifndef __CONFIG_H__ #define __CONFIG_H__ -#define PACKAGE_VERSION "1.2.4" +#define PACKAGE_VERSION "1.2.7" #define LS_ENABLE_SPDY 1 #endif diff --git a/src/edio/bufferedos.cpp b/src/edio/bufferedos.cpp index dc67d2fb3..f367c08d0 100644 --- a/src/edio/bufferedos.cpp +++ b/src/edio/bufferedos.cpp @@ -44,7 +44,7 @@ int BufferedOS::writeEx( const char * pBuf, int size, int avoidCache ) if ( m_buf.empty() ) { ret = m_pOS->write( pBuf, size ); - if ( ret >= avoidCache ) + if (( ret < size )&&( ret >= avoidCache )) { ret = m_buf.cache( pBuf, size, ret ); } diff --git a/src/edio/kqueuer.cpp b/src/edio/kqueuer.cpp index 6009365b1..521a0ad3a 100644 --- a/src/edio/kqueuer.cpp +++ b/src/edio/kqueuer.cpp @@ -210,7 +210,7 @@ int KQueuer::waitAndProcessEvents( int iTimeoutMilliSec ) { if ( pBegin->data != ENOENT ) { - fprintf( stderr, "kevent() error, fd: %d, error: %d, filter: %d flags: %04X\n", pReactor->getfd(), pBegin->data, pBegin->filter, pBegin->flags ); + fprintf( stderr, "kevent() error, fd: %d, error: %d, filter: %d flags: %04X\n", pReactor->getfd(), (int)pBegin->data, pBegin->filter, pBegin->flags ); } //revent = POLLERR; continue; @@ -269,7 +269,7 @@ int KQueuer::waitAndProcessEvents( int iTimeoutMilliSec ) //wil get this if modify event after socket closed, new socket created with the same file descriptor if ( pBegin->flags & EV_ERROR ) { - fprintf( stderr, "kevent(), mismatch handler, fd: %d, error: %d, filter: %d flags: %04X\n", pReactor->getfd(), pBegin->data, pBegin->filter, pBegin->flags ); + fprintf( stderr, "kevent(), mismatch handler, fd: %d, error: %d, filter: %d flags: %04X\n", pReactor->getfd(), (int)pBegin->data, pBegin->filter, pBegin->flags ); //if ( (int)pBegin->data != EBADF ) // close( (int)pBegin->ident ); } diff --git a/src/extensions/fcgi/fcgiconnection.cpp b/src/extensions/fcgi/fcgiconnection.cpp index d6d8e7c01..515bf0253 100644 --- a/src/extensions/fcgi/fcgiconnection.cpp +++ b/src/extensions/fcgi/fcgiconnection.cpp @@ -784,7 +784,7 @@ int FcgiConnection::begin() pRec->header, FCGI_BEGIN_REQUEST, m_iId, 8 ); register unsigned short role = getWorker()->getRole(); pRec->body.roleB0 = role & 0xff; - pRec->body.roleB1 = ( role >> 8 ) && 0xff; + pRec->body.roleB1 = ( role >> 8 ) & 0xff; pRec->body.flags = getWorker()->getConfigPointer()->isPersistConn() & 0xff; m_iovec.clear(); m_iCurStreamHeader = sizeof( FCGI_BeginRequestRecord ); diff --git a/src/extensions/localworker.cpp b/src/extensions/localworker.cpp index 2a3b2687f..791626ce0 100644 --- a/src/extensions/localworker.cpp +++ b/src/extensions/localworker.cpp @@ -89,7 +89,7 @@ void LocalWorker::moveToStopList() void LocalWorker::moveToStopList( int pid) { - PidList::iterator iter = m_pidList->find( (void *)pid ); + PidList::iterator iter = m_pidList->find( (void *)(long)pid ); if ( iter != m_pidList->end() ) { killProcess( pid ); diff --git a/src/http/datetime.cpp b/src/http/datetime.cpp index 88eff4dc9..ddce195d7 100644 --- a/src/http/datetime.cpp +++ b/src/http/datetime.cpp @@ -222,7 +222,7 @@ char * DateTime::getLogTime( time_t lTime, char * pBuf, int bGMT ) static char lastTimeStr[40]; static long lastTime = 0; //static bool lastGMT = 0; - if (( lastTime == lTime ) + if ( lastTime == lTime //&&( lastGMT == bGMT ) ) { diff --git a/src/http/hiostream.cpp b/src/http/hiostream.cpp index 312af3ad0..e9aac6cad 100644 --- a/src/http/hiostream.cpp +++ b/src/http/hiostream.cpp @@ -18,6 +18,20 @@ #include "hiostream.h" +static const char* s_sProtoName[] = { + "HTTP/1.x", + "SPDY/2", + "SPDY/3", + "SPDY/3.1" +}; + +const char * HioStream::getProtocolName( HiosProtocol proto ) +{ + if ( proto >= HIOS_PROTO_MAX ) + return "UNKNOWN"; + return s_sProtoName[proto]; +} + HioStream::~HioStream() { diff --git a/src/http/hiostream.h b/src/http/hiostream.h index 8cb7443cc..3d6e01d1f 100644 --- a/src/http/hiostream.h +++ b/src/http/hiostream.h @@ -39,7 +39,9 @@ enum HiosProtocol { HIOS_PROTO_HTTP = 0, HIOS_PROTO_SPDY2 = 1, - HIOS_PROTO_SPDY3 = 2 + HIOS_PROTO_SPDY3 = 2, + HIOS_PROTO_SPDY31 = 3, + HIOS_PROTO_MAX }; #define HIO_FLAG_PEER_SHUTDOWN (1<<0) @@ -122,6 +124,8 @@ class HioStream : public InputStream, public OutputStream, public LogTracker short isPeerShutdown() const { return m_iFlag & HIO_FLAG_PEER_SHUTDOWN; } + static const char * getProtocolName( HiosProtocol proto ); + private: HioStream(const HioStream& other); HioStream& operator=(const HioStream& other); diff --git a/src/http/httpcgitool.cpp b/src/http/httpcgitool.cpp index 0a87abe51..00044592b 100644 --- a/src/http/httpcgitool.cpp +++ b/src/http/httpcgitool.cpp @@ -443,7 +443,7 @@ int HttpCgiTool::buildCommonEnv( IEnv * pEnv, HttpConnection * pConn ) char achTranslated[10240]; m = pReq->translatePath( pReq->getPathInfo(), n, achTranslated, sizeof( achTranslated ) ); - if ( m != -1 ); + if ( m != -1 ) { pEnv->add( "PATH_TRANSLATED", 15, achTranslated, m ); ++count; diff --git a/src/http/httpcontext.cpp b/src/http/httpcontext.cpp index 225314523..7924fbd1e 100644 --- a/src/http/httpcontext.cpp +++ b/src/http/httpcontext.cpp @@ -129,7 +129,7 @@ void HttpContext::releaseHTAConf() int HttpContext::set( const char * pURI, const char * pLocation, const HttpHandler * pHandler, bool browse, int regex) { - if (( pURI == NULL )) + if ( pURI == NULL ) return EINVAL; if ( strncasecmp( pURI, "exp:", 4 ) == 0 ) { diff --git a/src/http/httplistener.cpp b/src/http/httplistener.cpp index f0b072a44..03e0075aa 100644 --- a/src/http/httplistener.cpp +++ b/src/http/httplistener.cpp @@ -117,18 +117,18 @@ int HttpListener::assign( int fd, struct sockaddr * pAddr ) char achAddr[128]; if (( addr.family() == AF_INET )&&( addr.getV4()->sin_addr.s_addr == INADDR_ANY )) { - snprintf( achAddr, 128, "*:%hu", addr.getPort() ); + snprintf( achAddr, 128, "*:%hu", (short)addr.getPort() ); } else if (( addr.family() == AF_INET6 )&&( IN6_IS_ADDR_UNSPECIFIED ( &addr.getV6()->sin6_addr ) )) { - snprintf( achAddr, 128, "[::]:%hu", addr.getPort() ); + snprintf( achAddr, 128, "[::]:%hu", (short)addr.getPort() ); } else addr.toString( achAddr, 128 ); LOG_NOTICE(( "Recovering server socket: [%s]", achAddr )); m_pMapVHost->setAddrStr( achAddr ); if (( addr.family() == AF_INET6 )&&( IN6_IS_ADDR_UNSPECIFIED ( &addr.getV6()->sin6_addr ) )) - snprintf( achAddr, 128, "[ANY]:%hu", addr.getPort() ); + snprintf( achAddr, 128, "[ANY]:%hu", (short)addr.getPort() ); setName( achAddr ); return setSockAttr( fd, addr ); } diff --git a/src/http/httpreq.h b/src/http/httpreq.h index fee1b8133..995be836c 100644 --- a/src/http/httpreq.h +++ b/src/http/httpreq.h @@ -146,14 +146,14 @@ class HttpReq int m_iHostLen; int m_iPathInfoOff; int m_iPathInfoLen; + const AutoStr2 * m_pRealPath; + int m_iMatchedLen; int m_iNewHostLen; int m_iLocationOff; // The following member need not to be initialized - const AutoStr2 * m_pRealPath; AutoStr2 m_sRealPathStore; int m_iMatchedOff; - int m_iMatchedLen; struct stat m_fileStat; int m_iScriptNameLen; key_value_pair * m_urls; diff --git a/src/http/ntwkiolink.cpp b/src/http/ntwkiolink.cpp index 0d53a9645..24c71f05b 100644 --- a/src/http/ntwkiolink.cpp +++ b/src/http/ntwkiolink.cpp @@ -82,13 +82,17 @@ int NtwkIOLink::setupHandler( HiosProtocol verSpdy ) if ( !isSSL() && (verSpdy == HIOS_PROTO_HTTP) ) verSpdy = HIOS_PROTO_SPDY2; #endif - setProtocol( verSpdy ); if ( verSpdy != HIOS_PROTO_HTTP ) { SpdyConnection * pConn = new SpdyConnection(); if ( !pConn ) return -1; setLogIdBuild( 0 ); + if ( verSpdy == HIOS_PROTO_SPDY31 ) + { + verSpdy = HIOS_PROTO_SPDY3; + pConn->enableSessionFlowCtrl(); + } pConn->init( verSpdy ); pHandler = pConn; } @@ -101,6 +105,8 @@ int NtwkIOLink::setupHandler( HiosProtocol verSpdy ) pHandler = pConn; } + setProtocol( verSpdy ); + pHandler->assignStream( this ); pHandler->onInitConnected(); return 0; @@ -1270,6 +1276,22 @@ int NtwkIOLink::acceptSSL() return ret; } +int NtwkIOLink::sslSetupHandler() +{ + unsigned int spdyVer = m_ssl.getSpdyVersion(); + if ( spdyVer >= HIOS_PROTO_MAX ) + { + LOG_ERR(( getLogger(), "[%s] bad SPDY version: %d, use HTTP", getLogId(), spdyVer )); + spdyVer = HIOS_PROTO_HTTP; + } + else + { + if ( D_ENABLED( DL_LESS )) + LOG_D(( getLogger(), "[%s] Next Protocol Negociation result: %s\n", getLogId(), getProtocolName( (HiosProtocol)spdyVer ) )); + } + return setupHandler( (HiosProtocol)spdyVer ); +} + int NtwkIOLink::SSLAgain() { if ( D_ENABLED( DL_LESS )) @@ -1284,13 +1306,7 @@ int NtwkIOLink::SSLAgain() ret = acceptSSL(); if ( ret == 1 ) { - unsigned int spdyVer = m_ssl.getSpdyVersion(); - if ( spdyVer > HIOS_PROTO_SPDY3 ) - { - LOG_ERR(( getLogger(), "[%s] bad SPDY version: %d, use HTTP", getLogId(), spdyVer )); - spdyVer = HIOS_PROTO_HTTP; - } - setupHandler( (HiosProtocol)spdyVer ); + sslSetupHandler(); } break; case SSLConnection::SHUTDOWN: diff --git a/src/http/ntwkiolink.h b/src/http/ntwkiolink.h index 425ed7497..cdb061925 100644 --- a/src/http/ntwkiolink.h +++ b/src/http/ntwkiolink.h @@ -188,6 +188,7 @@ class NtwkIOLink : public EventReactor, public HioStream void checkSSLReadRet( int ret ); int setupHandler( HiosProtocol verSpdy ); + int sslSetupHandler(); void doClose(); void dumpState(const char * pFuncName, const char * action); diff --git a/src/http/staticfilehandler.cpp b/src/http/staticfilehandler.cpp index a6714c7c2..2971930bd 100644 --- a/src/http/staticfilehandler.cpp +++ b/src/http/staticfilehandler.cpp @@ -86,7 +86,7 @@ inline int buildStaticFileHeaders( HttpResp * pResp, StaticFileData * pData ) #include -#define READ_BUF_SIZE 8192 +#define READ_BUF_SIZE 16384 static int cacheSend( HttpConnection* pConn, StaticFileData * pData, int remain ) { diff --git a/src/spdy/spdyconnection.cpp b/src/spdy/spdyconnection.cpp index c71f52c7b..52088956e 100644 --- a/src/spdy/spdyconnection.cpp +++ b/src/spdy/spdyconnection.cpp @@ -61,9 +61,12 @@ SpdyConnection::SpdyConnection() , m_uiGoAwayId( 0 ) , m_mapStream( 50, int_hash, int_comp ) , m_flag( 0 ) - , m_iServerInitWindowSize( 5*1024*1024 ) + , m_iCurDataOutWindow( SPDY_FCW_INIT_SIZE ) + , m_iCurInBytesToUpdate( 0 ) + , m_iDataInWindow( SPDY_FCW_INIT_SIZE ) + , m_iStreamInInitWindowSize( 5*1024*1024 ) , m_iServerMaxStreams( 500 ) - , m_iClientInitWindowSize( 65536 ) + , m_iStreamOutInitWindowSize( SPDY_FCW_INIT_SIZE ) , m_iClientMaxStreams( 100 ) , m_tmIdleBegin( 0 ) { @@ -71,14 +74,15 @@ SpdyConnection::SpdyConnection() int SpdyConnection::init( HiosProtocol ver ) { + m_iCurDataOutWindow = SPDY_FCW_INIT_SIZE; m_deflator.init( 0, ver ); m_inflator.init( 1, ver ); m_uiLastStreamID = 0; m_bVersion = ver + 1; if ( ver == HIOS_PROTO_SPDY3 ) - m_iClientInitWindowSize = 65536; + m_iStreamOutInitWindowSize = SPDY_FCW_INIT_SIZE; else - m_iClientInitWindowSize = 1024 * 1024 * 1024; //For SPDY2, there is no flow control, set it to a large value + m_iStreamOutInitWindowSize = 1024 * 1024 * 1024; //For SPDY2, there is no flow control, set it to a large value m_iServerMaxStreams = 500; m_iClientMaxStreams = 100; @@ -94,7 +98,12 @@ int SpdyConnection::onInitConnected() m_state = HIOS_CONNECTED; setOS( getStream() ); getStream()->continueRead(); - sendSettings(m_iServerMaxStreams, m_iServerInitWindowSize); + //sendSettings(m_iServerMaxStreams, m_iStreamInInitWindowSize); + if ( isFlowCtrl() ) + { + //sendWindowUpdateFrame( 0, SPDY_FCW_INIT_SIZE ); + //m_iDataInWindow += SPDY_FCW_INIT_SIZE; + } return 0; } @@ -150,6 +159,12 @@ int SpdyConnection::onReadEx2() break; m_bufInput.moveTo((char*)m_pcurrentSpdyHeader, 8); m_iCurrentFrameRemain = m_pcurrentSpdyHeader->getLength(); + if ( D_ENABLED( DL_LESS ) ) + { + if ( !m_pcurrentSpdyHeader->isControlFrame() ) + LOG_D(( getLogger(), "[%s] DATA frame, size: %d", getLogId(), + m_iCurrentFrameRemain )); + } } if ( m_pcurrentSpdyHeader->isControlFrame() ) { @@ -172,6 +187,19 @@ int SpdyConnection::onReadEx2() m_iCurrentFrameRemain = -8; } } + + if ( isFlowCtrl()&& + ( m_iDataInWindow / 2 < m_iCurInBytesToUpdate )) + { + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] bytes received for WINDOW_UPDATE: %d", + getLogId(), m_iDataInWindow )); + } + sendWindowUpdateFrame( 0, m_iCurInBytesToUpdate ); + m_iCurInBytesToUpdate = 0; + } + } return 0; } @@ -245,54 +273,44 @@ void SpdyConnection::printLogMsg( SpdyFrameHeader* pHeader ) int SpdyConnection::processSettingFrame( SpdyFrameHeader * pHeader ) {//process each setting ID/value pair - static char cpTemp[100]; static const char* cpEntryNames[] = { "", - "SPDY_SETTINGS_UPLOAD_BANDWIDTH = ", - "SPDY_SETTINGS_DOWNLOAD_BANDWIDTH = ", - "SPDY_SETTINGS_ROUND_TRIP_TIME = ", - "SPDY_SETTINGS_MAX_CONCURRENT_STREAMS = ", - "SPDY_SETTINGS_CURRENT_CWND = ", - "SPDY_SETTINGS_DOWNLOAD_RETRANS_RATE = ", - "SPDY_SETTINGS_INITIAL_WINDOW_SIZE = " }; + "SETTINGS_UPLOAD_BANDWIDTH", + "SETTINGS_DOWNLOAD_BANDWIDTH", + "SETTINGS_ROUND_TRIP_TIME", + "SETTINGS_MAX_CONCURRENT_STREAMS", + "SETTINGS_CURRENT_CWND", + "SETTINGS_DOWNLOAD_RETRANS_RATE", + "SETTINGS_INITIAL_WINDOW_SIZE" }; uint32_t iEntryID, iEntryValue; SpdySettingPairs settingPairs; unsigned char ucEntryFlags; int iEntries = pHeader->getHboData( 0 ); - unsigned char ucflags = pHeader->getFlags(); if ( m_iCurrentFrameRemain != 8 * iEntries ) { LOG_INFO(( getLogger(), "[%s] bad SETTING frame, frame size does not match, ignore.", getLogId() )); return 0; } - if ( D_ENABLED( DL_LESS ) ) - { - snprintf( cpTemp, 100, "SPDY SETTINGS: Version:%d, Flags:%d, Number of Entries:%d\n", - m_bVersion, ucflags, iEntries); - m_bufInflate.clear(); - m_bufInflate.append(cpTemp); - } for( int i = 0; i < iEntries; i++) { m_bufInput.moveTo( (char*)&settingPairs, 8); - if ( m_bVersion == 3 ) + if ( m_bVersion == 2 ) settingPairs.swapID(); ucEntryFlags = settingPairs.getFlags(); iEntryID = settingPairs.getID(); iEntryValue = settingPairs.getValue(); if ( D_ENABLED( DL_LESS ) ) { - m_bufInflate.append(cpEntryNames[iEntryID]); - sprintf( cpTemp, "%d, Flags=%d\n", iEntryValue, ucEntryFlags); - m_bufInflate.append(cpTemp); + LOG_D(( getLogger(), "[%s] %s(%d) value: %d, Flags=%d", getLogId(), + (iEntryID < 8)?cpEntryNames[iEntryID]:"INVALID", iEntryID, iEntryValue, ucEntryFlags)); } switch( iEntryID ) { case SPDY_SETTINGS_INITIAL_WINDOW_SIZE: - m_iClientInitWindowSize = iEntryValue ; + m_iStreamOutInitWindowSize = iEntryValue ; break; case SPDY_SETTINGS_MAX_CONCURRENT_STREAMS: m_iClientMaxStreams = iEntryValue ; @@ -302,12 +320,8 @@ int SpdyConnection::processSettingFrame( SpdyFrameHeader * pHeader ) } } m_iCurrentFrameRemain = 0; - if ( D_ENABLED( DL_LESS ) ) - { - m_bufInflate.append( '\0' ); - LOG_D(( getLogger(), "[%s] %s", - getLogId(), m_bufInflate.begin() ) ); - } + + sendSettings(m_iServerMaxStreams, m_iStreamInInitWindowSize); return 0; } @@ -315,22 +329,23 @@ int SpdyConnection::processWindowUpdateFrame( SpdyFrameHeader * pHeader ) { int32_t id = pHeader->getHboData(0); int32_t delta = pHeader->getHboData(1); - StreamobjpMap::iterator it = m_mapStream.find(( void* ) id ); - if ( it != m_mapStream.end() ) + StreamMap::iterator it; + if (( id == 0 )&&( isFlowCtrl() )) { - SpdyStream * pStream = it.second(); - int32_t current = pStream->getWindowOut(); - if ( pStream->isFlowCtrl() ) + m_iCurDataOutWindow += delta; + if ( D_ENABLED( DL_LESS ) ) { - pStream->adjWindowOut( delta ); - if (( current >= 0 )&&( pStream->getWindowOut() < 0 )) - { - //window overflow - resetStream( it, SPDY_RST_STREAM_FLOW_CONTROL_ERROR ); - } - else if (( pStream->isWantWrite() )&& ( pStream->getWindowOut() > 0 )) - getStream()->continueWrite(); + LOG_D(( getLogger(), "[%s] session WINDOW_UPDATE: %d, window size: %d ", + getLogId(), delta, m_iCurDataOutWindow ) ); } + return 0; + } + it = m_mapStream.find(( void* )(long)id ); + if ( it != m_mapStream.end() ) + { + SpdyStream * pStream = it.second(); + if ( pStream->adjWindowOut( delta ) == -1 ) + resetStream( it, SPDY_RST_STREAM_FLOW_CONTROL_ERROR ); } return 0; } @@ -338,7 +353,7 @@ int SpdyConnection::processWindowUpdateFrame( SpdyFrameHeader * pHeader ) int SpdyConnection::processRstFrame( SpdyFrameHeader* pHeader ) { - StreamobjpMap::iterator it = m_mapStream.find(( void* ) pHeader->getHboData(0) ); + StreamMap::iterator it = m_mapStream.find(( void* )(long)pHeader->getHboData(0) ); if ( it == m_mapStream.end() ) return 0; SpdyStream* pSpdyStream = it.second(); @@ -355,6 +370,9 @@ void SpdyConnection::skipRemainData() len = m_iCurrentFrameRemain; m_bufInput.pop_front( len ); m_iCurrentFrameRemain -= len; + + if ( isFlowCtrl() ) + m_iCurInBytesToUpdate += len; } int SpdyConnection::processDataFrame( SpdyFrameHeader* pHeader ) @@ -386,6 +404,8 @@ int SpdyConnection::processDataFrame( SpdyFrameHeader* pHeader ) pSpdyStream->appendReqData( m_bufInput.begin(), len, m_iCurrentFrameRemain ? 0 : pHeader->getFlags() ); m_bufInput.pop_front( len ); + if ( isFlowCtrl() ) + m_iCurInBytesToUpdate += len; } if ( isSpdy3() && !pSpdyStream->isPeerShutdown() ) @@ -395,11 +415,11 @@ int SpdyConnection::processDataFrame( SpdyFrameHeader* pHeader ) LOG_D(( getLogger(), "[%s] processDataFrame() ID: %d, input window size: %d ", getLogId(), streamID, pSpdyStream->getWindowIn() ) ); } - - if ( pSpdyStream->getWindowIn() < m_iServerInitWindowSize / 2 ) + + if ( pSpdyStream->getWindowIn() < m_iStreamInInitWindowSize / 2 ) { - sendWindowUpdateFrame( streamID, m_iServerInitWindowSize / 2 ); - pSpdyStream->adjWindowIn( m_iServerInitWindowSize / 2 ); + sendWindowUpdateFrame( streamID, m_iStreamInInitWindowSize / 2 ); + pSpdyStream->adjWindowIn( m_iStreamInInitWindowSize / 2 ); } } return 0; @@ -413,7 +433,7 @@ int SpdyConnection::processSynStreamFrame(SpdyFrameHeader* pHeader ) int priority; SpdyStream* pStream; uint32_t id = pHeader->getHboData( 0 ); - if ( m_flag & SPDY_CNN_FLAG_GOAWAY ) + if ( m_flag & SPDY_CONN_FLAG_GOAWAY ) { return 0; } @@ -653,7 +673,7 @@ SpdyStream* SpdyConnection::getNewStream( uint32_t uiStreamID, int iPriority, ui pConn->setNtwkIOLink( pLink ); pStream = new SpdyStream(); //pStream = SpdyStreamPool::getSpdyStream(); - m_mapStream.insert(( void* )uiStreamID, pStream ); + m_mapStream.insert(( void* )(long)uiStreamID, pStream ); if ( D_ENABLED( DL_MORE ) ) { LOG_D(( getLogger(), "[%s] getNewStream(), ID: %d, stream map size: %d ", @@ -669,14 +689,14 @@ SpdyStream* SpdyConnection::getNewStream( uint32_t uiStreamID, int iPriority, ui void SpdyConnection::recycleStream( uint32_t uiStreamID ) { - StreamobjpMap::iterator it = m_mapStream.find(( void* ) uiStreamID ); + StreamMap::iterator it = m_mapStream.find(( void* )(long) uiStreamID ); if ( it == m_mapStream.end() ) return; recycleStream( it ); } -void SpdyConnection::recycleStream( StreamobjpMap::iterator it ) +void SpdyConnection::recycleStream( StreamMap::iterator it ) { SpdyStream* pSpdyStream = it.second(); m_mapStream.erase( it ); @@ -704,11 +724,6 @@ int SpdyConnection::appendCtrlFrameHeader( SpdyFrameType type, uint8_t len ) s_achFrameHeader[7] = len; getBuf()->append( (char*)s_achFrameHeader, 8 ); - if ( D_ENABLED( DL_MORE ) ) - { - LOG_D(( getLogger(), "[%s] send %s, len: %d" - , getLogId(), getFrameName( type ), len ) ); - } return 0; } @@ -721,6 +736,11 @@ int SpdyConnection::sendFrame8Bytes( SpdyFrameType type, uint32_t uiVal1, uint32 appendNbo4Bytes( getBuf(), uiVal1 ); appendNbo4Bytes( getBuf(), uiVal2 ); flush(); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] send %s frame, stream: %d, value: %d" + , getLogId(), getFrameName( type ), uiVal1, uiVal2 ) ); + } return 0; } @@ -730,6 +750,11 @@ int SpdyConnection::sendFrame4Bytes( SpdyFrameType type, uint32_t uiVal1 ) appendCtrlFrameHeader( type, 4 ); appendNbo4Bytes( getBuf(), uiVal1 ); flush(); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] send %s frame, value: %d" + , getLogId(), getFrameName( type ), uiVal1 ) ); + } return 0; } @@ -773,14 +798,33 @@ int SpdyConnection::sendSettings(uint32_t uiMaxStreamNum, uint32_t uiWindowSize) appendNbo4Bytes( getBuf(), uiMaxStreamNum ); append4Bytes( getBuf(), cWindowSizeV3 ); appendNbo4Bytes( getBuf(), uiWindowSize ); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), + "[%s] send SETTING frame, MAX_CONCURRENT_STREAMS: %d," + " INITIAL_WINDOW_SIZE: %d" + , getLogId(), uiMaxStreamNum, uiWindowSize ) ); + } } else { appendCtrlFrameHeader( SPDY_FRAME_SETTINGS, 12 ); getBuf()->append(cMaxStreamNumV2, 8 ); appendNbo4Bytes( getBuf(), uiMaxStreamNum ); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), + "[%s] send SETTING frame, MAX_CONCURRENT_STREAMS: %d," + , getLogId(), uiMaxStreamNum ) ); + } } - flush(); + if ( isFlowCtrl() ) + { + sendWindowUpdateFrame( 0, SPDY_FCW_INIT_SIZE ); + m_iDataInWindow += SPDY_FCW_INIT_SIZE; + } + else + flush(); return 0; } @@ -804,7 +848,7 @@ int SpdyConnection::processPingFrame( SpdyFrameHeader * pHeader ) msec += ( CurTime.tv_usec - m_timevalPing.tv_usec ) / 1000; if ( D_ENABLED( DL_MORE ) ) { - LOG_D(( getLogger(), "[%s] Received Ping, ID=%d, Round trip " + LOG_D(( getLogger(), "[%s] Received PING, ID=%d, Round trip " "times=%d milli-seconds", getLogId(), m_uiLastPingID, msec ) ); } return 0; @@ -817,7 +861,7 @@ int SpdyConnection::append400BadReqReply( uint32_t uiStreamID ) SpdyStream* SpdyConnection::findStream( uint32_t uiStreamID ) { - StreamobjpMap::iterator it = m_mapStream.find(( void* ) uiStreamID ); + StreamMap::iterator it = m_mapStream.find(( void* )(long)uiStreamID ); if ( it == m_mapStream.end() ) return NULL; return it.second(); @@ -848,7 +892,7 @@ int SpdyConnection::onCloseEx() int SpdyConnection::onTimerEx() { int result = 0; - if ( m_flag & SPDY_CNN_FLAG_GOAWAY ) + if ( m_flag & SPDY_CONN_FLAG_GOAWAY ) result = releaseAllStream(); else result = timerRoutine(); @@ -858,7 +902,7 @@ int SpdyConnection::onTimerEx() int SpdyConnection::processGoAwayFrame( SpdyFrameHeader * pHeader ) { - m_flag |= ( short )SPDY_CNN_FLAG_GOAWAY; + m_flag |= ( short )SPDY_CONN_FLAG_GOAWAY; onCloseEx(); return true; @@ -890,7 +934,7 @@ int SpdyConnection::sendGoAwayFrame(SpdyGoAwayStatus status ) int SpdyConnection::releaseAllStream() { - StreamobjpMap::iterator itn, it = m_mapStream.begin(); + StreamMap::iterator itn, it = m_mapStream.begin(); for ( ; it != m_mapStream.end(); ) { itn = m_mapStream.next( it ); @@ -903,7 +947,7 @@ int SpdyConnection::releaseAllStream() int SpdyConnection::timerRoutine() { - StreamobjpMap::iterator itn, it = m_mapStream.begin(); + StreamMap::iterator itn, it = m_mapStream.begin(); for ( ; it != m_mapStream.end(); ) { itn = m_mapStream.next( it ); @@ -989,7 +1033,7 @@ int SpdyConnection::sendRespHeaders( IOVec &vector, int iheaderCount, uint32_t u getBuf()->update(( headerOffset + 4 ), (char*)&temp32, 4 ); //Length if ( D_ENABLED( DL_MORE ) ) { - LOG_D(( getLogger(), "[%s] Append_Respons_Header() successfull, " + LOG_D(( getLogger(), "[%s] sent SYN_REPLY for " "StreamID=%lu, total=%d\n", getLogId(), uiStreamID, total ) ); } return total; @@ -1063,7 +1107,7 @@ void SpdyConnection::resetStream( SpdyStream * pStream, SpdyRstErrorCode code ) } -void SpdyConnection::resetStream( StreamobjpMap::iterator it, SpdyRstErrorCode code ) +void SpdyConnection::resetStream( StreamMap::iterator it, SpdyRstErrorCode code ) { sendRstFrame( it.second()->getStreamID(), code ); recycleStream( it ); diff --git a/src/spdy/spdyconnection.h b/src/spdy/spdyconnection.h index dceee7d90..bc2dd9c6e 100644 --- a/src/spdy/spdyconnection.h +++ b/src/spdy/spdyconnection.h @@ -26,8 +26,10 @@ #include "http/hiostream.h" #include +#include -#define SPDY_CNN_FLAG_GOAWAY (1<<0) +#define SPDY_CONN_FLAG_GOAWAY (1<<0) +#define SPDY_CONN_FLAG_FLOW_CTRL (1<<1) #define SPDY_STREAM_PRIORITYS 8 @@ -51,7 +53,7 @@ class SpdyConnection: public HioStreamHandler, public BufferedOS int onWriteEx(); int isOutBufFull() const - { return getBuf()->size() >= SPDY_MAX_DATAFRAM_SIZE; } + { return ((m_iCurDataOutWindow <= 0 )||(getBuf()->size() >= SPDY_MAX_DATAFRAM_SIZE)); } int flush(); @@ -81,11 +83,14 @@ class SpdyConnection: public HioStreamHandler, public BufferedOS void continueWrite() { getStream()->continueWrite(); } - int32_t getServerInitWindowSize() const - { return m_iServerInitWindowSize; } + int32_t getStreamInInitWindowSize() const + { return m_iStreamInInitWindowSize; } - int32_t getClientInitWindowSize() const - { return m_iClientInitWindowSize; } + int32_t getStreamOutInitWindowSize() const + { return m_iStreamOutInitWindowSize; } + + int32_t getCurDataOutWindow() const + { return m_iCurDataOutWindow; } int appendPing(uint32_t uiStreamID) { return sendFrame4Bytes( SPDY_FRAME_PING, uiStreamID ); } @@ -100,11 +105,32 @@ class SpdyConnection: public HioStreamHandler, public BufferedOS { return sendFrame8Bytes( SPDY_FRAME_RST_STREAM, uiStreamID, code ); } + int sendFinFrame( uint32_t uiStreamID ) + { + char achHeader[8]; + *(uint32_t *)achHeader = htonl( uiStreamID ); + achHeader[4] = 1; + achHeader[5] = 0; + achHeader[6] = 0; + achHeader[7] = 0; + return cacheWrite( achHeader, sizeof( achHeader ) ); + } + + void dataFrameSent( int bytes ) + { + if ( isFlowCtrl() ) + m_iCurDataOutWindow -= bytes; + } + + + void enableSessionFlowCtrl() { m_flag |= SPDY_CONN_FLAG_FLOW_CTRL; } + short isFlowCtrl() const { return m_flag & SPDY_CONN_FLAG_FLOW_CTRL; } + void recycleStream( uint32_t uiStreamID ); static void replaceZero( char* pValue, int ilength ); private: - typedef THash< SpdyStream* > StreamobjpMap; + typedef THash< SpdyStream* > StreamMap; SpdyStream* findStream(uint32_t uiStreamID); int releaseAllStream(); @@ -134,19 +160,18 @@ class SpdyConnection: public HioStreamHandler, public BufferedOS int doGoAway(SpdyGoAwayStatus status); int append400BadReqReply(uint32_t uiStreamID); void resetStream( SpdyStream * pStream, SpdyRstErrorCode code ); - void resetStream( StreamobjpMap::iterator it, SpdyRstErrorCode code ); + void resetStream( StreamMap::iterator it, SpdyRstErrorCode code ); int appendCtrlFrameHeader(SpdyFrameType type, uint8_t len ); int sendFrame8Bytes( SpdyFrameType type, uint32_t uiVal1, uint32_t uiVal2 ); int sendFrame4Bytes( SpdyFrameType type, uint32_t uiVal1 ); - void recycleStream( StreamobjpMap::iterator it ); + void recycleStream( StreamMap::iterator it ); int isSpdy3() const { return (m_bVersion == 3); } void logDeflateInflateError( int n, int iDeflate ); int appendReqHeaders(SpdyStream* arg1, int arg2); int extractCompressedData(); void skipRemainData(); - private: LoopBuf m_bufInput; @@ -162,14 +187,18 @@ class SpdyConnection: public HioStreamHandler, public BufferedOS NameValuePair m_NameValuePairList[100]; NameValuePair m_NameValuePairListReqline[3]; DLinkQueue m_dqueStreamRespon[SPDY_STREAM_PRIORITYS]; - StreamobjpMap m_mapStream; + StreamMap m_mapStream; short m_state; short m_flag; char m_bVersion; + + int32_t m_iCurDataOutWindow; + int32_t m_iCurInBytesToUpdate; + int32_t m_iDataInWindow; - int32_t m_iServerInitWindowSize; + int32_t m_iStreamInInitWindowSize; int32_t m_iServerMaxStreams; - int32_t m_iClientInitWindowSize; + int32_t m_iStreamOutInitWindowSize; int32_t m_iClientMaxStreams; int32_t m_tmIdleBegin; int32_t m_SpdyHeaderMem[10]; diff --git a/src/spdy/spdyprotocol.cpp b/src/spdy/spdyprotocol.cpp index 7e5f285bc..56508eea6 100644 --- a/src/spdy/spdyprotocol.cpp +++ b/src/spdy/spdyprotocol.cpp @@ -16,21 +16,25 @@ * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ #include "spdyprotocol.h" + +static const char* s_sFrameName[] = { + "DATA", + "SYN_STREAM", + "SYN_REPLY", + "RST_STREAM", + "SETTINGS", + "NOOP", + "PING", + "GOAWAY", + "HEADERS", + "WINDOW_UPDATE", + "CREDENTIAL" +}; + const char* getFrameName(unsigned char bframeType) { - static const char* pbyt[] = { "DATA", - "SYN_STREAM", - "SYN_REPLY", - "RST_STREAM", - "SETTINGS", - "NOOP", - "PING", - "GOAWAY", - "HEADERS", - "WINDOW_UPDATE", - "RCREDENTIAL"}; if ( bframeType <= SPDY_FRAME_LAST_CONTROL_TYPE ) - return pbyt[bframeType]; + return s_sFrameName[bframeType]; return "UNKONWN"; } diff --git a/src/spdy/spdyprotocol.h b/src/spdy/spdyprotocol.h index 1537d8f76..a69f3d357 100644 --- a/src/spdy/spdyprotocol.h +++ b/src/spdy/spdyprotocol.h @@ -212,28 +212,28 @@ class SpdySettingPairs union { unsigned char m_b[4]; - uint32_t m_uiTemp; + uint32_t m_ui; - } m_un1; + } m_unFlagId; uint32_t m_uiValue; public: void swapID() { unsigned char ch; - ch = m_un1.m_b[0]; - m_un1.m_b[0] = m_un1.m_b[3]; - m_un1.m_b[3] = ch; - ch = m_un1.m_b[1]; - m_un1.m_b[1] = m_un1.m_b[2]; - m_un1.m_b[2] = ch; + ch = m_unFlagId.m_b[0]; + m_unFlagId.m_b[0] = m_unFlagId.m_b[3]; + m_unFlagId.m_b[3] = ch; + ch = m_unFlagId.m_b[1]; + m_unFlagId.m_b[1] = m_unFlagId.m_b[2]; + m_unFlagId.m_b[2] = ch; } - unsigned char getFlags() const { return m_un1.m_b[0]; } - uint32_t getValue() const { return htonl(m_uiValue); } - uint32_t getID() const { return ( htonl(m_un1.m_uiTemp) & 0xFFFFFF); } + unsigned char getFlags() const { return m_unFlagId.m_b[0]; } + uint32_t getValue() const { return ntohl(m_uiValue); } + uint32_t getID() const { return ( ntohl(m_unFlagId.m_ui) & 0xFFFFFF); } }; #define SPDY_MAX_DATAFRAM_SIZE 65536 - +#define SPDY_FCW_INIT_SIZE 65536 #endif // SPDYPROTOCOL_H diff --git a/src/spdy/spdystream.cpp b/src/spdy/spdystream.cpp index 7ce8b6232..e8a23b4fd 100644 --- a/src/spdy/spdystream.cpp +++ b/src/spdy/spdystream.cpp @@ -29,7 +29,7 @@ SpdyStream::SpdyStream() :m_uiStreamID(0) ,m_iPriority(0) - ,m_pSpdyCnn(NULL) + ,m_pSpdyConn(NULL) { } @@ -40,14 +40,14 @@ const char * SpdyStream::buildLogId() AutoStr2 & id = getIdBuf(); len = safe_snprintf( id.buf(), MAX_LOGID_LEN, "%s-%d", - m_pSpdyCnn->getStream()->getLogId(), m_uiStreamID ); + m_pSpdyConn->getStream()->getLogId(), m_uiStreamID ); id.setLen( len ); return id.c_str(); } int SpdyStream::init(uint32_t StreamID, - int Priority, SpdyConnection* pSpdyCnn, uint8_t flags, HioStreamHandler * pHandler ) + int Priority, SpdyConnection* pSpdyConn, uint8_t flags, HioStreamHandler * pHandler ) { HioStream::reset(); pHandler->assignStream( this ); @@ -58,11 +58,10 @@ int SpdyStream::init(uint32_t StreamID, m_bufIn.clear(); m_uiStreamID = StreamID; - m_iBytesAllowSend = SPDY_MAX_DATAFRAM_SIZE; - m_iWindowOut = pSpdyCnn->getClientInitWindowSize(); - m_iWindowIn = pSpdyCnn->getServerInitWindowSize(); + m_iWindowOut = pSpdyConn->getStreamOutInitWindowSize(); + m_iWindowIn = pSpdyConn->getStreamInInitWindowSize(); m_iPriority = Priority; - m_pSpdyCnn = pSpdyCnn; + m_pSpdyConn = pSpdyConn; if ( D_ENABLED( DL_LESS )) { LOG_D(( getLogger(), "[%s] SpdyStream::init(), id: %d. ", @@ -142,7 +141,7 @@ void SpdyStream:: continueWrite() getLogId() )); } setFlag(HIO_FLAG_WANT_WRITE, 1); - m_pSpdyCnn->continueWrite(); + m_pSpdyConn->continueWrite(); } void SpdyStream::onTimer() @@ -152,8 +151,6 @@ void SpdyStream::onTimer() int SpdyStream::sendFin() { - char achHeader[8]; - if ( getState() == HIOS_SHUTDOWN ) return 0; @@ -164,9 +161,8 @@ int SpdyStream::sendFin() LOG_D(( getLogger(), "[%s] SpdyStream::sendFin()", getLogId() )); } - buildDataFrameHeader( achHeader, 0 ); - m_pSpdyCnn->cacheWrite( achHeader, sizeof( achHeader ) ); - m_pSpdyCnn->flush(); + m_pSpdyConn->sendFinFrame( m_uiStreamID ); + m_pSpdyConn->flush(); return 0; } @@ -179,13 +175,13 @@ int SpdyStream::close() sendFin(); setFlag( HIO_FLAG_WANT_WRITE, 1 ); setState(HIOS_DISCONNECTED); - m_pSpdyCnn->continueWrite(); + m_pSpdyConn->continueWrite(); //if (getHandler()) //{ // getHandler()->recycle(); // setHandler( NULL ); //} - //m_pSpdyCnn->recycleStream( m_uiStreamID ); + //m_pSpdyConn->recycleStream( m_uiStreamID ); return 0; } @@ -200,23 +196,49 @@ int SpdyStream::flush() return 0; } +int SpdyStream::getDataFrameSize( int wanted ) +{ + if (( m_pSpdyConn->isOutBufFull() )|| + ( 0 >= m_iWindowOut )) + { + setFlag( HIO_FLAG_BUFF_FULL|HIO_FLAG_WANT_WRITE, 1 ); + m_pSpdyConn->continueWrite(); + return 0; + } + + if ( wanted > m_iWindowOut ) + wanted = m_iWindowOut; + if ( m_pSpdyConn->isFlowCtrl() && ( wanted > m_pSpdyConn->getCurDataOutWindow() )) + wanted = m_pSpdyConn->getCurDataOutWindow(); + if ( wanted > SPDY_MAX_DATAFRAM_SIZE ) + wanted = SPDY_MAX_DATAFRAM_SIZE; + return wanted; +} + int SpdyStream::writev( IOVec &vector, int total ) { - int totalSended = 0; - IOVec::iterator it; + int size; + int ret; if ( getState()==HIOS_DISCONNECTED ) return -1; if (getFlag( HIO_FLAG_BUFF_FULL) ) return 0; - - it = vector.begin(); - for (; it != vector.end(); it++) + size = getDataFrameSize( total ); + if ( size <= 0 ) + return 0; + if ( size < total ) { - totalSended += write( (char*)(it->iov_base), it->iov_len) ; - if (getFlag( HIO_FLAG_BUFF_FULL) ) - return totalSended; + //adjust vector + IOVec iov( vector ); + total = iov.shrinkTo( size, 0 ); + ret = sendData( &iov, size ); } - return totalSended; + else + ret = sendData( &vector, size ); + if ( ret == -1 ) + return -1; + return size; + } int SpdyStream::write( const char * buf, int len ) @@ -225,17 +247,9 @@ int SpdyStream::write( const char * buf, int len ) int allowed; if ( getState() == HIOS_DISCONNECTED ) return -1; - if (( m_pSpdyCnn->isOutBufFull() )|| - ( 0 >= m_iBytesAllowSend )) - { - setFlag( HIO_FLAG_BUFF_FULL|HIO_FLAG_WANT_WRITE, 1 ); - m_pSpdyCnn->continueWrite(); + allowed = getDataFrameSize( len ); + if ( allowed <= 0 ) return 0; - } - - allowed = m_iBytesAllowSend; - if ( len < allowed ) - allowed = len; iov.append( buf, allowed ); if ( sendData( &iov, allowed ) == -1 ) @@ -253,19 +267,16 @@ int SpdyStream::onWrite() LOG_D(( getLogger(), "[%s] SpdyStream::onWrite()", getLogId() )); } - if ( m_pSpdyCnn->isOutBufFull() ) + if ( m_pSpdyConn->isOutBufFull() ) return 0; - m_iBytesAllowSend = SPDY_MAX_DATAFRAM_SIZE; - if ( m_iBytesAllowSend > m_iWindowOut ) - m_iBytesAllowSend = m_iWindowOut; - if ( m_iBytesAllowSend <= 0 ) + if ( m_iWindowOut <= 0 ) return 0; setFlag( HIO_FLAG_BUFF_FULL, 0 ); if ( isWantWrite() ) getHandler()->onWriteEx(); if ( isWantWrite() ) - m_pSpdyCnn->continueWrite(); + m_pSpdyConn->continueWrite(); return 0; } @@ -284,7 +295,8 @@ int SpdyStream::sendData( IOVec * pIov, int total ) int ret; buildDataFrameHeader( achHeader, total ); pIov->push_front( achHeader, 8 ); - ret = m_pSpdyCnn->cacheWritev( *pIov ); + ret = m_pSpdyConn->cacheWritev( *pIov ); + pIov->pop_front( 1 ); if ( D_ENABLED( DL_LESS )) { LOG_D(( getLogger(), "[%s] SpdyStream::sendData(), total: %d, ret: %d", @@ -296,11 +308,13 @@ int SpdyStream::sendData( IOVec * pIov, int total ) return -1; } bytesSent( total ); - m_iBytesAllowSend -= total; + m_pSpdyConn->dataFrameSent( total ); if ( isFlowCtrl() ) + { m_iWindowOut -= total; - if ( m_iBytesAllowSend <= 0 ) - setFlag( HIO_FLAG_BUFF_FULL, 1 ); + if ( m_iWindowOut <= 0 ) + setFlag( HIO_FLAG_BUFF_FULL, 1 ); + } return total; } @@ -309,8 +323,29 @@ int SpdyStream::sendHeaders( IOVec &vector, int headerCount ) { if ( getState() == HIOS_DISCONNECTED ) return -1; - m_pSpdyCnn->move2ReponQue(this); - return m_pSpdyCnn->sendRespHeaders(vector, headerCount, m_uiStreamID); + m_pSpdyConn->move2ReponQue(this); + return m_pSpdyConn->sendRespHeaders(vector, headerCount, m_uiStreamID); +} + +int SpdyStream::adjWindowOut( int32_t n ) +{ + if ( isFlowCtrl() ) + { + m_iWindowOut += n; + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] stream WINDOW_UPDATE: %d, window size: %d ", + getLogId(), n, m_iWindowOut ) ); + } + if ( m_iWindowOut < 0 ) + { + //window overflow + return -1; + } + else if ( isWantWrite() ) + continueWrite(); + } + return 0; } diff --git a/src/spdy/spdystream.h b/src/spdy/spdystream.h index 0e96ea41b..0abbeaceb 100644 --- a/src/spdy/spdystream.h +++ b/src/spdy/spdystream.h @@ -36,7 +36,7 @@ class SpdyStream: public DLinkedObj, public HioStream ~SpdyStream(); int init(uint32_t StreamID, - int Priority, SpdyConnection* pSpdyCnn, uint8_t Spdy_Flags, HioStreamHandler * pHandler ); + int Priority, SpdyConnection* pSpdyConn, uint8_t Spdy_Flags, HioStreamHandler * pHandler ); int onInitConnected(); int getPriority() const @@ -79,7 +79,7 @@ class SpdyStream: public DLinkedObj, public HioStream int isFlowCtrl() const { return getFlag( HIO_FLAG_FLOWCTRL ); } int32_t getWindowOut() const { return m_iWindowOut; } - void adjWindowOut( int32_t n ) { m_iWindowOut += n; } + int adjWindowOut( int32_t n ); int32_t getWindowIn() const { return m_iWindowIn; } void adjWindowIn( int32_t n ) { m_iWindowIn += n; } @@ -91,6 +91,9 @@ class SpdyStream: public DLinkedObj, public HioStream return m_bufIn.append(pData, len); } + int getDataFrameSize( int wanted ); + + void appendInputData( char ch ) { return m_bufIn.append( ch ); @@ -114,10 +117,9 @@ class SpdyStream: public DLinkedObj, public HioStream private: uint32_t m_uiStreamID; int m_iPriority; - int m_iBytesAllowSend; int32_t m_iWindowOut; int32_t m_iWindowIn; - SpdyConnection* m_pSpdyCnn; + SpdyConnection* m_pSpdyConn; LoopBuf m_bufIn; }; diff --git a/src/ssi/ssiruntime.h b/src/ssi/ssiruntime.h index 1fa9c09bf..8593784ec 100644 --- a/src/ssi/ssiruntime.h +++ b/src/ssi/ssiruntime.h @@ -36,7 +36,7 @@ class SSIRuntime{ ~SSIRuntime(); void init() - { m_pCurScript = &m_stack[-1]; } + { m_pCurScript = &m_stack[0] -1; } int push( SSIScript *pScript ) { @@ -50,14 +50,14 @@ class SSIRuntime{ } void pop() - { if ( m_pCurScript > &m_stack[-1] ) + { if ( m_pCurScript > &m_stack[0] -1 ) -- m_pCurScript; } int full() { return m_pCurScript >= &m_stack[SSI_STACK_SIZE]; } int done() - { return m_pCurScript == &m_stack[-1]; } + { return m_pCurScript == &m_stack[0] -1; } int initConfig( SSIConfig * pConfig ); diff --git a/src/sslpp/sslconnection.cpp b/src/sslpp/sslconnection.cpp index c5fe1b52c..14247abdd 100644 --- a/src/sslpp/sslconnection.cpp +++ b/src/sslpp/sslconnection.cpp @@ -278,19 +278,22 @@ SSL_SESSION * SSLConnection::getSession() const const char * SSLConnection::getVersion() const { return SSL_get_version( m_ssl ); } +static const char NPN_SPDY_PREFIX[] = { 's', 'p', 'd', 'y', '/' }; int SSLConnection::getSpdyVersion() { int v = 0; #ifdef LS_ENABLE_SPDY #ifdef TLSEXT_TYPE_next_proto_neg - const char * NEXT_PROTO_NEGOTIATED_PREFIX = "spdy/"; unsigned int len; const unsigned char *data; SSL_get0_next_proto_negotiated(m_ssl, &data, &len); - if (len > strlen(NEXT_PROTO_NEGOTIATED_PREFIX) && - strncasecmp((const char *)data, NEXT_PROTO_NEGOTIATED_PREFIX, strlen(NEXT_PROTO_NEGOTIATED_PREFIX)) == 0) { - v = data[strlen(NEXT_PROTO_NEGOTIATED_PREFIX)] - '0' -1; + if (len > sizeof( NPN_SPDY_PREFIX ) && + strncasecmp((const char *)data, NPN_SPDY_PREFIX, sizeof( NPN_SPDY_PREFIX ) ) == 0) + { + v = data[ sizeof( NPN_SPDY_PREFIX ) ] - '1'; + if (( v == 2 )&&( len >= 8 )&&( data[6] == '.')&&( data[7] == '1')) + v = 3; return v; } #endif diff --git a/src/sslpp/sslcontext.cpp b/src/sslpp/sslcontext.cpp index 818548e6e..9e1ae5733 100644 --- a/src/sslpp/sslcontext.cpp +++ b/src/sslpp/sslcontext.cpp @@ -778,13 +778,13 @@ int SSLContext::addCRL( const char * pCRLFile, const char * pCRLPath) static const char * NEXT_PROTO_STRING[3] = { "\x06spdy/2\x08http/1.1\x08http/1.0", - "\x06spdy/3\x08http/1.1\x08http/1.0", - "\x06spdy/3\x06spdy/2\x08http/1.1\x08http/1.0" + "\x08spdy/3.1\x06spdy/3\x08http/1.1\x08http/1.0", + "\x08spdy/3.1\x06spdy/3\x06spdy/2\x08http/1.1\x08http/1.0" }; static int NEXT_PROTO_STRING_LEN[3] = { - 25, 25, 32 + 25, 34, 41 }; //static const char NEXT_PROTO_STRING[] = "\x06spdy/2\x08http/1.1\x08http/1.0"; diff --git a/src/util/ghash.cpp b/src/util/ghash.cpp index 9280a0c92..7ce3fcfc6 100644 --- a/src/util/ghash.cpp +++ b/src/util/ghash.cpp @@ -191,7 +191,7 @@ void GHash::clear() if ( n != (int)m_size ) { fprintf( stderr, "GHash::clear() error: n=%d, m_size=%d!\n", - n, m_size ); + n, (int)m_size ); } ::memset( m_table, 0, sizeof( HashElem* ) * m_capacity ); m_size = 0; diff --git a/src/util/sysinfo/linux_nicdetect.cpp b/src/util/sysinfo/linux_nicdetect.cpp index 09980d9f8..c4f900b32 100644 --- a/src/util/sysinfo/linux_nicdetect.cpp +++ b/src/util/sysinfo/linux_nicdetect.cpp @@ -37,11 +37,17 @@ struct ifi_info * parse_proc_net() { return NULL; } - int ret = nio_read( fd, achBuf, sizeof( achBuf ) - 1 ); + int ret, total = 0; + while( (ret = nio_read( fd, &achBuf[total], sizeof( achBuf ) - total - 1 )) > 0 ) + { + total += ret; + if ( total >= (int)sizeof( achBuf ) - 1 ) + break; + } nio_close( fd ); struct sockaddr_in6 addr; - char * pEnd = &achBuf[ret]; + char * pEnd = &achBuf[total]; char * pLineEnd; char * p = achBuf; *pEnd = 0; diff --git a/v1.2 b/v1.2 new file mode 100644 index 000000000..90b23fe8b --- /dev/null +++ b/v1.2 @@ -0,0 +1 @@ +a13a40c..cf636a7: command not found