Initial import from svn
authorEbersold <aebersol@n3150.home>
Wed, 22 Dec 2021 20:08:12 +0000 (21:08 +0100)
committerEbersold <aebersol@n3150.home>
Wed, 22 Dec 2021 20:08:12 +0000 (21:08 +0100)
73 files changed:
.gitmodules [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
data-models/CMakeLists.txt [new file with mode: 0644]
data-models/reverse_proxy.xsd [new file with mode: 0644]
rules [new submodule]
utils [new submodule]
wsproxy/CMakeLists.txt [new file with mode: 0644]
wsproxy/TODO.txt [new file with mode: 0644]
wsproxy/config/wsproxy.xml [new file with mode: 0644]
wsproxy/config/wsproxy_plugin.xml [new file with mode: 0644]
wsproxy/jsTerm-master/LICENSE [new file with mode: 0644]
wsproxy/jsTerm-master/README [new file with mode: 0644]
wsproxy/jsTerm-master/example/index.html [new file with mode: 0755]
wsproxy/jsTerm-master/example/palawan.html [new file with mode: 0755]
wsproxy/jsTerm-master/fonts/ansilove_font_pc_80x25.png [new file with mode: 0644]
wsproxy/jsTerm-master/src/Term.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/AnsiParser.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/ByteArray.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/CharacterCodes.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/EscapeSequencer.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/Keyboard.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/NVTCodes.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/SixteenColors.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/parser/Telnet.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/telnet/Session.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/telnet/Socket.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/viewer/AnsiViewer.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/viewer/Cursor.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/viewer/Font.js [new file with mode: 0644]
wsproxy/jsTerm-master/src/viewer/Point.js [new file with mode: 0644]
wsproxy/main.cpp [new file with mode: 0644]
wsproxy/plugins/CMakeLists.txt [new file with mode: 0644]
wsproxy/plugins/plugin_auth.h [new file with mode: 0644]
wsproxy/plugins/plugin_default.cpp [new file with mode: 0644]
wsproxy/plugins/plugin_default.h [new file with mode: 0644]
wsproxy/plugins/plugin_log.cpp [new file with mode: 0644]
wsproxy/plugins/plugin_log.h [new file with mode: 0644]
wsproxy/plugins/plugin_ssl.cpp [new file with mode: 0644]
wsproxy/plugins/plugin_ssl.h [new file with mode: 0644]
wsproxy/plugins/plugin_ws.cpp [new file with mode: 0644]
wsproxy/plugins/plugin_ws.h [new file with mode: 0644]
wsproxy/ressources/echo.html [new file with mode: 0644]
wsproxy/ressources/oxo.html [new file with mode: 0644]
wsproxy/sha1.cpp [new file with mode: 0755]
wsproxy/sha1.h [new file with mode: 0755]
wsproxy/test.html [new file with mode: 0644]
wsproxy/ws_acceptor.cpp [new file with mode: 0644]
wsproxy/ws_acceptor.h [new file with mode: 0644]
wsproxy/ws_allocator.h [new file with mode: 0644]
wsproxy/ws_base64.cpp [new file with mode: 0644]
wsproxy/ws_base64.h [new file with mode: 0644]
wsproxy/ws_conn_handler.h [new file with mode: 0644]
wsproxy/ws_constant.h [new file with mode: 0644]
wsproxy/ws_frame.cpp [new file with mode: 0644]
wsproxy/ws_frame.h [new file with mode: 0644]
wsproxy/ws_handler.h [new file with mode: 0644]
wsproxy/ws_handler_factory.cpp [new file with mode: 0644]
wsproxy/ws_handler_factory.h [new file with mode: 0644]
wsproxy/ws_http_handler.h [new file with mode: 0644]
wsproxy/ws_http_header.cpp [new file with mode: 0644]
wsproxy/ws_http_header.h [new file with mode: 0644]
wsproxy/ws_https_handler.h [new file with mode: 0644]
wsproxy/ws_log.cpp [new file with mode: 0644]
wsproxy/ws_log.h [new file with mode: 0644]
wsproxy/ws_plugin.h [new file with mode: 0644]
wsproxy/ws_plugin_manager.cpp [new file with mode: 0644]
wsproxy/ws_plugin_manager.h [new file with mode: 0644]
wsproxy/ws_plugin_request.h [new file with mode: 0644]
wsproxy/ws_proxy_endpoint.cpp [new file with mode: 0644]
wsproxy/ws_proxy_endpoint.h [new file with mode: 0644]
wsproxy/ws_proxy_handler.cpp [new file with mode: 0644]
wsproxy/ws_proxy_handler.h [new file with mode: 0644]
xml-transform [new submodule]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..cc376c5
--- /dev/null
@@ -0,0 +1,9 @@
+[submodule "rules"]
+       path = rules
+       url = https://git.ebersold.fr/repos/rules.git
+[submodule "utils"]
+       path = utils
+       url = https://git.ebersold.fr/repos/aebutils.git
+[submodule "xml-transform"]
+       path = xml-transform
+       url = https://git.ebersold.fr/repos/xml-transform.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..26bbef5
--- /dev/null
@@ -0,0 +1,26 @@
+PROJECT(wsproxy-root)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.8)
+
+LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/rules")
+
+SUBDIRS(rules utils xml-transform wsproxy data-models)
+
+INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR})
+
+#
+# Try generation of configuration reader
+#
+FIND_LIBRARY(EXPAT_LIB expat "/usr/local/lib:/usr/lib")
+INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
+FIND_LIBRARY(DL_LIB dl "/lib:/usr/local/lib:/usr/lib")
+
+INCLUDE_DIRECTORIES("${xml-t_SOURCE_DIR}/libxsd/include")
+INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/include")
+INCLUDE_DIRECTORIES(".")
+# Does not work under ubuntu cmake 2.8.7 It says empty string !!!
+# INCLUDE_DIRECTORIES("${aebutils_SOURCE_DIR}")
+INCLUDE_DIRECTORIES("/usr/local/include")
+
+SET(SAXON CACHE STRING  "~/Tools/saxon/saxon9.jar")
+SET(XSD2CPP "${xml-t_SOURCE_DIR}/xsd2cpp.xsl")
+
diff --git a/data-models/CMakeLists.txt b/data-models/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1cd7385
--- /dev/null
@@ -0,0 +1,6 @@
+PROJECT(wsproxy-dm)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.8)
+
+LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/rules")
+
+
diff --git a/data-models/reverse_proxy.xsd b/data-models/reverse_proxy.xsd
new file mode 100644 (file)
index 0000000..a0a0dd5
--- /dev/null
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema 
+    targetNamespace="http://www.ale.com/oxo/config/wsproxy" 
+    xmlns="http://www.ale.com/oxo/config/wsproxy" 
+    xmlns:tconfig="http://www.ale.com/oxo/config/wsproxy"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    elementFormDefault="unqualified" >
+
+    <xsd:simpleType name="UrlType">
+               <xsd:restriction base="xsd:string">
+                       <xsd:enumeration value="http" />
+                       <xsd:enumeration value="https" />
+                       <xsd:enumeration value="ws" />
+                       <xsd:enumeration value="wss" />
+                       <xsd:enumeration value="ftp" />
+                       <xsd:enumeration value="ftps" />
+                       <xsd:enumeration value="xmpp" />
+                       <xsd:enumeration value="xmpps" />
+               </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="AuthType">
+               <xsd:restriction base="xsd:string">
+                       <xsd:enumeration value="none" />
+                       <xsd:enumeration value="basic" />
+               </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name='AuthorizationType'>
+               <xsd:restriction base="xsd:string">
+                       <xsd:enumeration value="wan" />
+                       <xsd:enumeration value="https" />
+                       <xsd:enumeration value="http" />
+               </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="ListAuthorization">
+        <xsd:list itemType="AuthorizationType" />
+    </xsd:simpleType>
+    
+    <xsd:simpleType name="ListGateway">
+        <xsd:list itemType="xsd:string" />
+    </xsd:simpleType>
+    
+    <xsd:simpleType name="LogLevel">
+               <xsd:restriction base="xsd:string">
+                       <xsd:enumeration value="EMERG" />
+                       <xsd:enumeration value="ALERT" />
+                       <xsd:enumeration value="CRIT" />
+                       <xsd:enumeration value="ERROR" />
+                       <xsd:enumeration value="WARNING" />
+                       <xsd:enumeration value="NOTICE" />
+                       <xsd:enumeration value="DEBUG" />
+               </xsd:restriction>
+    </xsd:simpleType>
+
+
+    <xsd:complexType name="SessionTrackingType">
+        <xsd:simpleContent>
+            <xsd:extension base="xsd:string">
+                <xsd:attribute name="active" type="xsd:boolean"/>
+                <xsd:attribute name="max_inactive" type="xsd:integer"/>
+                <xsd:attribute name="max_simultaneous" type="xsd:integer"/>
+            </xsd:extension>
+      </xsd:simpleContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="AccessFilterType">
+      <xsd:simpleContent>
+          <xsd:extension base="xsd:string">
+              <xsd:attribute name="authorize" type="ListAuthorization"/>
+              <!-- gateways should be a list -->
+              <xsd:attribute name="gateway" type="ListGateway"/>
+              <xsd:attribute name="dynamic" type="xsd:integer"/>
+        </xsd:extension>
+      </xsd:simpleContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="SubdirType">
+        <xsd:sequence>
+            <xsd:element name="user" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
+        </xsd:sequence>
+        <xsd:attribute name='stealth' type="xsd:integer"/>
+        <xsd:attribute name='dir' type="xsd:string"/>
+        <xsd:attribute name='auth' type="AuthType"/>
+    </xsd:complexType>
+
+
+    <xsd:complexType name="AccessRightsType">
+        <xsd:simpleContent>
+            <xsd:restriction base="xsd:string">
+                          <xsd:enumeration value="R" />
+                          <xsd:enumeration value="W" />
+            </xsd:restriction>
+        </xsd:simpleContent>
+    </xsd:complexType>
+
+
+    <xsd:complexType name="FileServerType">
+        <xsd:simpleContent>
+            <xsd:extension base="xsd:string">
+                <xsd:attribute name='rights' type="AccessRightsType"/>
+            </xsd:extension>
+      </xsd:simpleContent>
+    </xsd:complexType>
+    
+    <xsd:complexType name="PluginType">
+        <xsd:simpleContent>
+            <xsd:extension base="xsd:string">
+                <xsd:attribute name='name' type="xsd:string"/>
+                <xsd:attribute name='load' type="xsd:string"/>
+            </xsd:extension>
+      </xsd:simpleContent>
+    </xsd:complexType>
+    
+    <xsd:complexType name="ParamType">
+        <xsd:simpleContent>
+            <xsd:extension base="xsd:string">
+                <xsd:attribute name='name' type="xsd:string" />
+                <xsd:attribute name='value' type="xsd:string"/>
+            </xsd:extension>
+      </xsd:simpleContent>
+    </xsd:complexType>
+
+
+
+    <xsd:complexType name="ApplicationType">
+        <xsd:sequence>
+            <xsd:choice>
+                <xsd:element name='filter' type="xsd:string">
+                  <xsd:annotation>
+                    <xsd:documentation>
+                        Field that defines the path of the request. Ex: /app/toto
+                    </xsd:documentation>
+                  </xsd:annotation>
+                </xsd:element>
+                <xsd:element name='file_server' type="FileServerType"/>
+            </xsd:choice>
+            <xsd:element name='destination' type="xsd:string" minOccurs="1" maxOccurs="1">
+              <xsd:annotation>
+                <xsd:documentation>
+                    Field that defines the backend port and address. This parameter is in conflict with attribute host and port !!!
+                    It would be good to see how we could define an unix socket name.
+                </xsd:documentation>
+              </xsd:annotation>
+            </xsd:element>
+            <xsd:element name='access_filter' type="AccessFilterType"/>
+            <xsd:element name='session_tracking' type="SessionTrackingType"/>
+            <xsd:element name='sub_dir' type="xsd:string" maxOccurs="unbounded"/>
+            <xsd:element name='param' type='ParamType' maxOccurs="unbounded"/>
+        </xsd:sequence>
+        <xsd:attribute name="name" type='xsd:string'  minOccurs="0"/>
+        <xsd:attribute name="host" type="xsd:string"  minOccurs="0"/>
+        <xsd:attribute name="port" type="xsd:integer" minOccurs="0"/>
+        <!-- The flow is binary or text. Need to be removed when code will be inline again -->
+        <xsd:attribute name="flow" type="xsd:string" default="text"/>
+        <xsd:attribute name="max_frame_size" type="xsd:integer" use="required" default="65535"/>
+    </xsd:complexType>
+
+    <!-- This is my point of view -->
+    <xsd:complexType name="GatewayType">
+        <xsd:sequence>
+            <xsd:element name="host"        type="xsd:string"/>
+            <xsd:element name="port"        type="xsd:integer"/>
+            <xsd:element name="schema"      type="UrlType"/>
+            <xsd:element name="certfile"    type="xsd:string" minOccurs="0"/>
+        </xsd:sequence>
+        <xsd:attribute name="name" type="xsd:string"/>
+        <xsd:attribute name="queue" type="xsd:integer"/>
+    </xsd:complexType>
+
+    <xsd:complexType name="ReverseProxyType">
+      <xsd:sequence>
+          <xsd:element name="application" type="ApplicationType" maxOccurs="unbounded"/>
+      </xsd:sequence>
+    </xsd:complexType>
+    <!-- Web Socket new -->
+
+  <xsd:complexType name="WsApplicationType">
+        <xsd:sequence>
+            <xsd:element name="schema"      type="UrlType"/>
+            <xsd:element name="certfile"    type="xsd:string" minOccurs="0"/>
+        </xsd:sequence>
+        <xsd:attribute name="name" type="xsd:string"/>
+        <xsd:attribute name="host" type="xsd:string"/>
+        <xsd:attribute name="port" type="xsd:integer"/>
+        <!-- The flow is binary or text -->
+        <xsd:attribute name="flow" type="xsd:string" default="text"/>
+        <xsd:attribute name="max_frame_size" type="xsd:integer" use="required" default="65535"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="WebSocketType">
+      <xsd:sequence>
+          <xsd:element name="application" type="WsApplicationType" maxOccurs="unbounded"/>
+      </xsd:sequence>
+  </xsd:complexType>
+  
+  <xsd:complexType name="LogType">
+      <xsd:sequence>
+          <xsd:element name="file" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+      </xsd:sequence>
+        <xsd:attribute name="name" type="xsd:string"/>
+        <xsd:attribute name="level" type="LogLevel"/>
+        <xsd:attribute name="syslog" type="xsd:boolean"/>
+  </xsd:complexType>
+
+  <!-- Plugins stuff -->
+  
+  <xsd:complexType name="PluginsType">
+      <xsd:sequence>
+          <xsd:element name="plugin" type="PluginType" maxOccurs="unbounded"/>
+      </xsd:sequence>
+  </xsd:complexType>
+  
+  <!-- Global settings-->
+  <xsd:complexType name="GlobalType">
+      <xsd:sequence>
+          <xsd:element name="log" type="LogType" maxOccurs="unbounded"/>
+          <xsd:element name="workers" type="xsd:integer" minOccurs="0" maxOccurs="1" default="1"/>
+          <xsd:element name="user" type="xsd:string" maxOccurs="1" default="root">
+              <xsd:annotation>
+                  <xsd:documentation>
+                      Defines the user name the process should have once running.
+                  </xsd:documentation>
+              </xsd:annotation>
+          </xsd:element>
+          <xsd:element name="group" type="xsd:string" maxOccurs="1" default="root">
+              <xsd:annotation>
+                  <xsd:documentation>
+                      Defines the group name the process should have once running.
+                  </xsd:documentation>
+              </xsd:annotation>
+          </xsd:element>
+      </xsd:sequence>
+  </xsd:complexType>
+   
+   <!--  Main entry .... -->
+    <xsd:complexType name="ConfigurationType">
+        <xsd:sequence>
+            <xsd:element name="global" type="GlobalType" maxOccurs="1"/>
+            <xsd:element name="plugins" type="PluginsType" minOccurs="0" maxOccurs="1"/>
+            <xsd:element name="listen" type="GatewayType" maxOccurs="unbounded"/>
+            <xsd:element name="rproxy" type="ReverseProxyType" maxOccur="1"/>
+            <xsd:element name="websocket" type="WebSocketType" maxOccur="1"/>
+        </xsd:sequence>
+    </xsd:complexType>
+    <xsd:element name="CONFIGURATION" type="ConfigurationType"/>
+</xsd:schema>
diff --git a/rules b/rules
new file mode 160000 (submodule)
index 0000000..aeca878
--- /dev/null
+++ b/rules
@@ -0,0 +1 @@
+Subproject commit aeca878a84169490996e427211493ac306f00c7c
diff --git a/utils b/utils
new file mode 160000 (submodule)
index 0000000..5f6e913
--- /dev/null
+++ b/utils
@@ -0,0 +1 @@
+Subproject commit 5f6e9134ab67b61537fc0bf557842221001f76b1
diff --git a/wsproxy/CMakeLists.txt b/wsproxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ca1adb1
--- /dev/null
@@ -0,0 +1,72 @@
+PROJECT(wsproxy)
+
+INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR})
+
+#
+# Try generation of configuration reader
+#
+FIND_LIBRARY(EXPAT_LIB expat "/usr/local/lib:/usr/lib")
+INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
+FIND_LIBRARY(DL_LIB dl "/lib:/usr/local/lib:/usr/lib")
+
+INCLUDE_DIRECTORIES("${xml-t_SOURCE_DIR}/libxsd/include")
+INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/include")
+INCLUDE_DIRECTORIES(".")
+INCLUDE_DIRECTORIES("${aebutils_SOURCE_DIR}")
+INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR}/aeb)
+INCLUDE_DIRECTORIES(${libltdl_SOURCE_DIR})
+INCLUDE_DIRECTORIES("/usr/local/include")
+
+SUBDIRS(plugins)
+
+SET(SAXON CACHE STRING  "~/Tools/saxon/saxon9.jar")
+SET(XSD2CPP "${xml-t_SOURCE_DIR}/xsd2cpp.xsl")
+SET(PROFILE
+    "${wsproxy-root_SOURCE_DIR}/data-models/reverse_proxy.xsd")
+
+
+ADD_CUSTOM_COMMAND(
+    SOURCE ${PROFILE}
+    COMMAND java 
+    ARGS -jar ${SAXON} -s ${PROFILE} -xsl:${XSD2CPP}
+    rootdir="./parser/"
+    target="release" root-element="CONFIGURATION"
+    shared-ptr="aeb" incdir="/../include"
+    srcdir="./"
+    OUTPUT 
+        ${CMAKE_CURRENT_BINARY_DIR}/parser/p_reverse_proxy.cpp
+        ${CMAKE_CURRENT_BINARY_DIR}/parser/reverse_proxy.cpp
+    COMMENT "Transform reverse_proxy.xsd"
+)
+
+
+
+
+ADD_EXECUTABLE(wsproxy
+  main.cpp
+  ws_proxy_handler.cpp
+  ws_proxy_endpoint.cpp
+  ws_handler_factory.cpp
+  ws_http_header.cpp
+  ws_acceptor.cpp
+  ws_base64.cpp
+  ws_frame.cpp
+  ws_log.cpp
+  sha1.cpp
+  ws_plugin_manager.cpp
+  ${CMAKE_CURRENT_BINARY_DIR}/parser/reverse_proxy.cpp
+  ${CMAKE_CURRENT_BINARY_DIR}/parser/p_reverse_proxy.cpp
+)
+
+TARGET_LINK_LIBRARIES(wsproxy ltdl libxsd ${EXPAT_LIB})
+
+IF( UNIX )
+ELSE (UNIX )
+  TARGET_LINK_LIBRARIES(ip4_server ws2_32)
+ENDIF (UNIX )
+
+
+
+INSTALL(TARGETS wsproxy DESTINATION bin
+    COMPONENT wsproxy
+    )
diff --git a/wsproxy/TODO.txt b/wsproxy/TODO.txt
new file mode 100644 (file)
index 0000000..80ea61a
--- /dev/null
@@ -0,0 +1,49 @@
+2015/09/22:
+-----------
+ - TODO create ws_handler abstract class
+ - TODO create ws_connection_handler class ( handles connection state,
+   CONNECTING,OPEN,CLOSING,CLOSED) decides if http or https according to
+   config
+ - TODO move ws logic into plugin_ws
+ - TODO plugin configuration management ... 
+ - TODO backend class seems to be ws_proxy_endpoint ...
+ - TODO servlet support
+ - TODO fastcgi support
+ - TODO auth module support
+2015/07/28:
+-----------
+ - CMake installer
+2014/12/04:
+-----------
+ - DONE telnet seems to work pretty well.
+ - DONE log information in configuration file
+ - frame limit check must be finalized.
+ - Packaging ...
+ - Documentation on the web site would be of great help as well.
+ - add a factory for handlers ws_handler_factory.  So that I can leave in
+   peace.
+ - improve aeb lib to support SSL / TLS 
+ - improve http header analysis (Origin, Cookies, Host)
+ - Authentication mechanism SASL, Basic Auth ....
+ - Add statistics number of connections, inbound / outbound flow ....
+2014/11/24:
+-----------
+ - DONE include base64 functions 
+ - DONE include sha-1 encoding functions
+ - DONE add configuration file
+ - I think a class ws_http_header would be good to handle WS HTTP initiation
+ - Improve error handling (exception or return code) when dealing with sockets
+   and streams
+ - integrate telnet example for proof of concept
+ - don't forget installer
+ - check if logging information are defined in configuration file log level,
+   log file, log syslog...
+ - check 
+2014/11/19:
+-----------
+ - There is a need for a logger.
+ - remove the traces in aeb/net
+ - include base64 functions
+ - include sha-1 encoding functions
+ - add configuration file
+ - implement end point class
diff --git a/wsproxy/config/wsproxy.xml b/wsproxy/config/wsproxy.xml
new file mode 100644 (file)
index 0000000..b97f6f6
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<CONFIGURATION>
+    <global>
+        <log name="wsproxy" level="DEBUG" syslog="true"></log>
+        <log name="ws_proxy_handler" level="DEBUG" syslog="false"></log>
+        <log name="ws_proxy_endpoint" level="WARNING" syslog="false"></log>
+        <log name="ws_handler_factory" level="WARNING" syslog="false"></log>
+        <log name="ws_acceptor" level="WARNING" syslog="false"></log>
+        <log name="ws_frame" level="DEBUG" syslog="false"></log>
+        <user>aebersol</user>
+        <group>users</group>
+    </global>
+    <listen>
+        <host>localhost</host>
+        <port>10323</port>
+        <certfile>test.cert</certfile>
+    </listen>
+    <!-- Reverse proxy backends -->
+    <rproxy>
+        <application name="csta" host="172.25.16.146" port="2555" flow="binary"></application>
+        <application name="telnet" host="172.25.16.146" port="22" flow="binary"></application>
+        <application name="sip" host="172.25.16.146" port="5060" flow="text"></application>
+    </rproxy>
+    <websocket>
+        <application name="csta" host="172.25.16.146" port="2555" flow="binary"></application>
+    </websocket>
+</CONFIGURATION>
diff --git a/wsproxy/config/wsproxy_plugin.xml b/wsproxy/config/wsproxy_plugin.xml
new file mode 100644 (file)
index 0000000..509e324
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<CONFIGURATION>
+    <global>
+        <log name="wsproxy" level="DEBUG" syslog="true"></log>
+        <log name="ws_proxy_handler" level="DEBUG" syslog="false"></log>
+        <log name="ws_proxy_endpoint" level="WARNING" syslog="false"></log>
+        <log name="ws_handler_factory" level="WARNING" syslog="false"></log>
+        <log name="ws_acceptor" level="DEBUG" syslog="false"></log>
+        <log name="ws_frame" level="DEBUG" syslog="false"></log>
+        <user>aebersol</user>
+        <group>users</group>
+    </global>
+    <plugins>
+        <plugin name="default" load="libplugin_default"/>
+        <plugin name="SSL" load="libplugin_log"/>
+    </plugins>
+    <listen name="lan" queue="5">
+        <host>localhost</host>
+        <port>8082</port>
+        <certfile>test.cert</certfile>
+    </listen>
+    <listen name="wan" queue="15">
+        <host>localhost</host>
+        <port>11323</port>
+        <certfile>test.cert</certfile>
+    </listen>
+    <!-- Reverse proxy backends -->
+    <rproxy>
+        <application name="csta" host="172.25.16.146" port="2555" >
+            <filter>/services/</filter>
+            <access_filter gateway="wan"></access_filter>
+            <param name="DefaultEnabled" value="on"/>
+            <param name="DefaultAction" value="on"/>
+            <param name="AuthType" value="basic"/>
+        </application>
+        <application name="telnet" host="172.25.16.146" port="22" >
+            <filter>/services/telnet</filter>
+            <access_filter gateway="lan"></access_filter>
+        </application>
+        <application name="xmlOxo" host="localhost" port="22" >
+            <filter>/services/XmlPhone</filter>
+            <access_filter gateway="lan wan"></access_filter>
+        </application>
+        <application name="xmlAdmin" host="172.25.16.146" port="22" >
+            <filter>/services/XmlAdmin</filter>
+            <access_filter gateway="lan"></access_filter>
+        </application>
+        <application name="IcsLocator" host="172.25.16.146" port="8894" ></application>
+    </rproxy>
+    <websocket>
+        <application name="csta" host="172.25.16.146" port="2556" flow="binary"></application>
+        <application name="sip" host="172.25.16.146" port="5060" flow="text"></application>
+    </websocket>
+</CONFIGURATION>
diff --git a/wsproxy/jsTerm-master/LICENSE b/wsproxy/jsTerm-master/LICENSE
new file mode 100644 (file)
index 0000000..ce2a40c
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Peter Nitsch
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/README b/wsproxy/jsTerm-master/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/wsproxy/jsTerm-master/example/index.html b/wsproxy/jsTerm-master/example/index.html
new file mode 100755 (executable)
index 0000000..d4647e7
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+<head>
+  <title>jsTerm Example</title>
+  <script src='../src/Term.js'></script>
+  <script src='../src/parser/Keyboard.js'></script>
+  <script src='../src/parser/CharacterCodes.js'></script>
+  <script src='../src/parser/SixteenColors.js'></script>
+  <script src='../src/parser/ByteArray.js'></script>
+  <script src='../src/parser/EscapeSequencer.js'></script>
+  <script src='../src/parser/AnsiParser.js'></script>
+  <script src='../src/parser/NVTCodes.js'></script>
+  <script src='../src/parser/Telnet.js'></script>
+  <script src='../src/viewer/Point.js'></script>
+  <script src='../src/viewer/Font.js'></script>
+  <script src='../src/viewer/Cursor.js'></script>
+  <script src='../src/viewer/AnsiViewer.js'></script>
+  <script src='../src/telnet/Socket.js'></script>
+  <script src='../src/telnet/Session.js'></script>
+
+  <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'></script>
+  <script>
+       $(document).ready(function(){
+
+               var session = new TERM.Session("../fonts/ansilove_font_pc_80x25.png");
+               var host = document.getElementById("host");
+               var port = document.getElementById("port");
+               var connect = document.getElementById("connect");
+               var bookmarks = document.getElementById("bookmarks");
+
+               connect.onclick = function() {
+                       session.connect(host.value, port.value);
+               }
+
+               bookmarks.onchange = function() {
+                       var val = bookmarks.value;
+                       if(val!=""){
+                               var i = val.indexOf(":");
+                               host.value = val.slice(0, i);
+                               port.value = val.slice(i+1, val.length);
+                       }
+               }
+
+       });
+  </script>
+</head>
+<body>
+               <div id="terminal"><canvas id="canvas" width="650" height="440"></canvas> </div>
+
+               <div id="panel">
+                       <select id="bookmarks" name="bookmarks">
+                       <option value="">- Bookmarks -</option>
+                       <option value="towel.blinkenlights.nl:23">towel.blinkenlights.nl</option>
+                       <option value="vert.synchro.net:23">vert.synchro.net</option>
+                       <option value="bbs.pharcyde.org:23">bbs.pharcyde.org</option>
+                       <option value="d1st.org:23">d1st.org</option>
+                       <option value="bbs.electronicchicken.com:23">bbs.electronicchicken.com</option>
+                       <option value="entropybbs.co.nz:23">entropybbs.co.nz</option>
+                       <option value="lunatic.zapto.org:23">lunatic.zapto.org</option>
+                       <option value="bbs.roughneckbbs.com:23">bbs.roughneckbbs.com</option>
+                       <option value="masqueradebbs.com:23">masqueradebbs.com</option>
+                       <option value="alecoexp.dyndns.org:23">alecoexp.dyndns.org</option>
+                       <option value="bluewavebbs.dyndns.org:23">bluewavebbs.dyndns.org</option>
+                       <option value="bbs.akroncdnr.com:23">bbs.akroncdnr.com</option>
+                       <option value="cbliss.synchro.net:23">cbliss.synchro.net</option>
+                       <option value="ds69bbs.com:23">ds69bbs.com</option>
+                       <option value="bbs.defcon.no:23">bbs.defcon.no</option>
+                       <option value="bbs.dmine.net:23">bbs.dmine.net</option>
+                       <option value="bbs.diskshop.ca:23">bbs.diskshop.ca</option>     
+                       <option value="eotd.com:23">eotd.com</option>
+                       <option value="flashpointbbs.no-ip.org:23">flashpointbbs.no-ip.org</option>
+                       <option value="fjbbs.gotdns.com:23">fjbbs.gotdns.com</option>
+                       <option value="isisunveiled.no-ip.org:23">isisunveiled.no-ip.org</option>
+                       <option value="bbs.zeusdev.co.uk:23">bbs.zeusdev.co.uk</option>
+                       <option value="musicstation.spb.ru:5223">musicstation.spb.ru</option>
+                       <option value="phybbs.dyndns.org:23">phybbs.dyndns.org</option>
+                       <option value="rdfig.net:23">rdfig.net</option>
+                       <option value="redhill.net.nz:4500">redhill.net.nz</option>
+                       <option value="bbs.dxrw.org:23">bbs.dxrw.org</option>
+                       <option value="bbs.scansoutheasternmass.com:23">bbs.scansoutheasternmass.com</option>
+                       <option value="thechangeosp.nl:23">thechangeosp.nl</option>
+                       <option value="darkside.dtdns.net:23">darkside.dtdns.net</option>
+                       <option value="white-squirrel.dnsalias.net:23">white-squirrel.dnsalias.net</option>
+                       <option value="wildcatcastle.gotdns.com:23">wildcatcastle.gotdns.com</option>
+                       <option value="bbs.zzap.org:23">bbs.zzap.org</option>
+                       </select>
+                       <input id="host" type="text" value="towel.blinkenlights.nl">
+                       <input id="port" type="text" value="23">
+                       <input id="connect" type="button" value="Connect">
+               </div>
+</body>
+</html>
diff --git a/wsproxy/jsTerm-master/example/palawan.html b/wsproxy/jsTerm-master/example/palawan.html
new file mode 100755 (executable)
index 0000000..d4647e7
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+<head>
+  <title>jsTerm Example</title>
+  <script src='../src/Term.js'></script>
+  <script src='../src/parser/Keyboard.js'></script>
+  <script src='../src/parser/CharacterCodes.js'></script>
+  <script src='../src/parser/SixteenColors.js'></script>
+  <script src='../src/parser/ByteArray.js'></script>
+  <script src='../src/parser/EscapeSequencer.js'></script>
+  <script src='../src/parser/AnsiParser.js'></script>
+  <script src='../src/parser/NVTCodes.js'></script>
+  <script src='../src/parser/Telnet.js'></script>
+  <script src='../src/viewer/Point.js'></script>
+  <script src='../src/viewer/Font.js'></script>
+  <script src='../src/viewer/Cursor.js'></script>
+  <script src='../src/viewer/AnsiViewer.js'></script>
+  <script src='../src/telnet/Socket.js'></script>
+  <script src='../src/telnet/Session.js'></script>
+
+  <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'></script>
+  <script>
+       $(document).ready(function(){
+
+               var session = new TERM.Session("../fonts/ansilove_font_pc_80x25.png");
+               var host = document.getElementById("host");
+               var port = document.getElementById("port");
+               var connect = document.getElementById("connect");
+               var bookmarks = document.getElementById("bookmarks");
+
+               connect.onclick = function() {
+                       session.connect(host.value, port.value);
+               }
+
+               bookmarks.onchange = function() {
+                       var val = bookmarks.value;
+                       if(val!=""){
+                               var i = val.indexOf(":");
+                               host.value = val.slice(0, i);
+                               port.value = val.slice(i+1, val.length);
+                       }
+               }
+
+       });
+  </script>
+</head>
+<body>
+               <div id="terminal"><canvas id="canvas" width="650" height="440"></canvas> </div>
+
+               <div id="panel">
+                       <select id="bookmarks" name="bookmarks">
+                       <option value="">- Bookmarks -</option>
+                       <option value="towel.blinkenlights.nl:23">towel.blinkenlights.nl</option>
+                       <option value="vert.synchro.net:23">vert.synchro.net</option>
+                       <option value="bbs.pharcyde.org:23">bbs.pharcyde.org</option>
+                       <option value="d1st.org:23">d1st.org</option>
+                       <option value="bbs.electronicchicken.com:23">bbs.electronicchicken.com</option>
+                       <option value="entropybbs.co.nz:23">entropybbs.co.nz</option>
+                       <option value="lunatic.zapto.org:23">lunatic.zapto.org</option>
+                       <option value="bbs.roughneckbbs.com:23">bbs.roughneckbbs.com</option>
+                       <option value="masqueradebbs.com:23">masqueradebbs.com</option>
+                       <option value="alecoexp.dyndns.org:23">alecoexp.dyndns.org</option>
+                       <option value="bluewavebbs.dyndns.org:23">bluewavebbs.dyndns.org</option>
+                       <option value="bbs.akroncdnr.com:23">bbs.akroncdnr.com</option>
+                       <option value="cbliss.synchro.net:23">cbliss.synchro.net</option>
+                       <option value="ds69bbs.com:23">ds69bbs.com</option>
+                       <option value="bbs.defcon.no:23">bbs.defcon.no</option>
+                       <option value="bbs.dmine.net:23">bbs.dmine.net</option>
+                       <option value="bbs.diskshop.ca:23">bbs.diskshop.ca</option>     
+                       <option value="eotd.com:23">eotd.com</option>
+                       <option value="flashpointbbs.no-ip.org:23">flashpointbbs.no-ip.org</option>
+                       <option value="fjbbs.gotdns.com:23">fjbbs.gotdns.com</option>
+                       <option value="isisunveiled.no-ip.org:23">isisunveiled.no-ip.org</option>
+                       <option value="bbs.zeusdev.co.uk:23">bbs.zeusdev.co.uk</option>
+                       <option value="musicstation.spb.ru:5223">musicstation.spb.ru</option>
+                       <option value="phybbs.dyndns.org:23">phybbs.dyndns.org</option>
+                       <option value="rdfig.net:23">rdfig.net</option>
+                       <option value="redhill.net.nz:4500">redhill.net.nz</option>
+                       <option value="bbs.dxrw.org:23">bbs.dxrw.org</option>
+                       <option value="bbs.scansoutheasternmass.com:23">bbs.scansoutheasternmass.com</option>
+                       <option value="thechangeosp.nl:23">thechangeosp.nl</option>
+                       <option value="darkside.dtdns.net:23">darkside.dtdns.net</option>
+                       <option value="white-squirrel.dnsalias.net:23">white-squirrel.dnsalias.net</option>
+                       <option value="wildcatcastle.gotdns.com:23">wildcatcastle.gotdns.com</option>
+                       <option value="bbs.zzap.org:23">bbs.zzap.org</option>
+                       </select>
+                       <input id="host" type="text" value="towel.blinkenlights.nl">
+                       <input id="port" type="text" value="23">
+                       <input id="connect" type="button" value="Connect">
+               </div>
+</body>
+</html>
diff --git a/wsproxy/jsTerm-master/fonts/ansilove_font_pc_80x25.png b/wsproxy/jsTerm-master/fonts/ansilove_font_pc_80x25.png
new file mode 100644 (file)
index 0000000..98aa572
Binary files /dev/null and b/wsproxy/jsTerm-master/fonts/ansilove_font_pc_80x25.png differ
diff --git a/wsproxy/jsTerm-master/src/Term.js b/wsproxy/jsTerm-master/src/Term.js
new file mode 100644 (file)
index 0000000..b78bb67
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2010 Peter Nitsch
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author Peter Nitsch
+ * http://jsterm.com
+ * http://www.peternitsch.net
+ */
+
+var TERM = TERM || {
+       socket : null,
+       SERVER_URL : "172.25.16.146", // Your node.js server IP
+       SERVER_PORT : "10222", // Your node.js server port
+       VERSION : "0.1 alpha"
+};
diff --git a/wsproxy/jsTerm-master/src/parser/AnsiParser.js b/wsproxy/jsTerm-master/src/parser/AnsiParser.js
new file mode 100644 (file)
index 0000000..b008328
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.AnsiParser = function (viewer){
+       
+       var viewer = viewer;
+       var escapeCommand = [];
+       var bufferEscapeCommand = false;
+       
+       this.escapeCommands = new TERM.EscapeSequencer(viewer);
+       this._bytes;
+       
+       this.parse = function (bytes) {
+               
+               if( bytes != null ) 
+            this._bytes = new TERM.ByteArray(bytes);
+               while( this._bytes.bytesAvailable > 0 ){
+                       var result = this._bytes.readUnsignedByte();
+
+                       if( result == SUBSTITUTE) {                     
+                               break;
+                       } else {
+                               this.readByte( result );
+                       }
+               }
+
+               this._bytes.position = 0;
+        this._bytes = null;
+       };
+       
+       this._exceptionsLib = [];
+       this._exceptions = [];
+       
+       this.hasException = function( code ) {
+               if( this._exceptions.indexOf(code) != -1 )
+                       return true;
+               return false;
+       };
+       
+       this.writeException = function( code, callback ) {
+               if( !this.hasException(code) ){
+                       this._exceptionsLib[code] = callback;
+                       this._exceptions.push(code);
+               }
+       };
+       
+       this.readByte = function (b) {
+               if(b == ESCAPE) {
+                       escapeCommand = [];
+                       escapeCommand.push(b);
+                       bufferEscapeCommand = true;
+            this.escapeCommands.onRead(0,b);
+               } else {
+                       if(bufferEscapeCommand){
+                               escapeCommand.push(b);
+                this.escapeCommands.onRead(escapeCommand.length,b);
+                               if( this.escapeCommands.complete && this.escapeCommands.checkCommandAction(escapeCommand.length, b) ) {
+                                       this.escapeCommands.executeCommand(escapeCommand);
+                                       bufferEscapeCommand = false;
+                    this.escapeCommands.complete = false;
+                               }
+                       } else if( this.hasException(b) ) {
+                       console.log("TERM.AnsiParser.readByte "+b+" Has exception");
+                               this._exceptionsLib[b]( b, this._bytes );
+                       } else if(b >= SPACE) {
+                               viewer.drawCharacter(b);
+                       } else {
+                console.log("TERM.AnsiParser.readByte switch: "+b+ " type="+typeof(b));
+                               switch(parseInt(b)) {
+                                       case BACKSPACE:
+                                               viewer.moveBackward(1, true);
+                                       break;
+
+                                       case LINE_FEED:
+                                               viewer.carriageReturn();
+                                               viewer.moveDown(1);
+                                       break;
+
+                                       case CARRIAGE_RETURN:
+                                               viewer.carriageReturn();
+                                       break;
+
+                                       case FORM_FEED:
+                                               viewer.eraseScreen();
+                                               viewer.reposition(0, 0);
+                                       break;
+                    default:
+                               console.log("TERM.AnsiParser.readByte in switch default:");
+                                               //viewer.carriageReturn();
+                    ;
+                               }
+                       }
+               }
+       };
+       
+};
diff --git a/wsproxy/jsTerm-master/src/parser/ByteArray.js b/wsproxy/jsTerm-master/src/parser/ByteArray.js
new file mode 100644 (file)
index 0000000..27f41ba
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.ByteArray = function (bytes){
+       
+       this.position = 0;
+       this.stringdata = bytes.toString();
+       this.readview   = new Int8Array(bytes);
+    this.buffer     = bytes;
+       this.readUnsignedByte = function() {
+               // var b = this.stringdata.charCodeAt(this.position);
+           // alert(" readUnsignedByte enter at position :"+this.position +" / "+ this.bytesAvailable);        
+               var b = this.readview[this.position].toString(10);
+           //console.log(" readUnsignedByte return ="+b+" at position :"+this.position );      
+        if(this.position!=this.buffer.byteLength) this.position++;
+               return b;
+       };
+       
+       this.writeByte = function(){
+               // TO DO
+       };
+
+};
+
+TERM.ByteArray.prototype = {
+       
+       get bytesAvailable (){
+               return this.buffer.byteLength - this.position;
+       },
+       get length (){
+               return this.buffer.byteLength;
+       }
+       
+};
+
diff --git a/wsproxy/jsTerm-master/src/parser/CharacterCodes.js b/wsproxy/jsTerm-master/src/parser/CharacterCodes.js
new file mode 100644 (file)
index 0000000..e1684af
--- /dev/null
@@ -0,0 +1,260 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const NULL = 0
+const START_OF_HEADING = 1;
+const START_OF_TEXT = 2;
+const END_OF_TEXT = 3;
+const END_OF_TRANSMISSION = 4;
+const ENQUIRY = 5;
+const ACKNOWLEDGE = 6;
+const BELL = 7;
+const BACKSPACE = 8;
+const HORIZONTAL_TABULATION = 9;
+const LINE_FEED = 10;
+const VERTICAL_TABULATION = 11;
+const FORM_FEED = 12;
+const CARRIAGE_RETURN = 13;
+const SHIFT_OUT = 14;
+const SHIFT_IN = 15;
+const DATA_LINK_ESCAPE = 16;
+const DEVICE_CONTROL_ONE = 17;
+const DEVICE_CONTROL_TWO = 18;
+const DEVICE_CONTROL_THREE = 19;
+const DEVICE_CONTROL_FOUR = 20;
+const NEGATIVE_ACKNOWLEDGE = 21;
+const SYNCHRONOUS_IDLE = 22;
+const END_OF_TRANSMISSION_BLOCK = 23;
+const CANCEL = 24;
+const END_OF_MEDIUM = 25;
+const SUBSTITUTE = 26;
+const ESCAPE = 27;
+const FILE_SEPARATOR = 28;
+const GROUP_SEPARATOR = 29;
+const RECORD_SEPARATOR = 30;
+const UNIT_SEPARATOR = 31;
+const SPACE = 32;
+const EXCLAMATION_MARK = 33;
+const QUOTATION_MARK = 34;
+const uint_SIGN = 35;
+const DOLLAR_SIGN = 36;
+const PERCENT_SIGN = 37;
+const AMPERSAND = 38;
+const APOSTROPHE = 39;
+const LEFT_PARENTHESIS = 40;
+const RIGHT_PARENTHESIS = 41;
+const ASTERISK = 42;
+const PLUS_SIGN = 43;
+const COMMA = 44;
+const HYPHEN_MINUS = 45;
+const FULL_STOP = 46;
+const SOLIDUS = 47;
+const DIGIT_ZERO = 48;
+const DIGIT_ONE = 49;
+const DIGIT_TWO = 50;
+const DIGIT_THREE = 51;
+const DIGIT_FOUR = 52;
+const DIGIT_FIVE = 53;
+const DIGIT_SIX = 54;
+const DIGIT_SEVEN = 55;
+const DIGIT_EIGHT = 56;
+const DIGIT_NINE = 57;
+const COLON = 58;
+const SEMICOLON = 59;
+const LESS_THAN_SIGN = 60;
+const EQUALS_SIGN = 61;
+const GREATER_THAN_SIGN = 62;
+const QUESTION_MARK = 63;
+const COMMERCIAL_AT = 64;
+const LATIN_CAPITAL_LETTER_A = 65;
+const LATIN_CAPITAL_LETTER_B = 66;
+const LATIN_CAPITAL_LETTER_C = 67;
+const LATIN_CAPITAL_LETTER_D = 68;
+const LATIN_CAPITAL_LETTER_E = 69;
+const LATIN_CAPITAL_LETTER_F = 70;
+const LATIN_CAPITAL_LETTER_G = 71;
+const LATIN_CAPITAL_LETTER_H = 72;
+const LATIN_CAPITAL_LETTER_I = 73;
+const LATIN_CAPITAL_LETTER_J = 74;
+const LATIN_CAPITAL_LETTER_K = 75;
+const LATIN_CAPITAL_LETTER_L = 76;
+const LATIN_CAPITAL_LETTER_M = 77;
+const LATIN_CAPITAL_LETTER_N = 78;
+const LATIN_CAPITAL_LETTER_O = 79;
+const LATIN_CAPITAL_LETTER_P = 80;
+const LATIN_CAPITAL_LETTER_Q = 81;
+const LATIN_CAPITAL_LETTER_R = 82;
+const LATIN_CAPITAL_LETTER_S = 83;
+const LATIN_CAPITAL_LETTER_T = 84;
+const LATIN_CAPITAL_LETTER_U = 85;
+const LATIN_CAPITAL_LETTER_V = 86;
+const LATIN_CAPITAL_LETTER_W = 87;
+const LATIN_CAPITAL_LETTER_X = 88;
+const LATIN_CAPITAL_LETTER_Y = 89;
+const LATIN_CAPITAL_LETTER_Z = 90;
+const LEFT_SQUARE_BRACKET = 91;
+const REVERSE_SOLIDUS = 92;
+const RIGHT_SQUARE_BRACKET = 93;
+const CIRCUMFLEX_ACCENT = 94;
+const LOW_LINE = 95;
+const GRAVE_ACCENT = 96;
+const LATIN_SMALL_LETTER_A = 97;
+const LATIN_SMALL_LETTER_B = 98;
+const LATIN_SMALL_LETTER_C = 99;
+const LATIN_SMALL_LETTER_D = 100;
+const LATIN_SMALL_LETTER_E = 101;
+const LATIN_SMALL_LETTER_F = 102;
+const LATIN_SMALL_LETTER_G = 103;
+const LATIN_SMALL_LETTER_H = 104;
+const LATIN_SMALL_LETTER_I = 105;
+const LATIN_SMALL_LETTER_J = 106;
+const LATIN_SMALL_LETTER_K = 107;
+const LATIN_SMALL_LETTER_L = 108;
+const LATIN_SMALL_LETTER_M = 109;
+const LATIN_SMALL_LETTER_N = 110;
+const LATIN_SMALL_LETTER_O = 111;
+const LATIN_SMALL_LETTER_P = 112;
+const LATIN_SMALL_LETTER_Q = 113;
+const LATIN_SMALL_LETTER_R = 114;
+const LATIN_SMALL_LETTER_S = 115;
+const LATIN_SMALL_LETTER_T = 116;
+const LATIN_SMALL_LETTER_U = 117;
+const LATIN_SMALL_LETTER_V = 118;
+const LATIN_SMALL_LETTER_W = 119;
+const LATIN_SMALL_LETTER_X = 120;
+const LATIN_SMALL_LETTER_Y = 121;
+const LATIN_SMALL_LETTER_Z = 122;
+const LEFT_CURLY_BRACKET = 123;
+const VERTICAL_LINE = 124;
+const RIGHT_CURLY_BRACKET = 125;
+const TILDE = 126;
+const DELETE = 127;
+const LATIN_CAPITAL_LETTER_C_WITH_CEDILLA = 128;
+const LATIN_SMALL_LETTER_U_WITH_DIAERESIS = 129;
+const LATIN_SMALL_LETTER_E_WITH_ACUTE = 130;
+const LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX = 131;
+const LATIN_SMALL_LETTER_A_WITH_DIAERESIS = 132;
+const LATIN_SMALL_LETTER_A_WITH_GRAVE = 133;
+const LATIN_SMALL_LETTER_A_WITH_RING_ABOVE = 134;
+const LATIN_SMALL_LETTER_C_WITH_CEDILLA = 135;
+const LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX = 136;
+const LATIN_SMALL_LETTER_E_WITH_DIAERESIS = 137;
+const LATIN_SMALL_LETTER_E_WITH_GRAVE = 138;
+const LATIN_SMALL_LETTER_I_WITH_DIAERESIS = 139;
+const LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX = 140;
+const LATIN_SMALL_LETTER_I_WITH_GRAVE = 141;
+const LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS = 142;
+const LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE = 143;
+const LATIN_CAPITAL_LETTER_E_WITH_ACUTE = 144;
+const LATIN_SMALL_LETTER_AE = 145;
+const LATIN_CAPITAL_LETTER_AE = 146;
+const LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX = 147;
+const LATIN_SMALL_LETTER_O_WITH_DIAERESIS = 148;
+const LATIN_SMALL_LETTER_O_WITH_GRAVE = 149;
+const LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX = 150;
+const LATIN_SMALL_LETTER_U_WITH_GRAVE = 151;
+const LATIN_SMALL_LETTER_Y_WITH_DIAERESIS = 152;
+const LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS = 153;
+const LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS = 154;
+const CENT_SIGN = 155;
+const POUND_SIGN = 156;
+const YEN_SIGN = 157;
+const PESETA_SIGN = 158;
+const LATIN_SMALL_LETTER_F_WITH_HOOK = 159;
+const LATIN_SMALL_LETTER_A_WITH_ACUTE = 160;
+const LATIN_SMALL_LETTER_I_WITH_ACUTE = 161;
+const LATIN_SMALL_LETTER_O_WITH_ACUTE = 162;
+const LATIN_SMALL_LETTER_U_WITH_ACUTE = 163;
+const LATIN_SMALL_LETTER_N_WITH_TILDE = 164;
+const LATIN_CAPITAL_LETTER_N_WITH_TILDE = 165;
+const FEMININE_ORDINAL_INDICATOR = 166;
+const MASCULINE_ORDINAL_INDICATOR = 167;
+const INVERTED_QUESTION_MARK = 168;
+const REVERSED_NOT_SIGN = 169;
+const NOT_SIGN = 170;
+const VULGAR_FRACTION_ONE_HALF = 171;
+const VULGAR_FRACTION_ONE_QUARTER = 172;
+const INVERTED_EXCLAMATION_MARK = 173;
+const LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 174;
+const RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 175;
+const LIGHT_SHADE = 176;
+const MEDIUM_SHADE = 177;
+const DARK_SHADE = 178;
+const BOX_DRAWINGS_LIGHT_VERTICAL = 179;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT = 180;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE = 181;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE = 182;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE = 183;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE = 184;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT = 185;
+const BOX_DRAWINGS_DOUBLE_VERTICAL = 186;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT = 187;
+const BOX_DRAWINGS_DOUBLE_UP_AND_LEFT = 188;
+const BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE = 189;
+const BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE = 190;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT = 191;
+const BOX_DRAWINGS_LIGHT_UP_AND_RIGHT = 192;
+const BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL = 193;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL = 194;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT = 195;
+const BOX_DRAWINGS_LIGHT_HORIZONTAL = 196;
+const BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL = 197;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE = 198;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE = 199;
+const BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT = 200;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT = 201;
+const BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL = 202;
+const BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL = 203;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT = 204;
+const BOX_DRAWINGS_DOUBLE_HORIZONTAL = 205;
+const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL = 206;
+const BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE = 207;
+const BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE = 208;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE = 209;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE = 210;
+const BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE = 211;
+const BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE = 212;
+const BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE = 213;
+const BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE = 214;
+const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE = 215;
+const BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE = 216;
+const BOX_DRAWINGS_LIGHT_UP_AND_LEFT = 217;
+const BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT = 218;
+const FULL_BLOCK = 219;
+const LOWER_HALF_BLOCK = 220;
+const LEFT_HALF_BLOCK = 221;
+const RIGHT_HALF_BLOCK = 222;
+const UPPER_HALF_BLOCK = 223;
+const GREEK_SMALL_LETTER_ALPHA = 224;
+const LATIN_SMALL_LETTER_SHARP_S = 225;
+const GREEK_CAPITAL_LETTER_GAMMA = 226;
+const GREEK_SMALL_LETTER_PI = 227;
+const GREEK_CAPITAL_LETTER_SIGMA = 228;
+const GREEK_SMALL_LETTER_SIGMA = 229;
+const MICRO_SIGN = 230;
+const GREEK_SMALL_LETTER_TAU = 231;
+const GREEK_CAPITAL_LETTER_PHI = 232;
+const GREEK_CAPITAL_LETTER_THETA = 233;
+const GREEK_CAPITAL_LETTER_OMEGA = 234;
+const GREEK_SMALL_LETTER_DELTA = 235;
+const INFINITY = 236;
+const GREEK_SMALL_LETTER_PHI = 237;
+const GREEK_SMALL_LETTER_EPSILON = 238;
+const INTERSECTION = 239;
+const IDENTICAL_TO = 240;
+const PLUS_MINUS_SIGN = 241;
+const GREATER_THAN_OR_EQUAL_TO = 242;
+const LESS_THAN_OR_EQUAL_TO = 243;
+const TOP_HALF_INTEGRAL = 244;
+const BOTTOM_HALF_INTEGRAL = 245;
+const DIVISION_SIGN = 246;
+const ALMOST_EQUAL_TO = 247;
+const DEGREE_SIGN = 248;
+const BULLET_OPERATOR = 249;
+const MIDDLE_DOT = 250;
+const SQUARE_ROOT = 251;
+const SUPERSCRIPT_LATIN_SMALL_LETTER_N = 252;
+const SUPERSCRIPT_TWO = 253;
+const BLACK_SQUARE = 254;
+const NO_BREAK_SPACE = 255;
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/src/parser/EscapeSequencer.js b/wsproxy/jsTerm-master/src/parser/EscapeSequencer.js
new file mode 100644 (file)
index 0000000..afbb831
--- /dev/null
@@ -0,0 +1,453 @@
+/**
+ * @author Peter Nitsch
+ */
+/**
+const LEFT_SQUARE_BRACKET = 91;
+const REVERSE_SOLIDUS = 92;
+const RIGHT_SQUARE_BRACKET = 93;
+const CIRCUMFLEX_ACCENT = 94;
+const LOW_LINE = 95;
+const GRAVE_ACCENT = 96;
+*/
+TERM.InitState = function () {
+  this.onRead = function (ctx,position,character) {
+        console.log("TERM.InitState.onRead "+character);
+        if (character == ESCAPE)
+            ctx.setState(new TERM.EscapeState());
+  };
+  console.log("TERM.InitState new called");
+};
+
+
+TERM.EscapeState = function () {
+
+  this.onRead = function (ctx,position,character) {
+        console.log("TERM.EscapeState.onRead "+character);
+        if (character == LEFT_SQUARE_BRACKET)
+            ctx.setState(new TERM.CsiState());
+        if (character == RIGHT_SQUARE_BRACKET)
+            ctx.setState(new TERM.OscState());
+  };
+};
+
+TERM.OscState = function () {
+
+  this.onRead = function (ctx,position,character) {
+        console.log("TERM.OscState.onRead "+character);
+        if (character == LATIN_CAPITAL_LETTER_G || character == BELL) {
+            ctx.complete = true;
+            ctx.setState(new TERM.InitState());
+        }
+  };
+};
+
+TERM.CsiState = function () {
+
+  this.onRead = function (ctx,position,character) {
+        console.log("TERM.CsiState.onRead "+character);
+        if (ctx.checkCommandAction(position,character)) {
+            ctx.complete = true;
+            ctx.setState(new TERM.InitState());
+        }
+  };
+};
+
+
+
+TERM.EscapeSequencer = function (viewer){
+       
+       var viewer = viewer;
+       var telnet;
+       var state;
+    var complete = false;
+       var _customCommand;
+       var _currentCustomCommand = {};
+       
+       this.actionCharacterLib = [];
+       
+       this.init = function() {
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_H ] = this.cursorPosition;        
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_F ] = this.cursorPosition;  
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_A ] = this.cursorUp;      
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_B ] = this.cursorDown;    
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_C] = this.cursorForward;  
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_D ] = this.cursorBackward;        
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_S ] = this.saveCursorPosition;      
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_U ] = this.restoreCursorPosition;   
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_K ] = this.eraseLine;     
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_J ] = this.eraseDisplay;  
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_N ] = this.deviceRequest;
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_M ] = this.setGraphicsMode;
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_H ] = this.setMode; 
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_L ] = this.resetMode;       
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_P ] = this.setKeyboardStrings;      
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_M ] = this.scrollUp;
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_R ] = this.scrollScreen;
+               
+               // TO DO
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_A ] = this.unused;  
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_D ] = this.unused;  
+               this.actionCharacterLib[ LATIN_SMALL_LETTER_E ] = this.unused;  
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_L ] = this.unused;
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_P ] = this.unused;
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_E ] = this.unused;        
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_F ] = this.unused;
+               this.actionCharacterLib[ LATIN_CAPITAL_LETTER_X ] = this.unused;
+        this.actionCharacterLib[ BELL    ] = this.title;
+               
+        this.state = new TERM.InitState();
+       };
+       
+    this.setState = function (_state) {
+      this.state = _state;
+    };
+
+    this.onRead = function (position,character) {
+      this.state.onRead(this,position,character);
+    };
+
+       this.executeCommand = function(command) {
+               try {
+                       this.actionCharacterLib[ command[command.length-1] ]( command );
+               } catch(error) {
+                       console.log(error);
+               }
+       };
+       
+       this.checkCommandAction = function(position, character) {
+               if( this.actionCharacterLib[character] != undefined )
+                       return true;
+        console.log("EscapeSequencer.checkCommandAction undefined "+character);
+               return false;
+       };
+       
+       this.unused = function(params) {
+               // EMPTY
+       };
+       
+    this.title = function(params) {
+               console.log("Title commande ");
+       };
+       
+       this.deviceRequest = function(params) {
+               if( params[2]==DIGIT_FIVE ){
+                       TERM.socket.writeByte(ESCAPE);
+                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                       TERM.socket.writeByte(DIGIT_ZERO);
+                       TERM.socket.writeByte(LATIN_SMALL_LETTER_N);
+               } else if( params[2]==DIGIT_SIX ) {
+                       var i;
+               var rows = "" + viewer.cursor.y;
+               var cols = "" + viewer.cursor.x;
+
+                       TERM.socket.writeByte(ESCAPE);
+                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                       for(i=0;i<rows.length;i++)      TERM.socket.writeByte(rows.charCodeAt(i));
+                       TERM.socket.writeByte(SEMICOLON);
+                       for(i=0;i<cols.length;i++)      TERM.socket.writeByte(cols.charCodeAt(i));
+                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_R);
+               } else {
+                       // 0 - Report Device OK
+                       // 3 - Report Device Failure 
+               }
+       };
+       
+       this.cursorPosition = function(params) {
+               var lastCharacter = params[params.length-1];
+               
+               if( params.length==3 && lastCharacter==LATIN_CAPITAL_LETTER_H){
+                       viewer.home();
+               } else {
+                       var lineArray = [];
+                       var lineStr = "";
+                       var line = 0;
+                       
+                       var columnArray = [];
+                       var columnStr = "";
+                       var column = 0;
+                       
+                       if(params.indexOf(SEMICOLON) != -1){
+                               var semicolonIndex = params.indexOf(SEMICOLON);
+                               
+                               if( params[semicolonIndex-1] != LEFT_SQUARE_BRACKET ) {
+                                       lineArray = params.slice(2, semicolonIndex);
+                                       for( i=0; i<lineArray.length; i++ ){
+                                               lineStr += (lineArray[i] - 48).toString();
+                                       }
+                                       line = parseInt(lineStr);
+                               }
+                               
+                               columnArray = params.slice(semicolonIndex+1, params.length-1);
+                               for( i=0; i<columnArray.length; i++ ){
+                                       columnStr += (columnArray[i] - 48).toString();
+                               }
+                               column = parseInt(columnStr);
+                               
+                       } else if(params.slice(2, params.indexOf(lastCharacter)).length > 0){
+                               lineArray = params.slice(2, params.length-1);
+                               for( i=0; i<lineArray.length; i++ ){
+                                       lineStr += (lineArray[i] - 48).toString();
+                               }
+                               line = parseInt(lineStr);
+                       } 
+                       
+                       column = (column>0) ? column-1 : 0;
+                       line = (line>0) ? line-1 : 0;
+                       
+                       viewer.reposition(column, line);
+               }
+       };
+       
+       this.cursorUp = function(params) {
+               var valueArray = params.slice(2, params.length-1);
+               var valueStr = "";
+               for( i=0; i<valueArray.length; i++ ){
+                       valueStr += (valueArray[i] - 48).toString();
+               }
+               var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+               
+               viewer.moveUp(value);
+       };
+       
+       this.cursorDown = function(params) {
+               var valueArray = params.slice(2, params.length-1);
+               var valueStr = "";
+               for( i=0; i<valueArray.length; i++ ){
+                       valueStr += (valueArray[i] - 48).toString();
+               }
+               var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+               
+               viewer.moveDown(value);
+       };
+       
+       this.cursorForward = function(params) {         
+               var valueArray = params.slice(2, params.length-1);
+               var valueStr = "";
+               for( i=0; i<valueArray.length; i++ ){
+                       valueStr += (valueArray[i] - 48).toString();
+               }
+               var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+               
+               viewer.moveForward(value);
+       };
+       
+       this.cursorBackward = function(params) {
+               var valueArray = params.slice(2, params.length-1);
+               var valueStr = "";
+               for( i=0; i<valueArray.length; i++ ){
+                       valueStr += (valueArray[i] - 48).toString();
+               }
+               var value = (valueStr.length > 0) ? parseInt(valueStr) : 1;
+               
+               viewer.moveBackward(value);
+       };
+       
+       this.saveCursorPosition = function(params) {
+               viewer.savePosition();
+       };
+       
+       this.restoreCursorPosition = function(params) {
+               viewer.restorePosition();
+       };
+       
+       // Set Graphic Mode functions
+       var _bold = false;
+       var _reverse = false;
+
+       var _boldColors = [BLACK_BOLD, RED_BOLD, GREEN_BOLD, YELLOW_BOLD, BLUE_BOLD, MAGENTA_BOLD, CYAN_BOLD, WHITE_BOLD];
+       var _normalColors = [BLACK_NORMAL, RED_NORMAL, GREEN_NORMAL, YELLOW_NORMAL, BLUE_NORMAL, MAGENTA_NORMAL, CYAN_NORMAL, WHITE_NORMAL];            
+
+       var _currentForegroundColor = WHITE_NORMAL;
+       var _currentBackgroundColor = BLACK_NORMAL;
+       
+       this.setGraphicsMode = function(params) {
+               console.log("setGraphicsMode");
+        for( i=2; i<params.length; i++ ){
+                       switch( params[i] ){
+
+                               /*  Reset */
+                               case LATIN_SMALL_LETTER_M:
+                               case DIGIT_ZERO:
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+                                               _bold = false;
+                                               _reverse = false;
+                                               
+                                               _currentForegroundColor = WHITE_NORMAL;
+                                               _currentBackgroundColor = BLACK_NORMAL;
+                                               
+                                               viewer.foregroundColorChanged(_currentForegroundColor);
+                                               viewer.backgroundColorChanged(_currentBackgroundColor);
+                                       }
+                               break;
+                               
+                               /*  Bold ON */
+                               case DIGIT_ONE:
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET) {
+                                               _bold = true;
+
+                                               for( j=0; j<_normalColors.length; j++ ){
+                                                       if( _currentForegroundColor == _normalColors[j] )
+                                                               _currentForegroundColor = _boldColors[j];
+                                               }
+                                               
+                                               viewer.foregroundColorChanged(_currentForegroundColor);
+                                       }
+                               break;
+                               
+                               /* Dim */
+                               case DIGIT_TWO:                                         
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET) {
+                                               _bold = false;
+
+                                               for( j=0; j<_normalColors.length; j++ ){
+                                                       if( _currentForegroundColor == _boldColors[j] )
+                                                               _currentForegroundColor = _normalColors[j];
+                                               }
+                                               
+                                               viewer.foregroundColorChanged(_currentForegroundColor);
+                                       }
+                               break;
+                               
+                               /* Set foreground color */
+                               case DIGIT_THREE:
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+                                               if(params[i+1] != SEMICOLON && params[i+1] != LATIN_SMALL_LETTER_M){
+                                                       
+                                                       var position = params[i+1] - 48;
+                                                       if(_reverse) {
+                                                               _currentBackgroundColor = _normalColors[position];
+                                                               viewer.backgroundColorChanged(_currentBackgroundColor);
+                                                       }else {
+                                                               _currentForegroundColor = (_bold) ? _boldColors[position] : _normalColors[position];
+                                                               viewer.foregroundColorChanged(_currentForegroundColor);
+                                                       }
+                                                       
+                                               }
+                                       }
+                               break;
+                               
+                               /* Set background color */
+                               case DIGIT_FOUR:
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET){
+                                               if(params[i+1] != SEMICOLON && params[i+1] != LATIN_SMALL_LETTER_M){
+                                                       position = params[i+1] - 48;
+                                                       if(_reverse) {
+                                                               _currentForegroundColor = (_bold) ? _boldColors[position] : _normalColors[position];
+                                                               viewer.foregroundColorChanged(_currentForegroundColor);
+                                                       } else {
+                                                               _currentBackgroundColor = _normalColors[position];
+                                                               viewer.backgroundColorChanged(_currentBackgroundColor);
+                                                       }
+                                               
+                                               /* Underline ON */              
+                                               } else {
+                                                       // TO DO
+                                               }
+                                       }
+                               break;
+                               
+                               /* Blink ON */
+                               case DIGIT_FIVE:
+                                       // TO DO
+                               break;
+                               
+                               /* Reverse ON */
+                               case DIGIT_SEVEN:
+                                       if(params[i-1] == SEMICOLON || params[i-1] == LEFT_SQUARE_BRACKET)
+                                               _reverse = true;
+                               break;
+                               
+                               /* Concealed ON */
+                               case DIGIT_EIGHT:
+                                       // TO DO
+                               break;
+                               
+                               /* Reset to normal? */
+                               case DIGIT_NINE:
+                                       // TO DO
+                               break;
+                       }
+               }
+       };
+       
+       this.scrollScreen = function(params) {
+               if(params.length==3){
+            console.log("Escape::scrollScreen 3 params");
+                       viewer.scrollScreen();
+               } else {
+            console.log("Escape::scrollScreen params length="+params.length);
+                       var lastCharacter = params[params.length-1];
+               
+                       var sArray = [];
+                       var sStr = "";
+                       var s = 0;
+                       
+                       var eArray = [];
+                       var eStr = "";
+                       var e = 0;
+                       
+                       var semicolonIndex = params.indexOf(SEMICOLON);
+
+                       sArray = params.slice(2, semicolonIndex);
+                       for( i=0; i<sArray.length; i++ ){
+               console.log("Escape::scrollScreen S getting "+sArray[i]);
+                               sStr += (sArray[i] - 48).toString();
+                       }
+                       s = parseInt(sStr);
+
+                       
+                       eArray = params.slice(semicolonIndex+1, params.length-1);
+                       for( i=0; i<eArray.length; i++ ){
+                 console.log("Escape::scrollScreen E getting "+eArray[i]);
+                 if ( eArray[i] > 48)
+                                  eStr += (eArray[i] - 48).toString();
+                       }
+                       e = parseInt(eStr);
+                               
+                       viewer.scrollScreen(s, e);
+               }
+       };
+       
+       this.scrollUp = function(params) {
+               viewer.scrollUp(1);
+       };
+       
+       this.eraseLine = function(params) {
+               if( params[2]==DIGIT_ONE ){
+                       viewer.eraseStartOfLine();
+               } else if( params[2]==DIGIT_TWO ) {
+                       viewer.eraseLine();
+               } else {
+                       viewer.eraseEndOfLine();
+               }               
+       };
+       
+       this.eraseDisplay = function(params) {
+         console.log("Escape::eraseDisaply");
+               if( params[2]==DIGIT_ONE ){
+                       viewer.eraseUp();
+                       viewer.reposition(0, 0);
+               } else if( params[2]==DIGIT_TWO ) {
+                       viewer.eraseScreen();
+                       viewer.reposition(0, 0);
+               } else {
+                       viewer.eraseDown();
+               }
+       };
+       
+       // Terminal functions
+       this.setMode = function(){
+               // TO DO
+       };
+       
+       this.resetMode = function(){
+               // TO DO
+       };
+       
+       this.setKeyboardStrings = function(){
+               // TO DO
+       };
+       
+       this.init();
+
+};
diff --git a/wsproxy/jsTerm-master/src/parser/Keyboard.js b/wsproxy/jsTerm-master/src/parser/Keyboard.js
new file mode 100644 (file)
index 0000000..0854a13
--- /dev/null
@@ -0,0 +1,11 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const KEYBOARD_LEFT = 37;
+const KEYBOARD_RIGHT = 39;
+const KEYBOARD_UP = 38;
+const KEYBOARD_DOWN = 40;
+const KEYBOARD_PAGE_UP = 33;
+const KEYBOARD_PAGE_DOWN = 34;
+const KEYBOARD_HOME = 36;
diff --git a/wsproxy/jsTerm-master/src/parser/NVTCodes.js b/wsproxy/jsTerm-master/src/parser/NVTCodes.js
new file mode 100644 (file)
index 0000000..5e4f947
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const IAC = 255;
+const GA = 249;
+const WILL = 251;
+const WONT = 252;
+const DO = 253;
+const DONT = 254;
+const SB = 250;
+const SE = 240;
+const NOP = 241;
+const DM = 242;
+const BRK = 243;
+
+const IP = 244;
+const AO = 245;
+const AYT = 246;
+const EC = 247;
+const EL = 248;
+
+const ECHO = 1;
+const SUPGA = 3;
+
+const NAWS = 31;
+const TTYPE = 24;
+const IS = 0;
+const SEND = 1;
+const LOGOUT = 18;
+
+const LINEMODE = 34;
+const LM_MODE = 1;
+const LM_EDIT = 1;
+const LM_TRAPSIG = 2;
+const LM_MODEACK = 4;
+const LM_FORWARDMASK = 2;
+
+const LM_SLC = 3;
+const LM_SLC_NOSUPPORT = 0;
+const LM_SLC_DEFAULT = 3;
+const LM_SLC_VALUE = 2;
+const LM_SLC_CANTCHANGE = 1;
+const LM_SLC_LEVELBITS = 3;
+const LM_SLC_ACK = 128;
+const LM_SLC_FLUSHIN = 64;
+const LM_SLC_FLUSHOUT = 32;
+
+const LM_SLC_SYNCH = 1;
+const LM_SLC_BRK = 2;
+const LM_SLC_IP = 3;
+const LM_SLC_AO = 4;
+const LM_SLC_AYT = 5;
+const LM_SLC_EOR = 6;
+const LM_SLC_ABORT = 7;
+const LM_SLC_EOF = 8;
+const LM_SLC_SUSP = 9;
+
+const NEWENV = 39;
+const NE_INFO = 2;
+const NE_VAR = 0;
+const NE_VALUE = 1;
+const NE_ESC = 2;
+const NE_USERVAR = 3;
+
+const NE_VAR_OK = 2;
+const NE_VAR_DEFINED = 1;
+const NE_VAR_DEFINED_EMPTY = 0;
+const NE_VAR_UNDEFINED = -1;
+const NE_IN_ERROR = -2;
+const NE_IN_END = -3;
+const NE_VAR_NAME_MAXLENGTH = 50;
+const NE_VAR_VALUE_MAXLENGTH = 1000;
+
+// Unused
+const EXT_ASCII = 17;
+const SEND_LOC = 23;
+const AUTHENTICATION = 37;
+const ENCRYPT = 38;
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/src/parser/SixteenColors.js b/wsproxy/jsTerm-master/src/parser/SixteenColors.js
new file mode 100644 (file)
index 0000000..fdf658a
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * @author Peter Nitsch
+ */
+
+const BLACK_NORMAL = "#000000";
+const BLACK_BOLD = "#545454";
+const RED_NORMAL = "#a80000";
+const RED_BOLD = "#fc5454";
+const GREEN_NORMAL = "#00a800";
+const GREEN_BOLD = "#54fc54";
+const YELLOW_NORMAL = "#a85400";
+const YELLOW_BOLD = "#fcfc54";
+const BLUE_NORMAL = "#0000a8";
+const BLUE_BOLD = "#5454fc";
+const MAGENTA_NORMAL = "#a800a8";
+const MAGENTA_BOLD = "#fc54fc";
+const CYAN_NORMAL = "#00a8a8";
+const CYAN_BOLD = "#54fcfc";
+const WHITE_NORMAL = "#a8a8a8";
+const WHITE_BOLD = "#fcfcfc";
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/src/parser/Telnet.js b/wsproxy/jsTerm-master/src/parser/Telnet.js
new file mode 100644 (file)
index 0000000..74d68f2
--- /dev/null
@@ -0,0 +1,796 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Telnet = function (viewer){
+       
+       var parser = viewer.parser;
+       var _actionCharacterLib = [];
+
+       var bytes;
+       
+       this.init = function() {
+               _actionCharacterLib[ IAC ] = interpretCommand;
+               parser.writeException(IAC, interpretCommand);
+       };
+       
+       function interpretCommand(code, b) { 
+               bytes = b;
+               var command = bytes.readUnsignedByte();
+               handleC(command);
+       };
+
+       function read16int () {
+               var c = 0;
+               try {
+                       c = bytes.readUnsignedByte();
+                       return c;
+               } catch (e) {
+                       console.log(e);
+               }
+               
+               return c;
+       };
+       
+       function IamHere() {
+               try {
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(DO);
+                       TERM.socket.writeByte(AYT);
+               } catch (error) {
+                       console.log("IamHere() Error "+ error);
+               }
+       };
+
+       function nvtBreak() {
+               // TO DO
+       };
+       
+       function setTerminalGeometry (width, height) {
+               // TO DO
+       };
+       
+       function setEcho(b) {
+               // TO DO
+       };
+                       
+       var buffer = [0,0];
+       
+       var DO_ECHO = false;
+       var DO_SUPGA = false;
+       var DO_NAWS = false;
+       var DO_TTYPE = false;
+       var DO_LINEMODE = false;
+       var DO_NEWENV = false;
+       
+       var WAIT_DO_REPLY_SUPGA = false;
+       var WAIT_DO_REPLY_ECHO = false;
+       var WAIT_DO_REPLY_NAWS = false;
+       var WAIT_DO_REPLY_TTYPE = false;
+       var WAIT_DO_REPLY_LINEMODE = false;
+       var WAIT_LM_MODE_ACK = false;
+       var WAIT_LM_DO_REPLY_FORWARDMASK = false;
+       var WAIT_DO_REPLY_NEWENV = false;
+       var WAIT_NE_SEND_REPLY = false;
+       
+       var WAIT_WILL_REPLY_SUPGA = false;
+       var WAIT_WILL_REPLY_ECHO = false;
+       var WAIT_WILL_REPLY_NAWS = false;
+       var WAIT_WILL_REPLY_TTYPE = false;
+       
+       function doCharacterModeInit() {
+               sendCommand(WILL, ECHO, true);
+               sendCommand(DONT, ECHO, true);
+               sendCommand(DO, NAWS, true);
+               sendCommand(WILL, SUPGA, true);
+               sendCommand(DO, SUPGA, true);
+               sendCommand(DO, TTYPE, true);
+               sendCommand(DO, NEWENV, true);
+       };
+       
+       function doLineModeInit() {
+               sendCommand(DO, NAWS, true);
+               sendCommand(WILL, SUPGA, true);
+               sendCommand(DO, SUPGA, true);
+               sendCommand(DO, TTYPE, true);
+               sendCommand(DO, LINEMODE, true);
+               sendCommand(DO, NEWENV, true);
+       };
+       
+       function handleC(i) {
+               buffer[0] = i;
+               if (!parseTWO(buffer)) {
+                       try {
+                               buffer[1] = bytes.readUnsignedByte();
+                               parse(buffer);
+                       } catch(e) {
+                               console.log(e);
+                       }
+               }
+               
+               buffer[0] = 0;
+               buffer[1] = 0;
+       };
+       
+       function parseTWO(buf) {
+               switch (buf[0]) {
+                       case IAC:
+                       break;
+                       case AYT:
+                               IamHere();
+                       break;
+                       case AO:
+                       case IP:
+                       case EL:
+                       case EC:
+                       case NOP:
+                       break;
+                       case BRK:
+                               nvtBreak();
+                       break;
+                       default:
+                               return false;
+               }
+               return true;
+       };
+       
+       function parse(buf) {
+               switch (buf[0]) {
+                       case WILL:
+                               if (supported(buf[1]) && isEnabled(buf[1])) {
+                                       ;
+                               } else {
+                                       if (waitDOreply(buf[1]) && supported(buf[1])) {
+                                               enable(buf[1]);
+                                               setWait(DO, buf[1], false);
+                                       } else {
+                                               if (supported(buf[1])) {                            
+                                                       sendCommand(DO, buf[1], false);
+                                                       enable(buf[1]);
+                                               } else {
+                                                       sendCommand(DONT, buf[1], false);
+                                               }
+                                       }
+                               }
+                       break;
+                       case WONT:
+                               if (waitDOreply(buf[1]) && supported(buf[1])) {
+                                       setWait(DO, buf[1], false);
+                               } else {
+                                       if (supported(buf[1]) && isEnabled(buf[1])) {
+                                               enable(buf[1]);
+                                       }
+                               }
+                       break;
+                       case DO:
+                               if (supported(buf[1]) && isEnabled(buf[1])) {
+                               } else {
+                                       if (waitWILLreply(buf[1]) && supported(buf[1])) {
+                                               enable(buf[1]);
+                                               setWait(WILL, buf[1], false);
+                                       } else {
+                                               if (supported(buf[1])) {
+                                                       sendCommand(WILL, buf[1], false);
+                                                       enable(buf[1]);
+                                               } else {
+                                                       sendCommand(WONT, buf[1], false);
+                                               }
+                                       }
+                               }
+                       break;
+                       case DONT:
+                               if (waitWILLreply(buf[1]) && supported(buf[1])) {
+                                       setWait(WILL, buf[1], false);
+                               } else {
+                                       if (supported(buf[1]) && isEnabled(buf[1])) {
+                                               enable(buf[1]);
+                                       }
+                               }
+                       break;
+                       
+                       case DM:        
+                       break;
+                       case SB: 
+                               if ((supported(buf[1])) && (isEnabled(buf[1]))) {
+                                       switch (buf[1]) {
+                                               case NAWS:
+                                                       handleNAWS();
+                                               break;
+                                               case TTYPE:
+                                                       handleTTYPE();
+                                               break;
+                                               case LINEMODE:
+                                                       handleLINEMODE();
+                                               break;
+                                               case NEWENV:
+                                                       handleNEWENV();
+                                               break;
+                                               default:
+                                                       ;
+                                       }
+                               } else {
+                       
+                               }
+                       break;
+                       default:
+                               ;
+               }
+       };
+       
+       
+       function handleNAWS() {
+               var width = read16int();
+               if (width == 255) {
+                       width = read16int(); 
+               }
+               var height = read16int();
+               if (height == 255) {
+                       height = read16int(); 
+               }
+               skipToSE();
+               setTerminalGeometry(width, height);
+       };
+       
+       function handleTTYPE() {
+               var tmpstr = "";
+               var b = bytes.readUnsignedByte();
+                
+               switch(b) {
+                       case SEND:
+                               var cont = true;
+                               do {
+                                       var i;
+                                       i = bytes.readUnsignedByte();
+                                       if (i == SE) {
+                                               cont = false;
+                                       }
+                 
+                               } while (cont);
+                               
+                               _session.flush();
+                                       
+                               TERM.socket.writeByte(IAC);
+                               TERM.socket.writeByte(SB);
+                               TERM.socket.writeByte(TTYPE);
+                               TERM.socket.writeByte(IS);
+                               writeMultiByte("ansi", "us-ascii");
+                               TERM.socket.writeByte(IAC);
+                               TERM.socket.writeByte(SE);
+                       break;
+                 
+                       case IS:
+                               tmpstr = readIACSETerminatedString(40);
+                       break;
+               }
+       };
+       
+       function handleLINEMODE() {
+               var c = bytes.readUnsignedByte();
+               switch (c) {
+                       case LM_MODE:
+                               handleLMMode();
+                       break;
+                       case LM_SLC:
+                               handleLMSLC();
+                       break;
+                       case WONT:
+                       case WILL:
+                               handleLMForwardMask(c);
+                       break;
+                       default:
+                               skipToSE();
+               }
+       };
+       
+       function handleLMMode() {
+               if (WAIT_LM_MODE_ACK) {
+                       var mask = bytes.readUnsignedByte();
+                       if (mask != (LM_EDIT | LM_TRAPSIG | LM_MODEACK)) {
+                       }
+                       WAIT_LM_MODE_ACK = false;
+               }
+               skipToSE();
+       };
+       
+       function handleLMSLC() {
+               var triple = [0,0,0];
+               if (!readTriple(triple)) return;
+               
+               if ((triple[0] == 0) && (triple[1] == LM_SLC_DEFAULT) && (triple[2] == 0)) {
+                       skipToSE();
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SB);
+                       TERM.socket.writeByte(LINEMODE);
+                       TERM.socket.writeByte(LM_SLC);
+               
+                       for (var i = 1; i < 12; i++) {
+                               TERM.socket.writeByte(i);
+                               TERM.socket.writeByte(LM_SLC_DEFAULT);
+                               TERM.socket.writeByte(0);
+                       }
+               
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SE);
+               } else {
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SB);
+                       TERM.socket.writeByte(LINEMODE);
+                       TERM.socket.writeByte(LM_SLC);
+                       TERM.socket.writeByte(triple[0]);
+                       TERM.socket.writeByte(triple[1] | LM_SLC_ACK);
+                       TERM.socket.writeByte(triple[2]);
+                       while (readTriple(triple)) {
+                               TERM.socket.writeByte(triple[0]);
+                               TERM.socket.writeByte(triple[1] | LM_SLC_ACK);
+                               TERM.socket.writeByte(triple[2]);
+                       }
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SE);
+               }
+       };
+       
+       function handleLMForwardMask(WHAT) {
+               switch (WHAT) {
+                       case WONT:
+                               if (WAIT_LM_DO_REPLY_FORWARDMASK) {
+                                       WAIT_LM_DO_REPLY_FORWARDMASK = false;
+                               }
+                       break;
+               }
+               skipToSE();
+       };
+       
+       function handleNEWENV() {
+               var c = bytes.readUnsignedByte();
+               switch (c) {
+                       case IS:
+                               handleNEIs();
+                       break;
+                       case NE_INFO:
+                               handleNEInfo();
+                       break;
+                       default:
+                               skipToSE();
+               }
+       };
+       
+       function readNEVariableName(sbuf) {
+               var i = -1;
+               do {
+                       i = bytes.readUnsignedByte();
+                       if (i == -1) {
+                               return NE_IN_ERROR;
+                       } else if (i == IAC) {
+                               i = bytes.readUnsignedByte();
+                               if (i == IAC) {
+                                       sbuf.concat(i);
+                               } else if (i == SE) {
+                                       return NE_IN_END;
+                               } else {
+                                       return NE_IN_ERROR;
+                               }
+                       } else if (i == NE_ESC) {
+                               i = bytes.readUnsignedByte();
+                               if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                                       sbuf.concat(i);
+                               } else {
+                                       return NE_IN_ERROR;
+                               }
+                       } else if (i == NE_VAR || i == NE_USERVAR) {
+                               return NE_VAR_UNDEFINED;
+                       } else if (i == NE_VALUE) {
+                               return NE_VAR_DEFINED;
+                       } else {
+                               if (sbuf.length >= NE_VAR_NAME_MAXLENGTH) {
+                                       return NE_IN_ERROR;
+                               } else {
+                                       sbuf.concat(i);
+                               }
+                       }
+               } while (true);
+                 
+               return i;
+       };
+       
+       function readNEVariableValue(sbuf) {
+               var i = bytes.readUnsignedByte();
+               if (i == -1) {
+                       return NE_IN_ERROR;
+               } else if (i == IAC) {
+                       i = bytes.readUnsignedByte();
+                       if (i == IAC) {
+                               return NE_VAR_DEFINED_EMPTY;
+                       } else if (i == SE) {
+                               return NE_IN_END;
+                       } else {
+                               return NE_IN_ERROR;
+                       }
+               } else if (i == NE_VAR || i == NE_USERVAR) {
+                       return NE_VAR_DEFINED_EMPTY;
+               } else if (i == NE_ESC) {
+                       i = bytes.readUnsignedByte();
+                       if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                               sbuf.concat(i);
+                       } else {
+                               return NE_IN_ERROR;
+                       }
+               } else {
+                       sbuf.concat(i);
+               }
+                 
+               do {
+                       i = bytes.readUnsignedByte();
+                       if (i == -1) {
+                               return NE_IN_ERROR;
+                       } else if (i == IAC) {
+                               i = bytes.readUnsignedByte();
+                               if (i == IAC) {
+                                       sbuf.concat(i);
+                               } else if (i == SE) {
+                                       return NE_IN_END;
+                               } else {
+                                       return NE_IN_ERROR;
+                               }
+                       } else if (i == NE_ESC) {
+                               i = bytes.readUnsignedByte();
+                               if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                                       sbuf.concat(i);
+                               } else {
+                                       return NE_IN_ERROR;
+                               }
+                       } else if (i == NE_VAR || i == NE_USERVAR) {
+                               return NE_VAR_OK;
+                       } else {
+                               if (sbuf.length > NE_VAR_VALUE_MAXLENGTH) {
+                                       return NE_IN_ERROR;
+                               } else {
+                                       sbuf.concat(i);
+                               }
+                       }
+               } while (true);
+                 
+               return i;
+       };
+       
+       
+       function readNEVariables() {
+               var sbuf = "";
+               var i = bytes.readUnsignedByte();
+               if (i == IAC) {
+                       skipToSE();
+                       console.log("readNEVariables()::INVALID VARIABLE");
+                       return;
+               }
+               var cont = true;
+               if (i == NE_VAR || i == NE_USERVAR) {
+                       do {
+                               switch (readNEVariableName(sbuf)) {
+                                       case NE_IN_ERROR:
+                                               console.log("readNEVariables()::NE_IN_ERROR");
+                                       return;
+                                       case NE_IN_END:
+                                               console.log("readNEVariables()::NE_IN_END");
+                                       return;
+                                       case NE_VAR_DEFINED:
+                                               console.log("readNEVariables()::NE_VAR_DEFINED");
+                                               var str = sbuf;
+                                               sbuf = "";
+                                               switch (readNEVariableValue(sbuf)) {
+                                                       case NE_IN_ERROR:
+                                                               console.log("readNEVariables()::NE_IN_ERROR");
+                                                               return;
+                                                       case NE_IN_END:
+                                                               console.log("readNEVariables()::NE_IN_END");
+                                                               return;
+                                                       case NE_VAR_DEFINED_EMPTY:
+                                                               console.log("readNEVariables()::NE_VAR_DEFINED_EMPTY");
+                                                       break;
+                                                       case NE_VAR_OK:
+                                                               console.log("readNEVariables()::NE_VAR_OK:VAR=" + str + " VAL=" + sbuf.toString());
+                                                               sbuf = "";
+                                                       break;
+                                               }
+                                       break;
+                                       case NE_VAR_UNDEFINED:
+                                               console.log("readNEVariables()::NE_VAR_UNDEFINED");
+                                       break;
+                               }
+                       } while (cont);
+               }
+       };
+       
+       function handleNEIs() {
+               if (isEnabled(NEWENV)) {
+                       readNEVariables();
+               }
+       };
+       
+       function handleNEInfo() {
+               if (isEnabled(NEWENV)) {
+                       readNEVariables();
+               }
+       };
+       
+       function getTTYPE() {
+               if (isEnabled(TTYPE)) {
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SB);
+                       TERM.socket.writeByte(TTYPE);
+                       TERM.socket.writeByte(SEND);
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SE);
+               }
+       };
+       
+       function negotiateLineMode() {
+               if (isEnabled(LINEMODE)) {
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SB);
+                       TERM.socket.writeByte(LINEMODE);
+                       TERM.socket.writeByte(LM_MODE);
+                       TERM.socket.writeByte(LM_EDIT | LM_TRAPSIG);
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SE);
+                       WAIT_LM_MODE_ACK = true;
+                       
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SB);
+                       TERM.socket.writeByte(LINEMODE);
+                       TERM.socket.writeByte(DONT);
+                       TERM.socket.writeByte(LM_FORWARDMASK);
+                       TERM.socket.writeByte(IAC);
+                       TERM.socket.writeByte(SE);
+                       WAIT_LM_DO_REPLY_FORWARDMASK = true;
+               }
+       };
+       
+       function negotiateEnvironment() {
+               if (isEnabled(NEWENV)) {
+                       ba.TERM.socket.writeByte(IAC);
+                       ba.TERM.socket.writeByte(SB);
+                       ba.TERM.socket.writeByte(NEWENV);
+                       ba.TERM.socket.writeByte(SEND);
+                       ba.TERM.socket.writeByte(NE_VAR);
+                       ba.TERM.socket.writeByte(NE_USERVAR);
+                       ba.TERM.socket.writeByte(IAC);
+                       ba.TERM.socket.writeByte(SE);
+                       WAIT_NE_SEND_REPLY = true;
+               }
+       };
+       
+       function skipToSE() {
+               while (bytes.readUnsignedByte() != SE) ;
+       };
+       
+       function readTriple(triple) {
+               triple[0] = bytes.readUnsignedByte();
+               triple[1] = bytes.readUnsignedByte();
+               if ((triple[0] == IAC) && (triple[1] == SE)) {
+                       return false;
+               } else {
+                       triple[2] = bytes.readUnsignedByte();
+                       return true;
+               }
+                 
+               return false;
+       };
+       
+       
+       function readIACSETerminatedString(maxlength) {
+               var where = 0;
+               var cbuf = [];
+               var b = ' ';
+               var cont = true;
+               
+               do {
+                       var i;
+                       i = bytes.readUnsignedByte();
+                       switch (i) {
+                               case IAC:
+                                       i = bytes.readUnsignedByte();
+                                       if (i == SE) {
+                                       cont = false;
+                                       }
+                               break;
+                               case -1:
+                                       return ("default");
+                               default:
+                       }
+                       if (cont) {
+                               b = i.toString();
+                               if (b == '\n' || b == '\r' || where == maxlength) {
+                                       cont = false;
+                               } else {
+                                       cbuf[where++] = b;
+                               }
+                       }
+               } while (cont);
+               
+               var str = "";
+               for(var j=0; j<where; j++) {
+                       str.concat(cbuf[i]);
+               }
+               
+               return (str);
+       };
+       
+       function supported(i) {
+               switch (i) {
+                       case SUPGA:
+                       case ECHO:
+                       case NAWS:
+                       case TTYPE:
+                               return true;
+                       case LINEMODE:
+                               return false;
+                       default:
+                               return false;
+               }
+       };
+       
+       function sendCommand(i, j, westarted) {
+               TERM.socket.writeByte(IAC);
+               TERM.socket.writeByte(i);
+               TERM.socket.writeByte(j);
+                 
+               if ((i == DO) && westarted) setWait(DO, j, true);
+               if ((i == WILL) && westarted) setWait(WILL, j, true);
+       };
+       
+       function enable(i) {
+               switch (i) {
+                       case SUPGA:
+                               if (DO_SUPGA) {
+                                       DO_SUPGA = false;
+                               } else {
+                                       DO_SUPGA = true;
+                               }
+                       break;
+                       case ECHO:
+                               if (DO_ECHO) {
+                                       DO_ECHO = false;
+                               } else {
+                                       DO_ECHO = true;
+                               }
+                       break;
+                       case NAWS:
+                               if (DO_NAWS) {
+                                       DO_NAWS = false;
+                               } else {
+                                       DO_NAWS = true;
+                               }
+                       break;
+                       case TTYPE:
+                       if (DO_TTYPE) {
+                                       DO_TTYPE = false;
+                               } else {
+                                       DO_TTYPE = true;
+                                       getTTYPE();
+                               }
+                       break;
+                       case LINEMODE:
+                               if (DO_LINEMODE) {
+                                       DO_LINEMODE = false;
+                               } else {
+                                       DO_LINEMODE = true;
+                                       negotiateLineMode();
+                               }
+                       break;
+                       case NEWENV:
+                               if (DO_NEWENV) {
+                                       DO_NEWENV = false;
+                               } else {
+                                       DO_NEWENV = true;
+                                       negotiateEnvironment();
+                               }
+                       break;
+               }
+       };
+       
+       function isEnabled(i) {
+               switch (i) {
+                       case SUPGA:
+                               return DO_SUPGA;
+                       case ECHO:
+                               return DO_ECHO;
+                       case NAWS:
+                               return DO_NAWS;
+                       case TTYPE:
+                               return DO_TTYPE;
+                       case LINEMODE:
+                               return DO_LINEMODE;
+                       case NEWENV:
+                               return DO_NEWENV;
+                       default:
+                               return false;
+               }
+                 
+               return false;
+       };
+       
+       function waitWILLreply(i) {
+               switch (i) {
+                       case SUPGA:
+                               return WAIT_WILL_REPLY_SUPGA;
+                       case ECHO:
+                               return WAIT_WILL_REPLY_ECHO;
+                       case NAWS:
+                               return WAIT_WILL_REPLY_NAWS;
+                       case TTYPE:
+                               return WAIT_WILL_REPLY_TTYPE;
+                       default:
+                               return false;
+               }
+         
+               return false;
+       };
+       
+       function waitDOreply(i) {
+               switch (i) {
+                       case SUPGA:
+                               return WAIT_DO_REPLY_SUPGA;
+                       case ECHO:
+                               return WAIT_DO_REPLY_ECHO;
+                       case NAWS:
+                               return WAIT_DO_REPLY_NAWS;
+                       case TTYPE:
+                               return WAIT_DO_REPLY_TTYPE;
+                       case LINEMODE:
+                               return WAIT_DO_REPLY_LINEMODE;
+                       case NEWENV:
+                               return WAIT_DO_REPLY_NEWENV;
+                       default:
+                               return false;
+               }
+                 
+               return false;
+       };
+       
+       function setWait(WHAT, OPTION, WAIT) {
+               switch (WHAT) {
+                       case DO:
+                       switch (OPTION) {
+                               case SUPGA:
+                                       WAIT_DO_REPLY_SUPGA = WAIT;
+                               break;
+                               case ECHO:
+                                       WAIT_DO_REPLY_ECHO = WAIT;
+                               break;
+                               case NAWS:
+                                       WAIT_DO_REPLY_NAWS = WAIT;
+                               break;
+                               case TTYPE:
+                                       WAIT_DO_REPLY_TTYPE = WAIT;
+                               break;
+                               case LINEMODE:
+                                       WAIT_DO_REPLY_LINEMODE = WAIT;
+                               break;
+                               case NEWENV:
+                                       WAIT_DO_REPLY_NEWENV = WAIT;
+                               break;
+                       }
+                       break;
+                       case WILL:
+                               switch (OPTION) {
+                               case SUPGA:
+                                       WAIT_WILL_REPLY_SUPGA = WAIT;
+                               break;
+                               case ECHO:
+                                       WAIT_WILL_REPLY_ECHO = WAIT;
+                               break;
+                               case NAWS:
+                                       WAIT_WILL_REPLY_NAWS = WAIT;
+                               break;
+                               case TTYPE:
+                                       WAIT_WILL_REPLY_TTYPE = WAIT;
+                               break;
+                       }
+                       break;
+               }
+                 
+               return false;
+       };
+
+       this.init();
+       
+};
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/src/telnet/Session.js b/wsproxy/jsTerm-master/src/telnet/Session.js
new file mode 100644 (file)
index 0000000..e5dc130
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Session = function (fontMapURL){
+       
+       var viewer;
+       var commands;
+
+       function initKeyboard() {
+               //document.addEventListener("keydown", function(e) {
+               document.onkeypress = function(e) {
+                       var key = e.keyCode || e.charCode;              
+                       console.log("TERM.Session fot getkey:"+e.keyCode);
+                       switch (key) {
+                               case KEYBOARD_LEFT :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_D);
+                               break;
+
+                               case KEYBOARD_RIGHT :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_C);
+                               break;
+
+                               case KEYBOARD_UP :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_A);
+                               break;
+
+                               case KEYBOARD_DOWN :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_B);
+                               break;
+
+                               case KEYBOARD_PAGE_UP :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_M);
+                               break;
+
+                               case KEYBOARD_PAGE_DOWN :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_H);
+                                       TERM.socket.writeByte(SEMICOLON);
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(DIGIT_TWO);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_J);
+                               break;
+
+                               case KEYBOARD_HOME :
+                                       TERM.socket.writeByte(ESCAPE);
+                                       TERM.socket.writeByte(LEFT_SQUARE_BRACKET);
+                                       TERM.socket.writeByte(LATIN_CAPITAL_LETTER_H);
+                               break;
+
+                               default:
+                                       TERM.socket.writeByte( key );
+                               break;
+
+                       }
+            return true;
+                       
+               //}, false);
+               };
+       };
+       
+       var fontmap = new Image();
+       fontmap.onload = function (){
+               viewer = new TERM.AnsiViewer(this);
+               commands = new TERM.Telnet(viewer);
+               
+               if(!("WebSocket" in window)) {
+               alert("Sorry, the build of your browser does not support HTML5 WebSockets.");
+               return;
+           }
+
+               initKeyboard();
+       };
+       fontmap.src = fontMapURL;
+       
+       this.connect = function(host, port) {
+               if(TERM.socket != undefined && TERM.socket.readyState == 1) {
+                       viewer.displayCleared();
+                       viewer.reposition(0, 0);
+                       //TERM.socket.send("telnet|"+host+"|"+port);
+                       TERM.socket.send("\n");
+               } else if(TERM.socket == undefined ){
+                       TERM.socket = new TERM.Socket();
+                       TERM.socket.init(host, port, function(e){
+                try {
+                   //alert("Got : "+e.data.toString());
+                                  //viewer.readBytes(e.data.toString());
+                                  viewer.readBytes(e.data);
+                   } catch (exp) {
+                     alert("Exception "+exp);
+                   }
+                       });
+               }
+       };
+       
+}
diff --git a/wsproxy/jsTerm-master/src/telnet/Socket.js b/wsproxy/jsTerm-master/src/telnet/Socket.js
new file mode 100644 (file)
index 0000000..8ea878a
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Socket = function (){
+       
+       var ws;
+       
+       this.init = function(host, port, onmessage){
+               ws = new WebSocket("ws://"+TERM.SERVER_URL+":"+TERM.SERVER_PORT+"/","telnet");
+               ws.binaryType = "arraybuffer";
+        ws.onmessage = onmessage;
+               ws.onclose = function(evt) {
+            //alert("Close ");
+           ws.close();
+           ws = null;
+        };
+           ws.onopen = function(evt) {
+            // alert("Open");
+                       //ws.send("telnet|"+host+"|"+port);
+                       ws.send("\n");
+
+           };
+        ws.onerror = function(evt)  { alert("Got an error "+evt.data.toString());};
+       };
+       
+       this.writeByte = function(code) {
+               ws.send(String.fromCharCode(code));
+       };
+
+       this.writeMultiByte = function(string, code) {
+               ws.send(string);
+       };
+       
+       this.send = function(packet){
+               ws.send(packet);
+       };
+       
+};
+
+TERM.Socket.prototype = {
+       get readyState(){
+               return ws.readyState;
+       }
+};
diff --git a/wsproxy/jsTerm-master/src/viewer/AnsiViewer.js b/wsproxy/jsTerm-master/src/viewer/AnsiViewer.js
new file mode 100644 (file)
index 0000000..8c590c4
--- /dev/null
@@ -0,0 +1,191 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.AnsiViewer = function (fontmap){
+       
+       this.cursor = new TERM.Cursor();
+       this.parser = new TERM.AnsiParser(this);
+       
+       var fontmap = fontmap;
+       var font = new TERM.Font();
+       var canvas = document.getElementById("canvas");
+       var width = canvas.width;
+       var height = canvas.height;
+       var topMargin = 1;
+       var botMargin = 25;
+       var ctx = canvas.getContext("2d");
+       var scroll = true;
+       var _savedPosition = new TERM.Point();
+       
+       this.readBytes = function (bytes) {
+               this.parser.parse(bytes);
+       };
+       
+       this.clearCanvas = function(){
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, 0, width, height);
+       };
+
+       this.colorTable = function(val) {
+               switch(val) {
+                       case BLACK_NORMAL: return 0; break;
+                       case BLUE_NORMAL: return 1; break;
+                       case GREEN_NORMAL: return 2; break;
+                       case CYAN_NORMAL: return 3; break;
+                       case RED_NORMAL: return 4; break;
+                       case MAGENTA_NORMAL: return 5; break;
+                       case YELLOW_NORMAL: return 6; break;
+                       case WHITE_NORMAL: return 7; break;
+                       case BLACK_BOLD: return 8; break;
+                       case BLUE_BOLD: return 9; break;
+                       case GREEN_BOLD: return 10; break;
+                       case CYAN_BOLD: return 11; break;
+                       case RED_BOLD: return 12; break;
+                       case MAGENTA_BOLD: return 13; break;
+                       case YELLOW_BOLD: return 14; break;
+                       case WHITE_BOLD: return 15; break;
+               }
+               return 0;
+       };
+
+       this.drawCharacter = function(character) {
+               this.draw(character);
+               this.cursor.moveForward(1);
+
+               if(!this.cursor.infinitewidth && this.cursor.x + this.cursor.columnWidth > this.cursor.maxColumnWidth * this.cursor.columnWidth){
+                       this.moveDown(1);
+                       this.cursor.carriageReturn();
+               }
+       };
+       
+       this.draw = function(charCode) {
+               //console.log(charCode +" "+ this.cursor.x +" "+ this.cursor.y)
+               
+               ctx.fillStyle = this.cursor.backgroundColor;
+               ctx.fillRect(this.cursor.x, this.cursor.y, font.width, font.height);
+
+               ctx.drawImage(fontmap, 
+                       charCode*(font.width+1), this.colorTable(this.cursor.foregroundColor)*font.height, font.width, font.height,
+                       this.cursor.x, this.cursor.y, font.width, font.height);
+       };
+       
+       this.carriageReturn = function() {
+               this.cursor.carriageReturn();
+       };
+       
+       this.formFeed = function() {
+               this.cursor.x = 0;
+               this.cursor.y = 0;
+       };
+
+       this.moveBackward = function(val, erase) {
+               var movements = val;
+
+               while( movements > 0 ) {
+                       this.cursor.moveBackward(1);
+                       if(erase) this.draw(SPACE);
+                       movements--;
+               }
+       };
+
+       this.moveDown = function(val) {
+        console.log("Viewer.moveDown "+this.cursor.y+" max "+(this.cursor.lineHeight*(botMargin-1)) );
+               if(this.cursor.y >= this.cursor.lineHeight*(botMargin-1) && scroll){
+                       this.scrollUp(1);
+               } else {
+                       this.cursor.moveDown(val);
+               }
+       };
+
+       this.moveForward = function(val) {
+               this.cursor.moveForward(val);
+       };
+
+       this.moveUp = function(val) {
+               this.cursor.moveUp(val);
+       };
+
+       this.reposition = function(x, y) {
+               this.cursor.x = x * this.cursor.columnWidth;
+               this.cursor.y = y * this.cursor.lineHeight;
+       };
+
+       this.restorePosition = function() {
+               this.cursor.x = _savedPosition.x;
+               this.cursor.y = _savedPosition.y;
+       };
+
+       this.savePosition = function() {
+               _savedPosition.x = this.cursor.x;
+               _savedPosition.y = this.cursor.y;
+       };
+
+       this.displayCleared = function() {
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, 0, this.cursor.maxColumnWidth * this.cursor.columnWidth, this.cursor.maxLineHeight * this.cursor.lineHeight);
+       };
+       
+       this.eraseUp = function() {
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, 0, this.cursor.maxColumnWidth * this.cursor.columnWidth, this.cursor.y);
+       };
+
+       this.eraseScreen = function() {
+               ctx.fillStyle = this.cursor.backgroundColor;
+               ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnWidth, this.cursor.maxLineHeight * this.cursor.lineHeight);
+       };
+
+       this.eraseDown = function() {
+        console.log("Viewer::eraseDown 0,"+this.cursor.y);
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnWidth * this.cursor.columnWidth, (this.cursor.maxLineHeight * this.cursor.lineHeight) - this.cursor.y);
+       };
+
+       this.eraseEndOfLine = function() {
+               ctx.fillStyle = BLACK_NORMAL;
+               var w = (this.cursor.maxColumnWidth * this.cursor.columnWidth) - (this.cursor.x - this.cursor.columnWidth);
+               ctx.fillRect(this.cursor.x, this.cursor.y, w, this.cursor.lineHeight);
+       };
+
+       this.eraseStartOfLine = function() {
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, this.cursor.y, this.cursor.x, this.cursor.lineHeight);
+       };
+
+       this.eraseLine = function() {
+               ctx.fillStyle = BLACK_NORMAL;
+               ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnWidth * this.cursor.columnWidth, this.cursor.lineHeight);
+       };
+       
+       this.backgroundColorChanged = function(color) {
+               this.cursor.backgroundColor = color;
+       };
+
+       this.foregroundColorChanged = function(color) {
+               this.cursor.foregroundColor = color;
+       };
+
+       this.home = function() {
+               this.cursor.x = 0;
+               this.cursor.y = (topMargin-1) * this.cursor.maxLineHeight;
+       };
+
+       this.scrollScreen = function(start, end) {
+        console.log("Viewer::scrollScreen handle Home KO start="+start+" end="+end+" topM="+topMargin+" "+botMargin);
+               topMargin = start;
+               if (end >0 && end < 25)
+          botMargin = end;
+               this.scrollUp(start);
+               handleHome();
+       };
+       
+       this.scrollUp = function(val) {
+               var canvasData = ctx.getImageData(0, topMargin * this.cursor.lineHeight, this.cursor.maxColumnWidth*this.cursor.columnWidth, this.cursor.lineHeight * (botMargin-topMargin));
+               this.displayCleared();
+               ctx.putImageData(canvasData, 0, this.cursor.lineHeight*(topMargin-1));
+       };
+       
+       this.clearCanvas();
+
+};
diff --git a/wsproxy/jsTerm-master/src/viewer/Cursor.js b/wsproxy/jsTerm-master/src/viewer/Cursor.js
new file mode 100644 (file)
index 0000000..9287e68
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Cursor = function (){
+       
+       this.foregroundColor = WHITE_NORMAL;
+       this.backgroundColor = BLACK_NORMAL;
+       this.position = new TERM.Point();
+       this.maxColumnWidth = 80;
+       this.maxLineHeight = 25;
+       this.columnWidth = 8;
+       this.lineHeight = 16;
+       this.maxColumns = 80;
+       this.infiniteWidth = false;
+       this.infiniteHeight = false;
+               
+       this.moveForward = function(columns) {
+               if( this.position.x + (columns*this.columnWidth) <= this.maxColumns * this.columnWidth )
+                       this.position.x = this.position.x + (columns*this.columnWidth);
+               else {
+                       //this.position.x = (this.maxColumns * this.columnWidth) - this.columnWidth;
+            this.position.x = 0;
+            this.moveDown(1);
+        }
+       };      
+               
+       this.moveBackward = function(columns) {
+               if( this.position.x - (columns*this.columnWidth) >= 0 )
+                       this.position.x = this.position.x - (columns*this.columnWidth);
+               else
+                       this.position.x = 0;
+       };
+
+       this.moveDown = function(lines) {
+               this.position.y = this.position.y + (lines*this.lineHeight);
+       };
+
+       this.moveUp = function(lines) {
+               if( this.position.y - (lines*this.lineHeight) >= 0 ) 
+                       this.position.y = this.position.y - (lines*this.lineHeight);
+               else
+                       this.position.y = 0;
+       };
+
+       this.carriageReturn = function() {
+               this.position.x = 0;
+ //       this.moveDown(1);
+       };
+       
+};
+
+TERM.Cursor.prototype = {
+       
+       get x (){
+               return this.position.x;
+       },
+       set x (val){
+               this.position.x = val;
+       },
+       
+       get y (){
+               return this.position.y;
+       },
+       set y (val){
+               this.position.y = val;
+       }
+       
+};
diff --git a/wsproxy/jsTerm-master/src/viewer/Font.js b/wsproxy/jsTerm-master/src/viewer/Font.js
new file mode 100644 (file)
index 0000000..794290e
--- /dev/null
@@ -0,0 +1,11 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Font = function() {
+       
+       this.width = 8;
+       this.height = 16;
+       this.lineHeight = 23;
+       
+};
\ No newline at end of file
diff --git a/wsproxy/jsTerm-master/src/viewer/Point.js b/wsproxy/jsTerm-master/src/viewer/Point.js
new file mode 100644 (file)
index 0000000..b31b4c9
--- /dev/null
@@ -0,0 +1,10 @@
+/**
+ * @author Peter Nitsch
+ */
+
+TERM.Point = function() {
+       
+       this.x = 0;
+       this.y = 0;
+       
+};
\ No newline at end of file
diff --git a/wsproxy/main.cpp b/wsproxy/main.cpp
new file mode 100644 (file)
index 0000000..2df0976
--- /dev/null
@@ -0,0 +1,450 @@
+#include <iostream>
+#include <list>
+#include <limits>
+#include <cstdlib>
+
+#include <aeb/net/ip/tcp.h>
+#include <aeb/net/ip/basic_endpoint.h>
+#include <aeb/net/socket_base.h>
+#include <aeb/net/io_dispatcher.h>
+#include <aeb/net/basic_socket_acceptor.h>
+#include <aeb/net/basic_socket_stream.h>
+#include <aeb/pointer/intrusive_ptr.h>
+#if defined(__MINGW32__)
+#include <aeb/net/detail/winsock_init.h>
+#endif
+
+// Signal stuff
+#include <signal.h>
+#include <stdlib.h>
+#include <fstream>
+using namespace aeb::net;
+typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+typedef aeb::net::basic_socket<ip::tcp> tcp_socket;
+
+#include <reverse_proxy.h>
+
+#include "ws_allocator.h"
+#include "ws_log.h"
+#include "ws_constant.h"
+#include "ws_frame.h"
+
+#include "ws_proxy_endpoint.h"
+#include "ws_proxy_handler.h"
+#include "ws_acceptor.h"
+
+#include "ws_handler_factory.h"
+#include <xsd/xsd.h>
+#include <xsd/parser/expat/elements.h>
+
+#include <p_reverse_proxy.h>
+
+#include "optionparser.h"
+/**
+ * plugin stuff 
+ */
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "ws_plugin_manager.h"
+
+
+// Local debug macro
+#define LOG_MAIN_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0);
+#define LOG_MAIN_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n" ,args);} while (0) 
+
+#define LOG_MAIN_INFO(x) do {m_logger->log(eLOG_INFO,"%s\n",x);} while (0);
+#define LOG_MAIN_INFO_FMT(format,args...) do { m_logger->log(eLOG_INFO,format "\n",args);} while (0) ;
+
+#define LOG_MAIN_NOTICE(x) do {m_logger->log(eLOG_NOTICE,"%s\n",x);} while (0);
+#define LOG_MAIN_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args);} while (0) ;
+
+#define LOG_MAIN_WARN(x) do {m_logger->log(eLOG_WARN,"%s\n",x);} while (0);
+#define LOG_MAIN_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args);} while (0) ;
+
+#define LOG_MAIN_ERROR(x) do {m_logger->log(eLOG_ERROR,"%s\n",x);} while (0);
+#define LOG_MAIN_ERROR_FMT(format,args...) do {m_logger->log(eLOG_ERROR,format "\n",args);} while (0) ;
+
+static ws_log *m_logger = ws_log::getInstance("wsproxy");
+
+using namespace wsproxy;
+
+typedef std::list<ws_acceptor::ptr>::iterator acceptor_iterator;
+
+std::list<ws_acceptor::ptr> g_acceptors;
+
+
+//
+// Load configuration
+//
+int load_configuration(const char *filename,ConfigurationType_skel &config)
+{
+    xsd::parser::SimpleElement se;
+    p_ConfigurationType_skel   p;
+    p_GatewayType_skel         p_gateway;
+    p_ReverseProxyType_skel    p_rproxy;
+    p_ApplicationType_skel     p_app;
+    p_WsApplicationType_skel   p_wsapp;
+    p_WebSocketType_skel       p_ws;
+    p_AccessFilterType_skel    p_ar;
+    p_ListAuthorization_skel   p_lauth;
+    p_ListGateway_skel         p_lg;
+    p_LogType_skel             p_log;
+    p_LogLevel_skel            p_logl;
+    p_GlobalType_skel          p_global;
+    p_ParamType_skel           p_param;
+    p_PluginsType_skel         p_plugins;
+    p_PluginType_skel          p_plugin;
+    // set parser 
+    p.listen_parser(p_gateway);
+    p.plugins_parser(p_plugins);
+    p.rproxy_parser(p_rproxy);
+    p.websocket_parser(p_ws);
+    p.global_parser(p_global);
+    //
+    p_global.log_parser(p_log);
+    //
+    //p_log.name_parser(se);
+    p_log.level_parser(p_logl);
+    //p_log.syslog_parser(se);
+    p_plugins.plugin_parser(p_plugin);
+    //
+    p_global.workers_parser(se);
+    p_global.user_parser(se);
+    p_global.group_parser(se);
+    //
+    p_gateway.host_parser(se);
+    p_gateway.port_parser(se);
+    p_gateway.certfile_parser(se);
+    
+    p_rproxy.application_parser(p_app);
+    p_ar.authorize_parser(p_lauth);
+    p_ar.gateway_parser(p_lg);
+    p_app.access_filter_parser(p_ar);
+    p_app.filter_parser(se);
+    p_app.param_parser(p_param);
+    
+    //
+    p_ws.application_parser(p_wsapp);
+    // p_app.name_parser(se);
+    // p_app.host_parser(se);
+    // p_app_port_parser(se);
+    // start parsing
+    std::ifstream iss1;
+    iss1.open(filename,std::ifstream::in);
+    xsd::parser::expat::Document doc(p,"CONFIGURATION");
+    doc.parse(iss1);
+    p.post(config);
+
+}
+
+//
+//  Setup log levels
+//
+void setup_log( wsproxy::GlobalType_skel &g)
+{
+  if (g.log().size() == 0)
+  {
+    std::cerr<<"setup_log no log entries in configuration file"<<std::endl;
+    return;
+  }
+
+  wsproxy::GlobalType_skel::log_sequence::iterator it = g.log().begin();
+  
+  for ( ; it != g.log().end() ; ++it) 
+  {
+      if (! std::string("DEBUG").compare((*it)->attr_level().content()))
+      {
+          ws_log::getInstance((*it)->attr_name())->set_level(eLOG_DEBUG);
+      }
+      else if (! std::string("NOTICE").compare((*it)->attr_level().content()))
+      {
+          ws_log::getInstance((*it)->attr_name())->set_level(eLOG_NOTICE);
+      }
+      else if (! std::string("WARNING").compare((*it)->attr_level().content()))
+      {
+          ws_log::getInstance((*it)->attr_name())->set_level(eLOG_WARN);
+      }
+      else if (! std::string("ERROR").compare((*it)->attr_level().content()))
+      {
+          ws_log::getInstance((*it)->attr_name())->set_level(eLOG_ERROR);
+      }
+      else if (! std::string("INFO").compare((*it)->attr_level().content()))
+      {
+          ws_log::getInstance((*it)->attr_name())->set_level(eLOG_INFO);
+      }
+      // Set syslog
+      if ((*it)->attr_syslog()) 
+      {
+        ws_log::getInstance((*it)->attr_name())->set_syslog() ;
+      }
+      // Check if log to file
+      if ( (*it)->isset_file()) 
+      {
+      }
+  }
+}
+
+//
+// Signal Handlers
+//
+volatile sig_atomic_t main_running = true;
+
+void main_stop(int sig)
+{
+  LOG_MAIN_DEBUG_FMT("main_stop: signal %d",sig);
+  main_running = false;
+  return ;
+}
+
+/**
+ * Option management
+ */
+enum optionIndex {UNKNOWN, HELP, DBG,FICHIER,DAEMON,OPT_END};
+
+const option::Descriptor usage[] = {
+   {UNKNOWN,      0, "", "",         option::Arg::None,"Usage wsproxy [options]\n\texample: wsproxy -D -c /users/toto/config.xml \n"},
+   {HELP,         0, "h", "help",    option::Arg::None,"--help,-h \tPrint help and quit."},
+   {DBG,          0, "d", "debug",   option::Arg::Optional,"--debug,-d \tDebug mode"},
+   {FICHIER,      0, "c", "config",  option::Arg::Required,"--config,-c \txml configuration file"},
+   {DAEMON,       0, "D", "daemon",   option::Arg::None,"--daemon,-D \tRun program as daemon"},
+   {0,0,0,0,0,0}
+};
+
+typedef ws_allocator<char,32> ws32_alloc;
+typedef std::basic_string<char,std::char_traits<char>,ws32_alloc> ws32_string;
+
+//
+// Main entry point 
+//
+int main(int argc, char **argv)
+{
+
+  ConfigurationType_skel config;
+  ip::basic_endpoint<ip::tcp> ep(ip::tcp::v4(),10222);
+
+  std::vector<ip::tcp::endpoint_type> endpoints;
+
+  {
+    ws32_alloc alloc;
+    ws32_string str;
+    str = "DEDE";
+    std::cout<<str<<std::endl;
+  }
+  signal(SIGTERM,main_stop); // Kill -TERM
+  signal(SIGINT,main_stop);  // ^C
+  signal(SIGQUIT,main_stop); // Looks like backgound
+  //signal(SIGPIPE,main_stop);
+  signal(SIGPIPE,SIG_IGN);
+
+  // Block SIGTERM.
+  sigset_t sigset, oldset,oldloopset;
+  sigemptyset(&sigset);
+  // sigaddset(&sigset, SIGTERM);
+  // sigaddset(&sigset, SIGINT);
+  // sigprocmask(SIG_BLOCK, &sigset, &oldset);
+
+  // Option stuff must go here
+  option::Stats   stats(usage,argc-1,&argv[1]);
+  const int       max(stats.options_max);
+  option::Option  options[OPT_END*2],buffer[OPT_END*3];
+  option::Parser  parser(usage,argc-1,&argv[1],options,buffer);
+  if (parser.error()) 
+  {
+      return 1;
+  }
+  if (options[HELP] )
+  {
+      option::printUsage(std::cout,usage);
+      return 1;
+  }
+  
+
+  // Maybe add some stuff to make it a deamon, change the user and so one
+  // to secure the process
+  if (options[FICHIER] )
+  {
+    option::Option *opt = options[FICHIER];
+    if (opt->arg)
+    {
+      load_configuration(opt->arg,config);
+    } else 
+    {
+      return 1;
+    }
+  } else {
+    // Lookup for config file in several places before trying to load the config
+    load_configuration("wsproxy.xml",config);
+  }
+  //
+  if (config.isset_global() ) 
+  {
+    setup_log(config.global());
+  } else 
+  {
+    LOG_MAIN_ERROR("main config.global not available in wsproxy.xml file");
+    exit(1);
+  }
+  // Handle daemon feature ....
+  if ( options[DAEMON] )
+  {
+    // Allright, fork ....
+    if ( pid_t pid = fork() )
+    {
+      // Parent process continues here.
+      if ( pid > 0 ) {
+        // detach from main ...
+        exit(0);
+      } else {
+        // Failure
+        LOG_MAIN_ERROR("Failed fork");
+        return 1;
+      }
+    } 
+    // child process here (pid == 0)
+    setsid();
+  }
+
+  /**
+   * trying to Load Plugins
+   */
+  LOG_MAIN_INFO("Loading plugins...");
+  ws_plugin_manager *mgr = ws_plugin_manager::getInstance("plugins");
+  
+  try 
+  {
+    if (mgr && config.isset_plugins() )
+    {
+        PluginsType_skel::plugin_sequence::iterator pit = config.plugins().plugin().begin();
+        for (; pit != config.plugins().plugin().end() ; ++pit)
+        {
+          std::string pn = (*pit)->attr_load() ;
+          ws_plugin *p_default =  mgr->load_plugin(pn);
+          if (p_default)
+          {
+            LOG_MAIN_INFO_FMT("Loaded plugin %s",pn.c_str());
+            // p_default->register_hooks();
+          } else {
+            LOG_MAIN_ERROR_FMT("Load Failed for plugin %s ",pn.c_str());
+          }
+        }
+
+    }
+  }
+  catch (std::exception &e)
+  {
+   LOG_MAIN_ERROR_FMT("EXCEPTION: %s",e.what());
+  }
+  
+  // Loop over ports to listen to
+  ConfigurationType_skel::listen_sequence::iterator it = config.listen().begin();
+  for ( ; it != config.listen().end() ; ++it)
+  {
+    ip::basic_endpoint<ip::tcp> eps(ip::tcp::v4(),(*it)->port());
+    endpoints.push_back(eps);
+    LOG_MAIN_DEBUG_FMT("Listen on port: %d",(*it)->port());
+  }
+
+  // Loop over rporxy applications
+  ReverseProxyType_skel::application_sequence::iterator it_app = config.rproxy().application().begin();
+  if (config.isset_rproxy() ) 
+  {
+    for ( ; it_app != config.rproxy().application().end() ; ++it_app)
+    {
+      LOG_MAIN_INFO_FMT("Reverse Proxy Backend <%s>\tconnect to : %s on port : %d"
+        , (*it_app)->attr_name().c_str()
+        , (*it_app)->attr_host().c_str()
+        , (*it_app)->attr_port()
+        );
+      if ( (*it_app)->isset_access_filter()) 
+      {
+        AccessFilterType_skel  access_filter((*it_app)->access_filter());
+        ListGateway_skel       gw(access_filter.attr_gateway());
+        ListAuthorization_skel  autorisations(access_filter.attr_authorize());
+        LOG_MAIN_INFO_FMT("Access Filter autorize length <%d> gw<%d>",autorisations.size(),gw.size());
+      }
+      // Alright, do the real job and register  the appropriate acceptor
+    }
+  }
+  // Loop over websocket applications
+  if (config.isset_websocket() ) 
+  {
+    WebSocketType_skel::application_sequence::iterator it_wsapp = config.websocket().application().begin();
+    for ( ; it_wsapp != config.websocket().application().end() ; ++it_wsapp)
+    {
+      LOG_MAIN_INFO_FMT("WebSock Proxy Backend <%s>\tconnect to : %s on port : %d"
+        , (*it_wsapp)->attr_name().c_str()
+        , (*it_wsapp)->attr_host().c_str()
+        , (*it_wsapp)->attr_port()
+        );
+    }
+  } else 
+  {
+    LOG_MAIN_WARN("No Web Socket application backend defined");
+  }
+
+  io_service *io = aeb::singleton<io_service>::get_instance();
+  try 
+  {
+    // Register all ws application with all acceptors
+    for ( std::vector<ip::tcp::endpoint_type>::const_iterator ite = endpoints.begin() 
+        ; ite != endpoints.end() 
+        ; ++ite)
+    {
+      int *i = new int;
+      LOG_MAIN_DEBUG_FMT("Web Socket application start acceptor %d",endpoints.size());
+      try 
+      {
+        ws_acceptor::ptr ws_ac( new ws_acceptor( (*ite)
+                                                 ,config.rproxy().application()) 
+                               );
+
+        ws_ac->listen();
+        g_acceptors.push_back(ws_ac);
+        io->register_handler(2,(ws_acceptor *)ws_ac);
+      }
+      catch (std::exception &e) 
+      {
+        LOG_MAIN_ERROR_FMT("EXCEPTION when creating acceptor %s",e.what());
+      }
+      LOG_MAIN_DEBUG_FMT("Web Socket application end acceptor %d",endpoints.size());
+    }
+
+    do
+    {
+        sigprocmask(SIG_SETMASK,&sigset,&oldloopset);
+        io->run(true);
+        sigprocmask(SIG_SETMASK,&sigset,NULL);
+    }
+    while (main_running);
+
+  }
+  catch (std::exception &e) 
+  {
+    std::cout<<e.what()<<std::endl;
+    main_running = false;   
+  }
+
+  LOG_MAIN_NOTICE("Normal Existing");
+  ws_handler_factory::get_instance()->close_handlers();
+  LOG_MAIN_NOTICE("Shutdown listening sockets");
+  acceptor_iterator ait = g_acceptors.begin();
+  for( ; ait != g_acceptors.end() ; ++ait)
+  {
+    (*ait)->shutdown(SHUT_RDWR);
+  }
+
+  LOG_MAIN_DEBUG("Shutdown Wait one more round to normal end");
+  io->run(true);
+  // Unregister
+  ait = g_acceptors.begin();
+  for( ; ait != g_acceptors.end() ; ++ait)
+  {
+    io->unregister_handler(2,(ws_acceptor *)(*ait));
+  }
+  // destroy listener
+  g_acceptors.erase(g_acceptors.begin(),g_acceptors.end());
+  LOG_MAIN_NOTICE_FMT("Exist %s",argv[0]);
+}
+/**
+  :vim:et:sw=2:ts=2:
+ */
diff --git a/wsproxy/plugins/CMakeLists.txt b/wsproxy/plugins/CMakeLists.txt
new file mode 100644 (file)
index 0000000..562478b
--- /dev/null
@@ -0,0 +1,9 @@
+PROJECT(ws-plugins)
+
+INCLUDE_DIRECTORIES(".")
+
+ADD_LIBRARY(plugin_default SHARED plugin_default.cpp)
+SET_TARGET_PROPERTIES(plugin_default PROPERTIES COMPILE_FLAGS -fPIC)
+SET_TARGET_PROPERTIES(plugin_default PROPERTIES LINK_FLAGS -Wl)
+ADD_LIBRARY(plugin_log     SHARED plugin_log.cpp)
+SET_TARGET_PROPERTIES(plugin_log PROPERTIES COMPILE_FLAGS -fPIC)
diff --git a/wsproxy/plugins/plugin_auth.h b/wsproxy/plugins/plugin_auth.h
new file mode 100644 (file)
index 0000000..67882f3
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef PLUGIN_AUTH_H
+#define PLUGIN_AUTH_H
+#endif /*PLUGIN_AUTH_H*/
diff --git a/wsproxy/plugins/plugin_default.cpp b/wsproxy/plugins/plugin_default.cpp
new file mode 100644 (file)
index 0000000..5a8070c
--- /dev/null
@@ -0,0 +1,66 @@
+#include <iostream>
+#include <map>
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "plugin_default.h"
+
+/**
+ * Default handler 
+ */
+class default_handler : public ws_plugin_handler {
+  public:
+      default_handler();
+      default_handler(const default_handler &r);
+      ~default_handler();
+
+      int handle_request(ws_plugin_request &r);
+};
+
+// default Contructor
+default_handler::default_handler()
+{
+}
+
+//
+default_handler::default_handler(const default_handler   &o)
+{
+}
+
+// default Desctructor
+default_handler::~default_handler()
+{
+}
+
+int
+default_handler::handle_request(ws_plugin_request &r)
+{
+  std::cout<<"default_handler::handle_request"<<std::endl;
+  return PLUGIN_OK;
+}
+
+/**
+ *  plugin_default implementation
+ */
+
+plugin_default::plugin_default(const std::string &name) : ws_plugin(name)
+{
+
+  std::cout<<"plugin_default::plugin_default contructor with name("<<name<<")"<<std::endl;
+}
+
+void plugin_default::register_hooks()
+{
+  std::cout<<"plugin_default::register_hooks"<<std::endl;
+}
+
+
+
+
+/*
+ * Function that will create the plugin.
+ *   will be called after dlopen
+ */
+extern "C" void *create_plugin() {
+  return new plugin_default("plugin_default");
+
+}
diff --git a/wsproxy/plugins/plugin_default.h b/wsproxy/plugins/plugin_default.h
new file mode 100644 (file)
index 0000000..f8023de
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef PLUGIN_DEFAULT_H
+#define PLUGIN_DEFAULT_H
+
+
+/**
+ * class plugin_default
+ *
+ * \brief
+ * \author
+ */
+class plugin_default : ws_plugin {
+  public:
+    //
+    plugin_default(const std::string &_n) ;
+    //
+    plugin_default(const plugin_default &o) ;
+    //
+    ~plugin_default() ;
+
+    void register_hooks() ;
+  protected:
+};
+
+
+#endif /*PLUGIN_DEFAULT_H*/
diff --git a/wsproxy/plugins/plugin_log.cpp b/wsproxy/plugins/plugin_log.cpp
new file mode 100644 (file)
index 0000000..48e53a8
--- /dev/null
@@ -0,0 +1,69 @@
+#include <iostream>
+#include <map>
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "plugin_log.h"
+
+/**
+ * Default handler 
+ */
+class log_handler : public ws_plugin_handler {
+  public:
+      log_handler();
+      log_handler(const log_handler &r);
+      ~log_handler();
+
+      int handle_request(ws_plugin_request &r);
+};
+
+// default Contructor
+log_handler::log_handler()
+{
+}
+
+//
+log_handler::log_handler(const log_handler   &o)
+{
+}
+
+// default Desctructor
+log_handler::~log_handler()
+{
+}
+
+int
+log_handler::handle_request(ws_plugin_request &r)
+{
+  std::cout<<"log_handler::handle_request"<<std::endl;
+  return PLUGIN_OK;
+}
+
+/**
+ *  plugin_log implementation
+ */
+
+plugin_log::plugin_log(const std::string &name) : ws_plugin(name)
+{
+
+  std::cout<<"plugin_log::plugin_log contructor with name("<<name<<")"<<std::endl;
+}
+
+void plugin_log::register_hooks()
+{
+  std::cout<<"plugin_log::register_hooks"<<std::endl;
+}
+
+
+
+
+/*
+ * Function that will create the plugin.
+ *   will be called after dlopen
+ */
+extern "C" {
+
+void *create_plugin() {
+  return new plugin_log("plugin_log");
+}
+
+}
diff --git a/wsproxy/plugins/plugin_log.h b/wsproxy/plugins/plugin_log.h
new file mode 100644 (file)
index 0000000..7b23d8f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef PLUGIN_LOG_H
+#define PLUGIN_LOG_H
+
+
+/**
+ * class plugin_log
+ *
+ * \brief
+ * \author
+ */
+class plugin_log : ws_plugin {
+  public:
+    //
+    plugin_log(const std::string &_n) ;
+    //
+    plugin_log(const plugin_log &o) ;
+    //
+    ~plugin_log() ;
+
+    void register_hooks() ;
+  protected:
+};
+
+
+#endif /*PLUGIN_DEFAULT_H*/
diff --git a/wsproxy/plugins/plugin_ssl.cpp b/wsproxy/plugins/plugin_ssl.cpp
new file mode 100644 (file)
index 0000000..cdce306
--- /dev/null
@@ -0,0 +1,69 @@
+#include <iostream>
+#include <map>
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "plugin_ssl.h"
+
+/**
+ * Default handler 
+ */
+class ssl_handler : public ws_plugin_handler {
+  public:
+      ssl_handler();
+      ssl_handler(const ssl_handler &r);
+      ~ssl_handler();
+
+      int handle_request(ws_plugin_request &r);
+};
+
+// default Contructor
+ssl_handler::ssl_handler()
+{
+}
+
+//
+ssl_handler::ssl_handler(const ssl_handler   &o)
+{
+}
+
+// default Desctructor
+ssl_handler::~ssl_handler()
+{
+}
+
+int
+ssl_handler::handle_request(ws_plugin_request &r)
+{
+  std::cout<<"ssl_handler::handle_request"<<std::endl;
+  return PLUGIN_OK;
+}
+
+/**
+ *  plugin_ssl implementation
+ */
+
+plugin_ssl::plugin_ssl(const std::string &name) : ws_plugin(name)
+{
+
+  std::cout<<"plugin_ssl::plugin_ssl contructor with name("<<name<<")"<<std::endl;
+}
+
+void plugin_ssl::register_hooks()
+{
+  std::cout<<"plugin_ssl::register_hooks"<<std::endl;
+  // core.register_conn_hook();
+  //
+  // core.register_log_hook(ssl_handler);
+}
+
+
+
+
+/*
+ * Function that will create the plugin.
+ *   will be called after dlopen
+ */
+extern "C" void *create_plugin() {
+  return new plugin_ssl("plugin_ssl");
+
+}
diff --git a/wsproxy/plugins/plugin_ssl.h b/wsproxy/plugins/plugin_ssl.h
new file mode 100644 (file)
index 0000000..82fd832
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef PLUGIN_SSL_H
+#define PLUGIN_SSL_H
+/**
+ * class plugin_ssl
+ *
+ * \brief
+ * \author
+ */
+class plugin_ssl : ws_plugin {
+  public:
+    //
+    plugin_ssl(const std::string &_n) ;
+    //
+    plugin_ssl(const plugin_ssl &o) ;
+    //
+    ~plugin_ssl() ;
+
+    void register_hooks() ;
+  protected:
+};
+
+#endif /*PLUGIN_SSL_H*/
diff --git a/wsproxy/plugins/plugin_ws.cpp b/wsproxy/plugins/plugin_ws.cpp
new file mode 100644 (file)
index 0000000..e53630c
--- /dev/null
@@ -0,0 +1,66 @@
+#include <iostream>
+#include <map>
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "plugin_ws.h"
+
+/**
+ * Default handler 
+ */
+class ws_handler : public ws_plugin_handler {
+  public:
+      ws_handler();
+      ws_handler(const ws_handler &r);
+      ~ws_handler();
+
+      int handle_request(ws_plugin_request &r);
+};
+
+// default Contructor
+ws_handler::ws_handler()
+{
+}
+
+//
+ws_handler::ws_handler(const ws_handler   &o)
+{
+}
+
+// default Desctructor
+ws_handler::~ws_handler()
+{
+}
+
+int
+ws_handler::handle_request(ws_plugin_request &r)
+{
+  std::cout<<"ws_handler::handle_request"<<std::endl;
+  return PLUGIN_OK;
+}
+
+/**
+ *  plugin_ws implementation
+ */
+
+plugin_ws::plugin_ws(const std::string &name) : ws_plugin(name)
+{
+
+  std::cout<<"plugin_ws::plugin_ws contructor with name("<<name<<")"<<std::endl;
+}
+
+void plugin_ws::register_hooks()
+{
+  std::cout<<"plugin_ws::register_hooks"<<std::endl;
+}
+
+
+
+
+/*
+ * Function that will create the plugin.
+ *   will be called after dlopen
+ */
+extern "C" void *create_plugin() {
+  return new plugin_ws("plugin_ws");
+
+}
diff --git a/wsproxy/plugins/plugin_ws.h b/wsproxy/plugins/plugin_ws.h
new file mode 100644 (file)
index 0000000..300e778
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef PLUGIN_WS_H
+#define PLUGIN_WS_H
+
+
+/**
+ * class plugin_ws
+ *
+ * \brief
+ * \author
+ */
+class plugin_ws : ws_plugin {
+  public:
+    //
+    plugin_ws(const std::string &_n) ;
+    //
+    plugin_ws(const plugin_ws &o) ;
+    //
+    ~plugin_ws() ;
+
+    void register_hooks() ;
+  protected:
+};
+
+
+#endif /*PLUGIN_WS_H*/
diff --git a/wsproxy/ressources/echo.html b/wsproxy/ressources/echo.html
new file mode 100644 (file)
index 0000000..aef37fa
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+
+<meta charset="utf-8" />
+
+<title>WebSocket Test</title>
+
+<script language="javascript" type="text/javascript">
+
+  //var wsUri = "ws://echo.websocket.org/";
+  var wsUri = "ws://172.25.16.146:10222/";
+  var output;
+
+  function init()
+  {
+    output = document.getElementById("output");
+    testWebSocket();
+  }
+
+  function testWebSocket()
+  {
+    websocket = new WebSocket(wsUri,"echo");
+    //websocket = new WebSocket(wsUri);
+    websocket.onopen = function(evt) { onOpen(evt) };
+    websocket.onclose = function(evt) { onClose(evt) };
+    websocket.onmessage = function(evt) { onMessage(evt) };
+    websocket.onerror = function(evt) { onError(evt) };
+  }
+
+  function onOpen(evt)
+  {
+    writeToScreen("CONNECTED");
+    doSend("WebSocket rocks");
+  }
+
+  function onClose(evt)
+  {
+    writeToScreen("DISCONNECTED");
+  }
+
+  function onMessage(evt)
+  {
+    writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
+    websocket.close();
+  }
+
+  function onError(evt)
+  {
+    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
+  }
+
+  function doSend(message)
+  {
+    writeToScreen("SENT: " + message); 
+    websocket.send(message);
+  }
+
+  function writeToScreen(message)
+  {
+    var pre = document.createElement("p");
+    pre.style.wordWrap = "break-word";
+    pre.innerHTML = message;
+    output.appendChild(pre);
+  }
+
+  window.addEventListener("load", init, false);
+
+</script>
+
+<h2>WebSocket Test</h2>
+
+<div id="output"></div>
diff --git a/wsproxy/ressources/oxo.html b/wsproxy/ressources/oxo.html
new file mode 100644 (file)
index 0000000..12c7c3c
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+
+<meta charset="utf-8" />
+
+<title>WebSocket Test</title>
+
+<script language="javascript" type="text/javascript">
+
+  //var wsUri = "ws://echo.websocket.org/";
+  var wsUri = "ws://172.25.16.146:10222/";
+  var output;
+
+  function init()
+  {
+    output = document.getElementById("output");
+    testWebSocket();
+  }
+
+  function testWebSocket()
+  {
+    //websocket = new WebSocket(wsUri,"echo");
+    websocket = new WebSocket(wsUri);
+    websocket.onopen = function(evt) { onOpen(evt) };
+    websocket.onclose = function(evt) { onClose(evt) };
+    websocket.onmessage = function(evt) { onMessage(evt) };
+    websocket.onerror = function(evt) { onError(evt) };
+  }
+
+  function onOpen(evt)
+  {
+    writeToScreen("CONNECTED");
+    doSend("WebSocket rocks");
+  }
+
+  function onClose(evt)
+  {
+    writeToScreen("DISCONNECTED");
+  }
+
+  function onMessage(evt)
+  {
+    writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
+    websocket.close();
+  }
+
+  function onError(evt)
+  {
+    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
+  }
+
+  function doSend(message)
+  {
+    writeToScreen("SENT: " + message); 
+    websocket.send(message);
+  }
+
+  function writeToScreen(message)
+  {
+    var pre = document.createElement("p");
+    pre.style.wordWrap = "break-word";
+    pre.innerHTML = message;
+    output.appendChild(pre);
+  }
+
+  window.addEventListener("load", init, false);
+
+</script>
+
+<h2>WebSocket Test</h2>
+
+<div id="output"></div>
diff --git a/wsproxy/sha1.cpp b/wsproxy/sha1.cpp
new file mode 100755 (executable)
index 0000000..49c5045
--- /dev/null
@@ -0,0 +1,185 @@
+/*\r
+ Copyright (c) 2011, Micael Hildenborg\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions are met:\r
+    * Redistributions of source code must retain the above copyright\r
+      notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright\r
+      notice, this list of conditions and the following disclaimer in the\r
+      documentation and/or other materials provided with the distribution.\r
+    * Neither the name of Micael Hildenborg nor the\r
+      names of its contributors may be used to endorse or promote products\r
+      derived from this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\r
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\r
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ Contributors:\r
+ Gustav\r
+ Several members in the gamedev.se forum.\r
+ Gregory Petrosyan\r
+ */\r
+\r
+#include "sha1.h"\r
+\r
+namespace sha1\r
+{\r
+    namespace // local\r
+    {\r
+        // Rotate an integer value to left.\r
+        inline const unsigned int rol(const unsigned int value,\r
+                const unsigned int steps)\r
+        {\r
+            return ((value << steps) | (value >> (32 - steps)));\r
+        }\r
+\r
+        // Sets the first 16 integers in the buffert to zero.\r
+        // Used for clearing the W buffert.\r
+        inline void clearWBuffert(unsigned int* buffert)\r
+        {\r
+            for (int pos = 16; --pos >= 0;)\r
+            {\r
+                buffert[pos] = 0;\r
+            }\r
+        }\r
+\r
+        void innerHash(unsigned int* result, unsigned int* w)\r
+        {\r
+            unsigned int a = result[0];\r
+            unsigned int b = result[1];\r
+            unsigned int c = result[2];\r
+            unsigned int d = result[3];\r
+            unsigned int e = result[4];\r
+\r
+            int round = 0;\r
+\r
+            #define sha1macro(func,val) \\r
+                       { \\r
+                const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \\r
+                               e = d; \\r
+                               d = c; \\r
+                               c = rol(b, 30); \\r
+                               b = a; \\r
+                               a = t; \\r
+                       }\r
+\r
+            while (round < 16)\r
+            {\r
+                sha1macro((b & c) | (~b & d), 0x5a827999)\r
+                ++round;\r
+            }\r
+            while (round < 20)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro((b & c) | (~b & d), 0x5a827999)\r
+                ++round;\r
+            }\r
+            while (round < 40)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro(b ^ c ^ d, 0x6ed9eba1)\r
+                ++round;\r
+            }\r
+            while (round < 60)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)\r
+                ++round;\r
+            }\r
+            while (round < 80)\r
+            {\r
+                w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\r
+                sha1macro(b ^ c ^ d, 0xca62c1d6)\r
+                ++round;\r
+            }\r
+\r
+            #undef sha1macro\r
+\r
+            result[0] += a;\r
+            result[1] += b;\r
+            result[2] += c;\r
+            result[3] += d;\r
+            result[4] += e;\r
+        }\r
+    } // namespace\r
+\r
+    void calc(const void* src, const int bytelength, unsigned char* hash)\r
+    {\r
+        // Init the result array.\r
+        unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };\r
+\r
+        // Cast the void src pointer to be the byte array we can work with.\r
+        const unsigned char* sarray = (const unsigned char*) src;\r
+\r
+        // The reusable round buffer\r
+        unsigned int w[80];\r
+\r
+        // Loop through all complete 64byte blocks.\r
+        const int endOfFullBlocks = bytelength - 64;\r
+        int endCurrentBlock;\r
+        int currentBlock = 0;\r
+\r
+        while (currentBlock <= endOfFullBlocks)\r
+        {\r
+            endCurrentBlock = currentBlock + 64;\r
+\r
+            // Init the round buffer with the 64 byte block data.\r
+            for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)\r
+            {\r
+                // This line will swap endian on big endian and keep endian on little endian.\r
+                w[roundPos++] = (unsigned int) sarray[currentBlock + 3]\r
+                        | (((unsigned int) sarray[currentBlock + 2]) << 8)\r
+                        | (((unsigned int) sarray[currentBlock + 1]) << 16)\r
+                        | (((unsigned int) sarray[currentBlock]) << 24);\r
+            }\r
+            innerHash(result, w);\r
+        }\r
+\r
+        // Handle the last and not full 64 byte block if existing.\r
+        endCurrentBlock = bytelength - currentBlock;\r
+        clearWBuffert(w);\r
+        int lastBlockBytes = 0;\r
+        for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)\r
+        {\r
+            w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);\r
+        }\r
+        w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);\r
+        if (endCurrentBlock >= 56)\r
+        {\r
+            innerHash(result, w);\r
+            clearWBuffert(w);\r
+        }\r
+        w[15] = bytelength << 3;\r
+        innerHash(result, w);\r
+\r
+        // Store hash in result pointer, and make sure we get in in the correct order on both endian models.\r
+        for (int hashByte = 20; --hashByte >= 0;)\r
+        {\r
+            hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;\r
+        }\r
+    }\r
+\r
+    void toHexString(const unsigned char* hash, char* hexstring)\r
+    {\r
+        const char hexDigits[] = { "0123456789abcdef" };\r
+\r
+        for (int hashByte = 20; --hashByte >= 0;)\r
+        {\r
+            hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];\r
+            hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];\r
+        }\r
+        hexstring[40] = 0;\r
+    }\r
+} // namespace sha1\r
diff --git a/wsproxy/sha1.h b/wsproxy/sha1.h
new file mode 100755 (executable)
index 0000000..540c156
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+ Copyright (c) 2011, Micael Hildenborg\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions are met:\r
+    * Redistributions of source code must retain the above copyright\r
+      notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright\r
+      notice, this list of conditions and the following disclaimer in the\r
+      documentation and/or other materials provided with the distribution.\r
+    * Neither the name of Micael Hildenborg nor the\r
+      names of its contributors may be used to endorse or promote products\r
+      derived from this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\r
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\r
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef SHA1_DEFINED\r
+#define SHA1_DEFINED\r
+\r
+namespace sha1\r
+{\r
+\r
+    /**\r
+     @param src points to any kind of data to be hashed.\r
+     @param bytelength the number of bytes to hash from the src pointer.\r
+     @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.\r
+     */\r
+    void calc(const void* src, const int bytelength, unsigned char* hash);\r
+\r
+    /**\r
+     @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.\r
+     @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.\r
+     */\r
+    void toHexString(const unsigned char* hash, char* hexstring);\r
+\r
+} // namespace sha1\r
+\r
+#endif // SHA1_DEFINED\r
diff --git a/wsproxy/test.html b/wsproxy/test.html
new file mode 100644 (file)
index 0000000..061997c
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+
+<meta charset="utf-8" />
+
+<title>WebSocket Test</title>
+
+<script language="javascript" type="text/javascript">
+
+  //var wsUri = "ws://echo.websocket.org/";
+  var wsUri = "ws://127.0.0.1:10222/";
+  var output;
+
+  function init()
+  {
+    output = document.getElementById("output");
+    testWebSocket();
+  }
+
+  function testWebSocket()
+  {
+    websocket = new WebSocket(wsUri);
+    websocket.onopen = function(evt) { onOpen(evt) };
+    websocket.onclose = function(evt) { onClose(evt) };
+    websocket.onmessage = function(evt) { onMessage(evt) };
+    websocket.onerror = function(evt) { onError(evt) };
+  }
+
+  function onOpen(evt)
+  {
+    writeToScreen("CONNECTED");
+    doSend("WebSocket rocks");
+  }
+
+  function onClose(evt)
+  {
+    writeToScreen("DISCONNECTED");
+  }
+
+  function onMessage(evt)
+  {
+    writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
+    websocket.close();
+  }
+
+  function onError(evt)
+  {
+    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
+  }
+
+  function doSend(message)
+  {
+    writeToScreen("SENT: " + message); 
+    websocket.send(message);
+  }
+
+  function writeToScreen(message)
+  {
+    var pre = document.createElement("p");
+    pre.style.wordWrap = "break-word";
+    pre.innerHTML = message;
+    output.appendChild(pre);
+  }
+
+  window.addEventListener("load", init, false);
+
+</script>
+
+<h2>WebSocket Test</h2>
+
+<div id="output"></div>
diff --git a/wsproxy/ws_acceptor.cpp b/wsproxy/ws_acceptor.cpp
new file mode 100644 (file)
index 0000000..3d4427c
--- /dev/null
@@ -0,0 +1,78 @@
+#include <iostream>
+#include <list>
+
+#include <aeb/net/ip/tcp.h>
+#include <aeb/net/ip/basic_endpoint.h>
+#include <aeb/net/socket_base.h>
+#include <aeb/net/io_dispatcher.h>
+#include <aeb/net/basic_socket_acceptor.h>
+#include <aeb/net/basic_socket_stream.h>
+#include <aeb/pointer/intrusive_ptr.h>
+#if defined(__MINGW32__)
+#include <aeb/net/detail/winsock_init.h>
+#endif
+
+using namespace aeb::net;
+typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+typedef aeb::net::basic_socket<ip::tcp> tcp_socket;
+
+#include "reverse_proxy.h"
+#include "ws_constant.h"
+#include "ws_log.h"
+#include "ws_frame.h"
+#include "ws_proxy_endpoint.h"
+#include "ws_proxy_handler.h"
+
+#include "ws_acceptor.h"
+#include "ws_handler_factory.h"
+
+// Local debug macro
+#define LOG_WSAC_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0)
+#define LOG_WSAC_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n",args);} while (0) 
+
+#define LOG_WSAC_NOTICE(x) do { m_logger->log(eLOG_NOTICE,"%s\n",x); } while (0)
+#define LOG_WSAC_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args); } while (0) 
+
+#define LOG_WSAC_WARN(x) do { m_logger->log(eLOG_WARN,"%s\n",x); } while (0)
+#define LOG_WSAC_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args); } while (0) 
+
+#define LOG_WSAC_ERROR(x) do { m_logger->log(eLOG_ERROR,"%s\n",x); } while (0)
+#define LOG_WSAC_ERROR_FMT(format,args...) do { m_logger->log(eLOG_ERROR,format "\n",args);  } while (0)
+
+static ws_log *m_logger = ws_log::getInstance("ws_acceptor");
+
+
+
+ws_acceptor::ws_acceptor(const ip::basic_endpoint<ip::tcp> &e, const  wsproxy::ReverseProxyType_skel::application_sequence &apps)
+  : basic_socket_acceptor<detail::socket_type,ip::tcp>(e)
+  , m_applications(apps)
+  , m_ref(1)
+{
+  LOG_WSAC_DEBUG_FMT("ws_acceptor::ws_acceptor %d apps.size=%d",m_ref,apps.size());
+  int val = 1;
+  m_socket.set_option(SO_REUSEADDR,val);
+}
+
+ws_acceptor::~ws_acceptor()
+{
+  LOG_WSAC_DEBUG_FMT("ws_acceptor::~ws_acceptor %d",m_ref);
+}
+
+void
+ws_acceptor::on_accept()
+{
+   endpoint_type tmp;
+   int len = tmp.size();
+   detail::socket_type s;
+   aeb::sys::error ec;
+   LOG_WSAC_DEBUG("ws_acceptor::on_accept");
+   s = aeb::net::accept<socklen_t>(this->m_descriptor,tmp.data(),&len,ec);
+   
+   LOG_WSAC_NOTICE_FMT("ws_acceptor::on_accept on(%d) new socket %d error code is %d str(%s)",this->m_descriptor,s,ec.code(), ec.c_str());
+     
+   if (s != aeb::net::detail::invalid_socket)
+   {
+       ws_handler_factory *f = ws_handler_factory::get_instance();
+       ws_proxy_handler::ptr handler = f->get_handler(s,m_applications);
+   }   
+}
diff --git a/wsproxy/ws_acceptor.h b/wsproxy/ws_acceptor.h
new file mode 100644 (file)
index 0000000..fb2ac6e
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef WS_ACCEPTOR_H
+#define WS_ACCEPTOR_H
+
+
+class ws_acceptor : public basic_socket_acceptor<aeb::net::detail::socket_type,ip::tcp>
+{
+  private:
+      int m_ref;
+    
+    ws_acceptor(ws_acceptor &a) {
+      std::cout<<"ws_acceptor:: copy"<<std::endl;
+    }
+    virtual ~ws_acceptor();
+  public: 
+    typedef aeb::intrusive_ptr<ws_acceptor> ptr;
+
+    inline void add_ref() {m_ref++;};
+    
+    inline void release() {if (--m_ref == 0) delete this;};
+    
+  public:
+    typedef aeb::net::detail::socket_type socket_type;
+    
+    ws_acceptor(const ip::basic_endpoint<ip::tcp> &e, const  wsproxy::ReverseProxyType_skel::application_sequence &);
+
+    void on_accept();
+  protected:
+    ws_proxy_handler::ptr m_handler;
+    wsproxy::ReverseProxyType_skel::application_sequence       m_applications;
+};
+
+#endif
diff --git a/wsproxy/ws_allocator.h b/wsproxy/ws_allocator.h
new file mode 100644 (file)
index 0000000..4720f7f
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef WS_ALLOCATOR_H
+#define WS_ALLOCATOR_H
+
+/**
+ * The purpose of the allocator is to 
+ * align memory allocation to 8 bytes borders. This should help 
+ * optimize the memory management. 
+ * An maybe pool management as well to collect statistics.
+ *
+ *   To be used for strings, vectors, maps, list, queues
+ */
+template <typename T ,std::size_t maxSize,int Align = 4>
+struct ws_allocator
+{
+  public: 
+    // traits
+    typedef       T *      pointer;
+    typedef const T *      const_pointer;
+    typedef T       &      reference;
+    typedef const T &      const_reference;
+    typedef T              value_type;
+    typedef std::size_t    size_type;
+    typedef std::ptrdiff_t difference_type;
+  public:
+
+    ws_allocator() {}
+    
+    ws_allocator(const ws_allocator &a) {}
+    
+    ~ws_allocator() {}
+
+    pointer allocate(std::size_t n)
+    {
+        //check max size ...
+        if ( (n < maxSize) && (n <= std::numeric_limits<std::size_t>::max() / sizeof(T)) ) 
+        {
+          int l = (n * sizeof(T) / Align + 1) * Align;
+          if (void * ptr = std::malloc( ( n * sizeof(T)/Align + 1) * Align )  ) {
+              return static_cast<pointer>(ptr);
+          }
+        }
+        throw std::bad_alloc();
+    }
+
+    void deallocate(pointer ptr, std::size_t n) {
+      std::free(ptr);
+    }
+    
+    void construct(pointer p, const_reference val) { new(p) T(val); }
+      
+    void destroy(pointer p)
+    { 
+        p->~T();
+    }
+    
+    size_t max_size()  const { return maxSize;}
+    
+    template <typename U>
+    struct rebind { typedef ws_allocator<U,maxSize> other; } ;
+  protected:
+};
+
+template <typename T1,std::size_t S1,int A1,typename T2,std::size_t S2,int A2>
+inline bool operator ==(ws_allocator<T1,S1,A1> const &,ws_allocator<T2,S2,A2> const &) {
+  return true;
+}
+
+#endif /*WS_ALLOCATOR_H*/
diff --git a/wsproxy/ws_base64.cpp b/wsproxy/ws_base64.cpp
new file mode 100644 (file)
index 0000000..82c9439
--- /dev/null
@@ -0,0 +1,60 @@
+#include <iostream>
+#include "ws_base64.h"
+
+/*
+ * Translation Table as described in RFC1113
+ **/
+static const unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*
+ * Translation Table to decode (created by author)
+ **/
+static const unsigned char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+
+
+void 
+encode_base64_block(unsigned char *in,unsigned char *out,int len)
+{
+        out[0] = (unsigned char) cb64[ (int)(in[0] >> 2) & 0x3F ];
+        out[1] = (unsigned char) cb64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ];
+        out[2] = (unsigned char) (len > 1 ? cb64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '=');
+        out[3] = (unsigned char) (len > 2 ? cb64[ (int)(in[2] & 0x3f) ] : '=');
+        ;
+}
+    
+    
+void 
+decode_base64_block(unsigned char *in,unsigned char *out,int len)
+{
+        out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
+        out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
+        out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
+}
+
+
+void encode_base64(const unsigned char *str,int len,std::string &output )
+{
+    int count = 0;
+    unsigned char *p = ( unsigned char *)(str);
+    const unsigned char *end =(unsigned char *)( str + len);
+        
+    long size = ( (len - 1) /3) * 4 + 4;
+
+    output.resize(size);
+    unsigned char *out = (unsigned char *)(const_cast<char *>(output.c_str()));
+    while (p < end)
+    {
+       if (p+3 < end) {
+         encode_base64_block(p,out,end-p);
+         p+=3; out+=4;
+       } else
+       {
+         encode_base64_block(p,out,end-p);
+         p+= (end-p);
+       }
+    }
+
+
+}
+
diff --git a/wsproxy/ws_base64.h b/wsproxy/ws_base64.h
new file mode 100644 (file)
index 0000000..6b698e4
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef WS_BASE64_H__
+#define WS_BASE64_H__
+void encode_base64(const unsigned char *,int len,std::string &output );
+
+#endif
diff --git a/wsproxy/ws_conn_handler.h b/wsproxy/ws_conn_handler.h
new file mode 100644 (file)
index 0000000..08e58d1
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef WS_CONN_HANDLER_H
+#define WS_CONN_HANDLER_H
+
+class ws_conn_handler;
+
+/**
+ * \brief
+ *   Possible state. IDLE, CONNECTING, SSL HANDSHACK, OPEN, CLOSING, CLOSED
+ *    when ssl, conn goes through SSL HANDSHACK, otherwise direcly to OPEN
+ *    Should I handle chunk and mime types here or at a higher level?
+ *
+ */
+class ws_conn_state 
+{
+    ws_conn_state();
+    ws_conn_state(const ws_conn_state &con);
+  public:
+    virtual ~ws_conn_state();
+    
+    virtual void onRead(ws_conn_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+    
+    virtual void doActivity(ws_conn_handler &p);
+  
+};
+
+
+
+// 
+// ws_conn_handler
+//  \bried  Actually, this is probably the lowest layer I should use.
+//    Once connected, the flow should travel through upper layers 
+//    that know better what to do. Plugins should come in action 
+//      specifically conn hooks 
+//        - decides if the connection is accepted
+//        - according to config, decides if its ssl or not
+//        - conn_handler has a stated. IDLE CONNECTING OPEN CLOSING CLOSED
+//        - several https/http/ws or what ever can be processed.
+//        - if ssl do ssl auth stuff and so on
+//        - if plain do plain read and so on
+//
+class ws_conn_handler : public ws_handler
+{
+  public: 
+    
+    bool available () const;   
+  public:
+    ws_conn_handler(detail::socket_type s);
+  
+    virtual ~ws_conn_handler() ;
+    
+    virtual void onRead(ws_conn_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+
+    void on_write() ;
+    
+    void on_read() ;
+    
+    void on_accept();
+
+    void io_register();
+    
+    void io_unregister();
+    // reuse handler with a new socket
+    void reuse(aeb::net::detail::socket_type s);
+  
+  protected:
+    ws_conn_handler(const ws_conn_handler &p);
+    ws_conn_state   *m_state;
+    // Do I own stream objects or not
+};
+
+
+#endif /*WS_CONN_HANDLER_H*/
diff --git a/wsproxy/ws_constant.h b/wsproxy/ws_constant.h
new file mode 100644 (file)
index 0000000..49ae5df
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef WS_CONSTANT_H__
+#define WS_CONSTANT_H__
+
+#define SEC_WEBSOCKET_VERSION   "Sec-WebSocket-Version"
+#define SEC_WEBSOCKET_KEY       "Sec-WebSocket-Key"
+#define SEC_WEBSOCKET_ACCEPT    "Sec-WebSocket-Accept"
+#define SEC_WEBSOCKET_PROTOCOL  "Sec-WebSocket-Protocol"
+#define WS_UPGRADE              "Upgrade"
+#define WS_CONNECTION           "Connection"
+#define WS_COOKIES              "Cookies"
+#define WS_HOST                 "Host"
+#define WS_GET                  "GET"
+#define WS_ORIGIN               "Origin"
+
+#define WS_HANDSHACK            "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
+// Structures as well
+
+enum ws_opcodes {
+    ews_continue    = 0x0
+   ,ews_text        = 0x1
+   ,ews_binary      = 0x2
+   ,ews_close       = 0x8
+   ,ews_ping        = 0x9
+   ,ews_pong        = 0xA
+};
+
+enum ws_exit_code {
+    ews_exit_normal     = 1000
+   ,ews_exit_server     = 1001
+   ,ews_exit_protocol   = 1001
+   ,ews_exit_bad_frame  = 1003 
+};
+
+typedef struct ws_header_ {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  // For Big endian 
+  unsigned char   fin :1;
+  unsigned char   rsv1:1;
+  unsigned char   rsv2:1;
+  unsigned char   rsv3:1;
+  unsigned char   opcode:4;
+#else
+  unsigned char   opcode:4;
+  unsigned char   rsv3:1;
+  unsigned char   rsv1:1;
+  unsigned char   rsv2:1;
+  unsigned char   fin :1;
+#endif
+} ws_header;
+
+
+#endif
diff --git a/wsproxy/ws_frame.cpp b/wsproxy/ws_frame.cpp
new file mode 100644 (file)
index 0000000..f2dbd18
--- /dev/null
@@ -0,0 +1,142 @@
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <map>
+
+#include <stdlib.h> // for calloc
+#include <string.h>
+
+#include "ws_log.h"
+#include "ws_constant.h"
+#include "ws_frame.h"
+
+// Local debug macro
+#define LOG_WSFR_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0)
+#define LOG_WSFR_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n",args);} while (0) 
+
+#define LOG_WSFR_NOTICE(x) do { m_logger->log(eLOG_NOTICE,"%s\n",x); } while (0)
+#define LOG_WSFR_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args); printf(format "\n",args);} while (0) 
+
+#define LOG_WSFR_WARN(x) do { m_logger->log(eLOG_WARN,"%s\n",x); } while (0)
+#define LOG_WSFR_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args); printf(format "\n",args);} while (0) 
+
+#define LOG_WSFR_ERROR(x) do { m_logger->log(eLOG_ERROR,"%s\n",x); } while (0)
+#define LOG_WSFR_ERROR_FMT(format,args...) do { m_logger->log(eLOG_ERROR,format "\n",args);  } while (0)
+
+static ws_log *m_logger = ws_log::getInstance("ws_frame");
+
+
+
+ws_frame::ws_frame(unsigned char *_d,long l)
+  : m_length(l) , m_buffer(_d) , m_data(_d) , m_allocated(false)
+{
+}
+
+ws_frame::~ws_frame()
+{
+    if (m_allocated)
+        free(m_buffer);
+}
+
+int
+ws_frame::decode(  unsigned char *_d,size_t len)
+{
+  bool have_key = false;
+  m_buffer = _d;
+  m_data   = _d;
+  m_header = *(ws_header *)_d;
+  m_data++;
+  LOG_WSFR_DEBUG_FMT("ws_frame::decode start len=%d",len);
+  if ( *m_data & 0x80)
+    have_key = true;
+  if ( (*m_data & 0x7F) == 0x7E) {
+    // 16 bits length header  
+    m_data++;
+    unsigned short l = *(unsigned short *) m_data ;
+    m_data+=2;
+    m_length = l;
+  }  else {
+    m_length = *m_data & 0x7F;
+    m_data++;
+  }
+  if (have_key)
+  {
+    int i = 0;
+    unsigned char *d = NULL;
+    for ( ; i < 4 ; m_key[i++] = *m_data, m_data++) ;
+    // Now if mask  decode the buffer;
+    d  = m_data;
+    len -= (d - _d);
+    i  = 0;
+    LOG_WSFR_DEBUG_FMT("ws_frame::decode loop pos=%d len=%d",(int)(m_data-_d),len);
+    while (len--)
+    {  
+           *d = *d ^ m_key[i % 4];
+           d++;
+           i++;
+    } 
+  } else {
+      LOG_WSFR_ERROR("ws_frame::decode un encoded frame should quit");
+  }
+  LOG_WSFR_DEBUG("End Decode Frame");
+  LOG_WSFR_DEBUG_FMT("ws_frame::decode end m_length=%d data=%s",m_length,m_data);
+}
+
+int
+ws_frame::encode(const  unsigned char *_b,size_t len,int mode)
+{
+    m_length      = len;
+    m_allocated   = true;
+
+    std::ostringstream ss;
+    std::ostringstream str;
+    
+    int al = ( len / 8  + 2) * 8;
+    m_buffer = (unsigned char *)calloc(  al  , sizeof(char) );
+    LOG_WSFR_DEBUG_FMT("ws_frame::encode( len=%d) allocated %d",len,al);
+#if 0
+    // For debug purpose.
+    for (int i = 0 ; i < len ; i++ )
+    {
+       ss<<std::hex<<std::setw(2)<<std::setfill('0')<<(int)_b[i]<<" ";
+       if (_b[i] > 31 && _b[i] < 127) {
+         str<<_b[i];
+       } else {
+         str<<".";
+       }
+       if ( ! (i % 16 ) ) {
+            LOG_WSPH_DEBUG_FMT("ws_frame::encode(buffer=<%s %s> size=%lu)",ss.str().c_str(),str.str().c_str(),len);
+            ss.str(""); str.str("");
+       }
+    }
+#endif
+    if (len < 126)
+    {
+        ws_header *header = (ws_header *)m_buffer;
+        //header->opcode  = ews_binary;
+        header->opcode  = mode;
+        header->fin     = 1;
+        m_buffer[1]       = (char) len;
+        memcpy(&m_buffer[2],_b,len);
+        //m_stream.send(buffer,len+2);
+        m_buffer_length = len + 2;
+    } else if (len < 65535)
+    {
+        unsigned short *l = (unsigned short *)&m_buffer[2];
+        ws_header *header = (ws_header *)m_buffer;
+        
+        //header->opcode  = ews_binary;
+        header->opcode  = mode;
+        header->fin     = 1;
+        m_buffer[1]       = (char) 126;
+        *l              = (unsigned short)len;
+        memcpy(&m_buffer[4],_b,len);
+        //m_stream.send(buffer,len+4);
+        m_buffer_length = len + 4;
+    } else {
+        LOG_WSFR_ERROR("ws_frame::encode( frame_size Too big  > 65535 not supported");
+        return 1;
+    }
+    return 0;
+
+}
diff --git a/wsproxy/ws_frame.h b/wsproxy/ws_frame.h
new file mode 100644 (file)
index 0000000..0424ed2
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef WS_BUFFER_H__
+#define WS_BUFFER_H__
+
+class ws_frame
+{
+  public:
+    ws_frame(unsigned char *_d=NULL,long len=0);
+    ~ws_frame();
+
+    inline long length() const { return m_length; };
+
+    inline unsigned char * data() const { return m_data; };
+    
+    inline const unsigned char * buffer() const { return m_buffer; };
+
+    inline long buffer_length() const { return m_buffer_length;};
+
+    inline int  opcode() const { return m_header.opcode; };
+
+    int decode( unsigned char *b,size_t length);
+
+    int encode(const unsigned char *_b,size_t length , int mode = ews_binary);
+
+  private:
+    ws_frame(const ws_frame &) {} ;
+  protected:
+    unsigned char      m_key[4];
+    unsigned char      *m_buffer;
+    unsigned char      *m_data;
+    long            m_length;
+    long            m_buffer_length;
+    ws_header       m_header;
+    bool            m_allocated;
+};
+#endif
diff --git a/wsproxy/ws_handler.h b/wsproxy/ws_handler.h
new file mode 100644 (file)
index 0000000..c288aec
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef WS_HANDLER_H
+#define WS_HANDLER_H
+
+
+// 
+// ws_proxy_handler
+//
+class ws_handler : public event_handler<detail::socket_type,ip::tcp>
+{
+  private:
+      int m_ref;
+  public: 
+    
+    typedef basic_socket_stream<ip::tcp>        Stream;
+    /// aeb::ssl::stream<ip::tcp> ? or detail::socket_type
+    typedef basic_socket_stream<ip::tcp>        SSLStream;
+    
+    typedef aeb::intrusive_ptr<ws_handler>      ptr;
+
+    inline void add_ref() {m_ref++;};
+    
+    inline void release() {
+      if (--m_ref == 0) delete this;
+    };
+    bool available () const;   
+  public:
+    ws_handler(detail::socket_type s);
+  
+    virtual ~ws_handler() ;
+    
+
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+
+    void on_write() ;
+    
+    void on_read() ;
+    
+    void on_accept();
+
+    void io_register();
+    
+    void io_unregister();
+    // reuse handler with a new socket
+    void reuse(aeb::net::detail::socket_type s);
+  
+  protected:
+    ws_handler(const ws_handler &p) ;
+    // Should own an endpoint 
+    long                                m_max_frame_size;
+};
+
+/**
+vim:et:sw=2:ts=2
+ */
+
+
+#endif /*WS_HANDLER_H*/
diff --git a/wsproxy/ws_handler_factory.cpp b/wsproxy/ws_handler_factory.cpp
new file mode 100644 (file)
index 0000000..1f656ad
--- /dev/null
@@ -0,0 +1,138 @@
+#include <iostream>
+#include <map>
+#include <list>
+#include <algorithm> // find_if
+
+#include <aeb/net/ip/tcp.h>
+#include <aeb/net/ip/basic_endpoint.h>
+#include <aeb/net/socket_base.h>
+#include <aeb/net/io_dispatcher.h>
+#include <aeb/net/basic_socket_acceptor.h>
+#include <aeb/net/basic_socket_stream.h>
+#include <aeb/pointer/intrusive_ptr.h>
+#if defined(__MINGW32__)
+#include <aeb/net/detail/winsock_init.h>
+#endif
+
+
+#include "time.h"
+#include "reverse_proxy.h"
+#include "ws_constant.h"
+#include "ws_log.h"
+#include "ws_frame.h"
+#include "sha1.h"
+#include "ws_base64.h"
+
+using namespace aeb::net;
+typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+#include "ws_proxy_endpoint.h"
+#include "ws_proxy_handler.h"
+#include "ws_handler_factory.h"
+
+// Log feature
+#define LOG_WSHF_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0);
+#define LOG_WSHF_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n" ,args);} while (0) 
+
+#define LOG_WSHF_NOTICE(x) do {m_logger->log(eLOG_NOTICE,"%s\n",x);} while (0);
+#define LOG_WSHF_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args);} while (0)
+
+#define LOG_WSHF_WARN(x) do {m_logger->log(eLOG_WARN,"%s\n",x);} while (0)
+#define LOG_WSHF_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args);} while (0) 
+
+#define LOG_WSHF_ERROR(x) do {m_logger->log(eLOG_ERROR,"%s\n",x);} while (0)
+#define LOG_WSHF_ERROR_FMT(format,args...) do {m_logger->log(eLOG_ERROR,format "\n",args);} while (0) 
+
+static ws_log *m_logger = ws_log::getInstance("ws_handler_factory");
+
+// Begin Of Code
+
+//
+ws_handler_factory::ws_handler_factory() 
+{
+  LOG_WSHF_DEBUG("ws_handler_factory::ws_handler_factory");
+}
+
+//
+ws_handler_factory::ws_handler_factory(const ws_handler_factory &_f)
+{
+  LOG_WSHF_DEBUG("ws_handler_factory::ws_handler_factory copy");
+}
+
+// I need a finder  object to find 
+struct find_free {
+  find_free() {};
+  bool operator ()(ws_handler_factory::handler &h) {
+    return h->available();
+  };
+};
+
+// I need a finder  object to find 
+struct find_pointer {
+  find_pointer(ws_proxy_handler *_p) : m_p(_p) {};
+  bool operator ()(ws_handler_factory::handler &h) {
+    return m_p == (ws_proxy_handler *)h;
+  };
+  ws_proxy_handler  *m_p;
+};
+//    handler get_handler(aeb::net::detail::socket_type fd,const wsproxy::ReverseProxyType_skel::application_sequence &apps);
+//
+ws_handler_factory::handler 
+ws_handler_factory::get_handler(aeb::net::detail::socket_type fd,const wsproxy::ReverseProxyType_skel::application_sequence &apps)
+{
+  LOG_WSHF_DEBUG_FMT("ws_handler_factory::get_handler active handlers %d", m_handlers.size());
+
+  handler_iterator it = std::find_if(m_handlers.begin(),m_handlers.end(),find_free());
+  
+  if ( it == m_handlers.end() )
+  {
+    LOG_WSHF_DEBUG("ws_handler_factory::get_handler create new");
+    handler h( new ws_proxy_handler(fd,apps));
+    m_handlers.push_back(h);
+    return h;
+  } 
+  else 
+  {
+    handler h(*it);
+    LOG_WSHF_DEBUG("ws_handler_factory::get_handler recycle unused handler");
+    (*it)->reuse(fd);
+    return h;
+  }
+}
+
+bool  ws_handler_factory::find(ws_proxy_handler *ptr,handler _rp)
+{
+  handler_iterator it = std::find_if(m_handlers.begin(),m_handlers.end(),find_pointer(ptr));
+  if (it !=  m_handlers.end())
+  {
+      _rp = *it;
+      return true;
+  } else {
+      return false;
+  }
+}
+//
+ws_handler_factory * ws_handler_factory::m_factory  = NULL;
+
+ws_handler_factory *
+ws_handler_factory::get_instance() {
+  if (m_factory == NULL)
+      m_factory = new ws_handler_factory();
+  return m_factory;
+
+}
+
+void
+ws_handler_factory::close_handlers() 
+{
+   LOG_WSHF_DEBUG_FMT("ws_handler_factory::close_handlers handlers size: %d",m_handlers.size());
+   handler_iterator it = m_handlers.begin();
+   for ( ; it != m_handlers.end() ; ++it)
+   {
+       if (!(*it)->available())
+           (*it)->onClose(ews_exit_server);
+       // (*it)->release();
+   }
+   //m_handlers.erase(m_handlers.begin(),m_handlers.end());
+   
+   LOG_WSHF_DEBUG_FMT("ws_handler_factory::close_handlers handlers end size : %d",m_handlers.size());
+}
diff --git a/wsproxy/ws_handler_factory.h b/wsproxy/ws_handler_factory.h
new file mode 100644 (file)
index 0000000..f6d58c6
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef WS_HANDLER_FACTORY_H__
+#define WS_HANDLER_FACTORY_H__
+
+
+class ws_handler_factory 
+{
+  public:
+    typedef ws_proxy_handler::ptr                 handler;
+    //typedef std::map<int,ws_proxy_handler::ptr>   handler_map;
+    typedef std::list<ws_proxy_handler::ptr>   handler_map;
+    typedef handler_map::iterator                 handler_iterator;
+
+    static ws_handler_factory *get_instance();
+    //
+    handler get_handler(aeb::net::detail::socket_type fd,const wsproxy::ReverseProxyType_skel::application_sequence &apps);
+    // In case of end, close all sockets and exit properly
+    void   close_handlers();
+
+    bool  find(ws_proxy_handler *ptr,handler _rp);
+  protected:
+    handler_map m_handlers;
+
+  private:
+    ws_handler_factory();
+    
+    ws_handler_factory(const ws_handler_factory &_f);
+
+    static ws_handler_factory *m_factory;
+};
+
+/*
+  vim:et:sw=2:ts=2
+ */
+#endif
diff --git a/wsproxy/ws_http_handler.h b/wsproxy/ws_http_handler.h
new file mode 100644 (file)
index 0000000..7e2656f
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef WS_HTTP_HANDLER_H
+#define WS_HTTP_HANDLER_H
+
+// 
+// ws_http_handler
+//
+class ws_http_handler : public ws_handler
+{
+  public: 
+    
+    bool available () const;   
+  public:
+    ws_http_handler(detail::socket_type s);
+  
+    virtual ~ws_http_handler() ;
+    
+
+    virtual void onRead(ws_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+
+    void on_write() ;
+    
+    void on_read() ;
+    
+    void on_accept();
+
+    void io_register();
+    
+    void io_unregister();
+    // reuse handler with a new socket
+    void reuse(aeb::net::detail::socket_type s);
+  
+  protected:
+    ws_http_handler(const ws_http_handler &p) ;
+};
+
+/**
+vim:et:sw=2:ts=2
+ */
+
+#endif /*WS_HTTP_HANDLER_H*/
diff --git a/wsproxy/ws_http_header.cpp b/wsproxy/ws_http_header.cpp
new file mode 100644 (file)
index 0000000..360543e
--- /dev/null
@@ -0,0 +1,97 @@
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+#include <limits>
+#include <cstdlib>
+
+#include "ws_constant.h"
+#include "ws_log.h"
+#include "ws_allocator.h"
+#include "ws_http_header.h"
+
+// Local debug macro
+#define LOG_WSHH_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0);
+#define LOG_WSHH_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n" ,args);} while (0) 
+
+#define LOG_WSHH_NOTICE(x) do {m_logger->log(eLOG_NOTICE,"%s\n",x);} while (0);
+#define LOG_WSHH_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args);} while (0) ;
+
+#define LOG_WSHH_WARN(x) do {m_logger->log(eLOG_WARN,"%s\n",x);} while (0);
+#define LOG_WSHH_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args);} while (0) ;
+
+#define LOG_WSHH_ERROR(x) do {m_logger->log(eLOG_ERROR,"%s\n",x);} while (0);
+#define LOG_WSHH_ERROR_FMT(format,args...) do {m_logger->log(eLOG_ERROR,format "\n",args);} while (0) ;
+
+static ws_log *m_logger = ws_log::getInstance("ws_proxy_handler");
+
+//using namespace aeb::net;
+//typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+
+//#include "ws_proxy_endpoint.h"
+
+//
+ws_http_header::ws_http_header()
+{
+  LOG_WSHH_DEBUG("ws_http_header::ws_http_header");
+}
+
+
+ws_http_header::~ws_http_header()
+{
+  LOG_WSHH_DEBUG("ws_http_header::~ws_http_header");
+}
+
+int
+ws_http_header::parse(const std::string &_h)
+{
+  LOG_WSHH_DEBUG("ws_http_header::parse ");
+  std::istringstream stream(_h);
+  char result[256];
+  
+  while( ! stream.getline(result,256).eof() ) {
+    int pos;
+    std::string s(result);
+    // std::cout<<"Process line:"<<s<<std::endl;
+    if ( (pos = s.find(SEC_WEBSOCKET_KEY)) != std::string::npos && (pos == 0)) {
+      set_entry(SEC_WEBSOCKET_KEY,s.substr(s.find(":")+1));
+    } 
+    else if ( ((pos = s.find(WS_UPGRADE)) != std::string::npos ) && (pos == 0 )) {
+          set_entry(WS_UPGRADE,s.substr(s.find(":")+1));
+    }
+    else if ( ((pos = s.find(WS_ORIGIN)) != std::string::npos ) && (pos == 0 )) {
+          set_entry(WS_ORIGIN,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(SEC_WEBSOCKET_VERSION)) != std::string::npos && (pos == 0)) {
+      set_entry(SEC_WEBSOCKET_VERSION,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(WS_CONNECTION)) != std::string::npos) {
+          set_entry(WS_CONNECTION,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(SEC_WEBSOCKET_PROTOCOL) != std::string::npos) && (pos == 0)) {
+          set_entry(SEC_WEBSOCKET_PROTOCOL,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(WS_HOST) != std::string::npos) && (pos == 0)) {
+          set_entry(WS_HOST,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(WS_COOKIES) != std::string::npos) && (pos == 0)) {
+          set_entry(WS_COOKIES,s.substr(s.find(":")+1));
+    } else {
+    }
+ }
+  return 0;
+}
+
+
+void 
+ws_http_header::to_string(std::string &_h)
+{
+}
+
+void 
+ws_http_header::set_entry(const string32 &key,const std::string &_val)
+{
+    string256 s(_val.substr(1,_val.size()-2).c_str());
+    LOG_WSHH_DEBUG_FMT("ws_proxy_handler::set_header key=%s Value(%s)",key.c_str(),s.c_str());
+    m_header[key] = s;
+}
diff --git a/wsproxy/ws_http_header.h b/wsproxy/ws_http_header.h
new file mode 100644 (file)
index 0000000..f0629c3
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef WS_HTTP_HEADER_H__
+#define WS_HTTP_HEADER_H__
+
+class ws_http_header {
+  public:
+    typedef ws_allocator<char,256> ws256_alloc;
+    typedef ws_allocator<char,32>  ws32_alloc;
+    typedef std::basic_string<char,std::char_traits<char>,ws256_alloc> string256;
+    typedef std::basic_string<char,std::char_traits<char>,ws32_alloc>  string32;
+    
+    ws_http_header();
+
+    virtual ~ws_http_header();
+
+    int parse(const std::string &_h);
+
+    void to_string(std::string &_h);
+    
+    void to_string(int code,std::string &result);
+
+    void set_entry(const string32 &key,const std::string &_val);
+  protected:
+    // header entries
+    std::map<string32,string256>   m_header;
+
+};
+
+#endif
diff --git a/wsproxy/ws_https_handler.h b/wsproxy/ws_https_handler.h
new file mode 100644 (file)
index 0000000..f7b4370
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef WS_HTTPS_HANDLER_H
+#define WS_HTTPS_HANDLER_H
+
+// 
+// ws_https_handler
+//
+class ws_https_handler : public ws_handler
+{
+  public: 
+    
+    bool available () const;   
+  public:
+    ws_https_handler(detail::socket_type s);
+  
+    virtual ~ws_https_handler() ;
+    
+
+    virtual void onRead(ws_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+
+    void on_write() ;
+    
+    void on_read() ;
+    
+    void on_accept();
+
+    void io_register();
+    
+    void io_unregister();
+    // reuse handler with a new socket
+    void reuse(aeb::net::detail::socket_type s);
+  
+  protected:
+    ws_https_handler(const ws_http_handler &p);
+
+};
+
+
+
+#endif /*WS_HTTPS_HANDLER_H*/
diff --git a/wsproxy/ws_log.cpp b/wsproxy/ws_log.cpp
new file mode 100644 (file)
index 0000000..8396c95
--- /dev/null
@@ -0,0 +1,81 @@
+#include <iostream>
+#include <string>
+#include <map>
+#include <stdarg.h>
+#include <string.h> // for memset
+#include <syslog.h>
+
+#include "ws_log.h"
+
+
+ws_log *ws_log::getInstance(const std::string &cls) 
+{
+//  std::cout<<"ws_log::getInstance "<<cls<<std::endl;
+  logger_const_iterator it = m_loggers.find(cls);
+//  std::cout<<"ws_log::getInstance after fine "<<cls<<" m_loggers size = "<<m_loggers.size()<<std::endl;
+  if (m_loggers.size() == 0)
+  {
+    ws_log::m_loggers = ws_log::init_map();
+  }
+
+  if (it != m_loggers.end()) {
+   // std::cout<<"ws_log::getInstance found"<<cls<<std::endl;
+    return it->second;
+  }
+  ws_log *l    = new ws_log(cls);
+  ws_log::m_loggers[cls]       = l;
+ // std::cout<<"ws_log::getInstance before return "<<cls<<std::endl;
+  return l;
+}
+
+#define BUFFER_SIZE (1024*8)
+void ws_log::log(int level,const char *format,...)
+{
+  char buffer[BUFFER_SIZE];
+  va_list      vl;
+  memset(buffer,0x00,BUFFER_SIZE);
+  va_start(    vl,format);
+  vsprintf(buffer,format,vl);
+  if (level <= m_level)
+    std::cout<<buffer;
+  va_end(vl);
+  // Missing check if loger should write to syslog
+  switch (level) 
+  {
+      case eLOG_ERROR:
+          syslog(LOG_ERR,buffer);
+          break;
+      case eLOG_WARN:
+          syslog(LOG_WARNING,buffer);
+          break;
+      default:
+          ;
+  }
+  //syslog(buffer);
+}
+
+ws_log::ws_log(const std::string &name)
+  : m_level(eLOG_DEBUG) , m_syslog(false)
+{
+}
+
+ws_log::ws_log(const ws_log &name)
+{
+    if ( !ws_log::m_syslog_open) 
+    {
+        openlog("wsproxy",LOG_PID | LOG_NDELAY,LOG_DAEMON);
+    } 
+}
+
+ws_log::logger_type
+ws_log::init_map()
+{
+  logger_type m;
+  std::cout<<"ws_log::init_map "<<std::endl;
+  m["null"] = NULL;
+  return m;
+}
+
+std::map<std::string,ws_log *> ws_log::m_loggers = init_map();
+bool ws_log::m_syslog_open     = false;
+
diff --git a/wsproxy/ws_log.h b/wsproxy/ws_log.h
new file mode 100644 (file)
index 0000000..2d309c0
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef WS_LOG_H__
+#define WS_LOG_H__
+
+
+enum e_ws_log_level {
+  eLOG_EMERG   = 0
+ ,eLOG_ERROR   = 1
+ ,eLOG_AUTH    = 2
+ ,eLOG_WARN    = 3
+ ,eLOG_NOTICE  = 4
+ ,eLOG_INFO    = 5
+ ,eLOG_DEBUG   = 6
+
+};
+
+class ws_log
+{
+  public:
+    typedef std::map<std::string,ws_log *>  logger_type;
+    typedef std::map<std::string,ws_log *>::const_iterator     logger_const_iterator;
+    typedef std::map<std::string,ws_log *>::iterator           logger_iterator;
+
+    inline void set_level(int _l) { m_level = _l;};
+
+    inline void set_syslog() {m_syslog = true; };
+
+    static ws_log *getInstance(const std::string &cls) ;
+
+    void log(int level,const char *format,...);
+
+  protected:
+    int                m_level;
+    bool    m_syslog; // Says if trace should be reported in syslog.
+  private:
+    ws_log(const std::string &name);
+
+    ws_log(const ws_log &name);
+    static logger_type init_map();
+    static logger_type         m_loggers;
+    static bool                m_syslog_open;
+};
+#endif
diff --git a/wsproxy/ws_plugin.h b/wsproxy/ws_plugin.h
new file mode 100644 (file)
index 0000000..6d7268a
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef WS_PLUGING_H__
+#define WS_PLUGING_H__
+
+#define PLUGIN_OK       0
+#define PLUGIN_DECLINE -1
+
+/**
+ * Defines the kind of hool the plugin is going to register
+ */
+#define PLUGIN_HANDLER_FILTER_IN  0
+#define PLUGIN_HANDLER_CONTENT    1
+#define PLUGIN_HANDLER_FILTER_OUT 2
+
+
+/**
+ * class ws_plugin
+ *
+ * \brief Model class to implement a plugin
+ * \author
+ */
+class ws_plugin {
+  public:
+    //
+    ws_plugin(const std::string &_name) : m_name(_name)  {} ;
+    //
+    ws_plugin(const ws_plugin &o) {} ;
+    //
+    ~ws_plugin() {} ;
+
+    // Functions called my the 
+    virtual void register_hooks() = 0;
+  protected:
+    // Plugin name
+    std::string m_name;
+};
+
+
+/**
+ * class ws_plugin_handler
+ *
+ * \brief
+ * \author
+ */
+class ws_plugin_handler {
+  public:
+    //
+    ws_plugin_handler() {} ;
+    //
+    ws_plugin_handler(const ws_plugin_handler &o) {} ;
+    //
+    ~ws_plugin_handler() {};
+
+    virtual int handle_request(ws_plugin_request &r) = 0;
+  protected:
+};
+
+
+extern "C" void *create_plugin() ;
+
+#endif
diff --git a/wsproxy/ws_plugin_manager.cpp b/wsproxy/ws_plugin_manager.cpp
new file mode 100644 (file)
index 0000000..f37effc
--- /dev/null
@@ -0,0 +1,115 @@
+#include <iostream>
+#include <iostream>
+#include <map>
+
+#include "ltdl.h"
+
+#include "ws_log.h"
+
+#include "ws_plugin_request.h"
+#include "ws_plugin.h"
+#include "ws_plugin_manager.h"
+
+// Local debug macro
+#define LOG_PMGR_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0);
+#define LOG_PMGR_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n" ,args);} while (0) 
+
+#define LOG_PMGR_INFO(x) do {m_logger->log(eLOG_INFO,"%s\n",x);} while (0);
+#define LOG_PMGR_INFO_FMT(format,args...) do { m_logger->log(eLOG_INFO,format "\n",args);} while (0) ;
+
+#define LOG_PMGR_NOTICE(x) do {m_logger->log(eLOG_NOTICE,"%s\n",x);} while (0);
+#define LOG_PMGR_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args);} while (0) ;
+
+#define LOG_PMGR_WARN(x) do {m_logger->log(eLOG_WARN,"%s\n",x);} while (0);
+#define LOG_PMGR_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args);} while (0) ;
+
+#define LOG_PMGR_ERROR(x) do {m_logger->log(eLOG_ERROR,"%s\n",x);} while (0);
+#define LOG_PMGR_ERROR_FMT(format,args...) do {m_logger->log(eLOG_ERROR,format "\n",args);} while (0) ;
+
+static ws_log *m_logger = ws_log::getInstance("ws_plugin_manager");
+
+typedef void * (*fct)();
+
+class ltdl_manager : public ws_plugin_manager
+{
+  public:
+    ltdl_manager(const std::string &s ) : ws_plugin_manager(s)
+    {
+      int res = lt_dlinit();
+      LOG_PMGR_DEBUG_FMT("ltdl_manager::ltdl_manager init res=%d",res);
+    }
+
+    ~ltdl_manager() {
+      lt_dlclose(m_Handle);
+    }
+    ws_plugin *load_plugin(const std::string &s)
+    {
+      m_Handle = lt_dlopenext(s.c_str());
+      LOG_PMGR_DEBUG_FMT("ltdl_manager::load_plugin %s m_Handle=%x",s.c_str(),m_Handle);
+      if (m_Handle)
+      {
+         fct _create = reinterpret_cast<fct>(reinterpret_cast<long>(lt_dlsym(m_Handle,"create_plugin")));
+        if ( _create )
+        {
+           ws_plugin *p = static_cast<ws_plugin *>(_create());
+          if (p)
+          {
+              m_Plugins[s] = p;
+          }
+          return p;
+        } else 
+        {
+           LOG_PMGR_ERROR_FMT("ltdl_manager::load_plugin Failed create_function lt_dlerror=%s",lt_dlerror());
+            std::cout<<"Failed load function  create_plugin"<<std::endl;
+        }
+      } else {
+        LOG_PMGR_ERROR_FMT("ltdl_manager::load_plugin Failed load %s lt_dlerror=%s",s.c_str(),lt_dlerror());
+      } 
+      return NULL;
+    }
+
+  protected:
+    lt_dlhandle m_Handle;
+};
+
+// default Contructor
+ws_plugin_manager::ws_plugin_manager(const std::string &n) : m_Dir(n)
+{
+}
+
+//
+ws_plugin_manager::ws_plugin_manager(const ws_plugin_manager   &o)
+{
+}
+
+// default Desctructor
+ws_plugin_manager::~ws_plugin_manager()
+{
+}
+
+/**
+ * I should return a shared pointer
+ */
+ws_plugin *
+ws_plugin_manager::load_plugin(const std::string &s)
+{
+  return NULL;
+}
+
+/**
+ * Initialize static attribute
+ */
+ws_plugin_manager *
+ws_plugin_manager::m_PluginManager  = NULL;
+
+ws_plugin_manager *
+ws_plugin_manager::getInstance(const std::string &_dir)
+{
+    if (m_PluginManager == NULL) 
+    {
+        m_PluginManager = new ltdl_manager(_dir);
+    }
+    return m_PluginManager;
+}
+
diff --git a/wsproxy/ws_plugin_manager.h b/wsproxy/ws_plugin_manager.h
new file mode 100644 (file)
index 0000000..e71d4c5
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef WS_PLUGIN_MANAGER_H
+#define WS_PLUGIN_MANAGER_H
+
+/**
+ * class ws_plugin_manager
+ *
+ * \brief This class is responsible to provide all services related to plugin management.
+ *   load plugins , get a plugins, unload_ plugins
+ * \author
+ */
+class ws_plugin_manager {
+  public:
+    typedef std::map<std::string,ws_plugin *> PluginsMap;
+  public:
+    static ws_plugin_manager *getInstance(const std::string &_dir) ;
+  protected:  
+    //
+    ws_plugin_manager(const std::string &dir) ;
+    //
+    ws_plugin_manager(const ws_plugin_manager &o) ;
+    //
+    ~ws_plugin_manager() ;
+
+  public:
+    /**
+     * load plugin whose name is given in parameter
+     * \param _name: plugin name.
+     */
+    virtual ws_plugin* load_plugin(const std::string &_name) ;
+
+
+  protected:
+    std::string m_Dir;
+    // Local storage for loaded plugins
+    PluginsMap m_Plugins;
+    // Instance to store the Manager
+    static ws_plugin_manager *m_PluginManager;
+};
+
+
+#endif /*WS_PLUGIN_MANAGER_H*/
diff --git a/wsproxy/ws_plugin_request.h b/wsproxy/ws_plugin_request.h
new file mode 100644 (file)
index 0000000..8d8c699
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef WS_PLUGIN_REQUEST_H
+#define WS_PLUGIN_REQUEST_H
+
+
+
+/**
+ * class ws_plugin_request
+ *
+ * \brief this class contains all information required to process an http
+ * request. Among the known information are :
+ *   - the uri
+ *   - the method (GET,INFO,PUT,DELETE,POST,...
+ *   - header_input
+ *   - header_output
+ *   - content
+ *   - connection on which the handler operated (needed for ssl management
+ *   - The plugin handler requests by the server 
+ *   - add missing fields here.
+ * \author
+ */
+class ws_plugin_request {
+  public:
+      // could be improved.
+      typedef std::map<std::string,std::string> header;
+  public:
+    //
+    ws_plugin_request() ;
+    //
+    ws_plugin_request(const ws_plugin_request &o) ;
+    //
+    ~ws_plugin_request() ;
+  protected:
+    header  m_HeaderIn;
+    header  m_HeaderOut;
+    // Need the native socket so that I can decide what kind of handler to attach to the request.
+    // m_Conn; /* read write handler .... */
+};
+
+
+#endif /*WS_PLUGIN_REQUEST_H*/
diff --git a/wsproxy/ws_proxy_endpoint.cpp b/wsproxy/ws_proxy_endpoint.cpp
new file mode 100644 (file)
index 0000000..5b07b29
--- /dev/null
@@ -0,0 +1,150 @@
+#include <iostream>
+
+#include <string.h> // for memset in linux
+#include <aeb/net/ip/basic_endpoint.h>
+#include <aeb/net/ip/tcp.h>
+#include <aeb/net/socket_base.h>
+#include <aeb/net/basic_socket_stream.h>
+
+#include <aeb/net/io_dispatcher.h>
+
+#include <aeb/pointer/intrusive_ptr.h>
+#if defined(__MINGW32__)
+#include <aeb/net/detail/winsock_init.h>
+#endif
+using namespace aeb::net;
+#include "ws_constant.h"
+#include "ws_log.h"
+#include "ws_frame.h"
+#include "reverse_proxy.h"
+#include "ws_proxy_endpoint.h"
+#include "ws_proxy_handler.h"
+
+// Local debug macro
+#define LOG_WSEP_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0)
+#define LOG_WSEP_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n",args);} while (0) 
+
+#define LOG_WSEP_NOTICE(x) do { m_logger->log(eLOG_NOTICE,"%s\n",x); } while (0)
+#define LOG_WSEP_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args); printf(format "\n",args);} while (0) 
+
+#define LOG_WSEP_WARN(x) do { m_logger->log(eLOG_WARN,"%s\n",x); } while (0)
+#define LOG_WSEP_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args); printf(format "\n",args);} while (0) 
+
+#define LOG_WSEP_ERROR(x) do { m_logger->log(eLOG_ERROR,"%s\n",x); } while (0)
+#define LOG_WSEP_ERROR_FMT(format,args...) do { m_logger->log(eLOG_ERROR,format "\n",args);  } while (0)
+
+static ws_log *m_logger = ws_log::getInstance("ws_proxy_endpoint");
+
+using namespace aeb::net;
+typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+typedef aeb::net::basic_socket<ip::tcp> tcp_socket;
+
+ws_proxy_endpoint::ws_proxy_endpoint(const std::string &ws_proxy,const std::string &host,unsigned int port)
+    : m_endpoint(host.c_str(),port), m_stream(),m_ref(0), event_handler<detail::socket_type,ip::tcp>(-1)
+{
+  LOG_WSEP_DEBUG_FMT("ws_proxy_endpoint::ws_proxy_endpoint host=%s port=%d",host.c_str(),port);
+}
+
+ws_proxy_endpoint::ws_proxy_endpoint(const wsproxy::ReverseProxyType_skel::application_sptr &app,const handler_ptr &h)
+    : m_application(app)
+    , m_endpoint(app->attr_host().c_str(),app->attr_port())
+    , m_stream()
+    , m_handler(h)
+    , m_ref(0), event_handler<detail::socket_type,ip::tcp>(-1)
+{
+  LOG_WSEP_DEBUG_FMT("ws_proxy_endpoint::ws_proxy_endpoint host=%s port=%d",app->attr_host().c_str(),app->attr_port());
+}
+
+ws_proxy_endpoint::~ws_proxy_endpoint()
+{
+  LOG_WSEP_DEBUG("ws_proxy_endpoint::~ws_proxy_endpoint");
+  m_stream.close();
+}
+
+int ws_proxy_endpoint::open()
+{
+  LOG_WSEP_DEBUG("ws_proxy_endpoint::open");
+  aeb::net::ip::tcp p = m_endpoint.protocol();
+
+  m_stream.open(p);
+
+  m_stream.connect(m_endpoint);
+
+  this->m_descriptor = m_stream.native();
+  // Register to io_service 
+  register_io();
+  
+  return 0;
+}
+
+void ws_proxy_endpoint::close()
+{
+  LOG_WSEP_DEBUG("ws_proxy_endpoint::close");
+
+  // Register to io_service 
+  unregister_io();
+}
+
+
+
+int ws_proxy_endpoint::send(unsigned char *_b,size_t len)
+{
+  LOG_WSEP_DEBUG_FMT("ws_proxy_endpoint::send len=%d",len);
+  if ( ! m_stream.is_open()) 
+  {
+      // Do not even try to send anything is the backend is closed
+      LOG_WSEP_ERROR("ws_proxy_endpoint::send bakend is closed try to ropen send");
+      open();
+  }
+  int l = m_stream.send((const char *)_b,len);
+  
+  if ( l != len) {
+    LOG_WSEP_ERROR_FMT("ws_proxy_endpoint::send failed: len=%d result=%d",len,l);
+  }
+  return l;
+}
+
+
+#define BUF_SIZE (1024*4)
+void ws_proxy_endpoint::on_read()
+{
+  char buf[BUF_SIZE];
+  LOG_WSEP_DEBUG("ws_proxy_endpoint::on_read");
+  // write data back into proxy_handler (send_frame here, flow attribute is important)
+  memset(buf,0x00,BUF_SIZE);
+  int result = m_stream.receive(buf,BUF_SIZE);
+  if (result < 0 )
+  { // An error ahs occured
+    LOG_WSEP_ERROR_FMT("ws_proxy_endpoint::on_read read %d disconnect %d",result,m_stream.native());
+  } else if (result == 0)
+  { // The socket has been closed. Do the same on my side.
+    LOG_WSEP_WARN_FMT("ws_proxy_endpoint::on_read read 0 disconnect %d",m_stream.native());
+    unregister_io();
+  } else
+  { // Have got the data
+      if (! std::string("text").compare(m_application->attr_flow()))
+      {
+          //if (*m_handler)
+              m_handler->send_frame_text(buf);
+      } else 
+      {
+          //if (*m_handler)
+              m_handler->send_frame_binary((unsigned char *)buf,result);
+      }
+  }
+}
+
+void ws_proxy_endpoint::register_io()
+{
+  LOG_WSEP_DEBUG("ws_proxy_endpoint::register_io");
+  io_service *io = aeb::singleton<io_service>::get_instance();
+  io->register_handler(0,this);
+}
+void ws_proxy_endpoint::unregister_io()
+{
+    LOG_WSEP_DEBUG("ws_proxy_endpoint::unregister_io");
+    io_service *io = aeb::singleton<io_service>::get_instance();
+    io->unregister_handler(0,this);
+    m_stream.close();
+}
diff --git a/wsproxy/ws_proxy_endpoint.h b/wsproxy/ws_proxy_endpoint.h
new file mode 100644 (file)
index 0000000..885835f
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef WS_PROXY_ENDPOINT_H
+#define WS_PROXY_ENDPOINT_H
+
+// the endpoint needs to send data to the handler.
+// the handler  sends data to the endpoint
+// an endpoint  is a handler as well
+class ws_proxy_handler;
+
+/**
+ * helper class to find the appropriate application in an array
+ */
+struct find_application {
+  find_application(const std::string &n) : m_name(n) {};
+  bool operator ()(const wsproxy::ReverseProxyType_skel::application_sptr &s) {
+    return ! m_name.compare(s->attr_name());
+  };
+  std::string m_name;
+};
+
+/**
+ *
+ */
+class ws_proxy_endpoint : public event_handler<detail::socket_type,ip::tcp>
+{
+  private:
+      int m_ref;
+  public: 
+    typedef aeb::intrusive_ptr<ws_proxy_endpoint> ptr;
+    typedef aeb::intrusive_ptr<ws_proxy_handler>  handler_ptr;
+
+    inline void add_ref() {m_ref++;};
+    inline void release() {if (--m_ref == 0) delete this;};
+    
+  public:
+    typedef aeb::net::ip::basic_endpoint<ip::tcp> endpoint_type;
+    typedef aeb::net::basic_socket_stream<aeb::net::ip::tcp> stream_type;
+
+    ws_proxy_endpoint(const std::string &ws_protocol,
+                      const std::string &host,unsigned int port);
+    
+    ws_proxy_endpoint(const wsproxy::ReverseProxyType_skel::application_sptr &app,const handler_ptr &);
+    
+    virtual ~ws_proxy_endpoint();
+    // handler functions 
+    void on_read() ;
+    void on_write() {};
+    void on_accept() {} ;
+    // Possible actions....
+    int open();
+    void close();
+    int send(unsigned char *,size_t len);
+  protected:
+    void unregister_io();
+    void register_io();
+  protected:
+    wsproxy::ReverseProxyType_skel::application_sptr   m_application;
+    handler_ptr                               m_handler;
+    endpoint_type   m_endpoint;
+    stream_type     m_stream;
+};
+
+#endif
diff --git a/wsproxy/ws_proxy_handler.cpp b/wsproxy/ws_proxy_handler.cpp
new file mode 100644 (file)
index 0000000..783863c
--- /dev/null
@@ -0,0 +1,669 @@
+#include <iostream>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <map>
+#include <algorithm> // find_if
+#include <aeb/net/ip/tcp.h>
+#include <aeb/net/ip/basic_endpoint.h>
+#include <aeb/net/socket_base.h>
+#include <aeb/net/io_dispatcher.h>
+#include <aeb/net/basic_socket_acceptor.h>
+#include <aeb/net/basic_socket_stream.h>
+#include <aeb/pointer/intrusive_ptr.h>
+#if defined(__MINGW32__)
+#include <aeb/net/detail/winsock_init.h>
+#endif
+
+#include "time.h"
+#include "reverse_proxy.h"
+#include "ws_constant.h"
+#include "ws_log.h"
+#include "ws_frame.h"
+#include "sha1.h"
+#include "ws_base64.h"
+
+// Local debug macro
+#define LOG_WSPH_DEBUG(x) do { m_logger->log(eLOG_DEBUG,"%s\n",x); } while (0);
+#define LOG_WSPH_DEBUG_FMT(format,args...) do {m_logger->log(eLOG_DEBUG,format "\n" ,args);} while (0) 
+
+#define LOG_WSPH_NOTICE(x) do {m_logger->log(eLOG_NOTICE,"%s\n",x);} while (0);
+#define LOG_WSPH_NOTICE_FMT(format,args...) do { m_logger->log(eLOG_NOTICE,format "\n",args);} while (0) ;
+
+#define LOG_WSPH_WARN(x) do {m_logger->log(eLOG_WARN,"%s\n",x);} while (0);
+#define LOG_WSPH_WARN_FMT(format,args...) do { m_logger->log(eLOG_WARN,format "\n",args);} while (0) ;
+
+#define LOG_WSPH_ERROR(x) do {m_logger->log(eLOG_ERROR,"%s\n",x);} while (0);
+#define LOG_WSPH_ERROR_FMT(format,args...) do {m_logger->log(eLOG_ERROR,format "\n",args);} while (0) ;
+
+static ws_log *m_logger = ws_log::getInstance("ws_proxy_handler");
+using namespace aeb::net;
+typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
+#include "ws_proxy_endpoint.h"
+#include "ws_proxy_handler.h"
+
+void proxy_state::onRead(ws_proxy_handler &p,const ws_frame &buffer)
+{
+  ws_frame frame;
+  
+  frame.decode((unsigned char *)buffer.data(),buffer.length());
+  //frame.decode()
+  switch (frame.opcode())
+  {
+      case ews_continue:
+          break;
+      case ews_text:
+          this->onTextFrame(p,frame);
+          break;
+      case ews_binary:
+          this->onBinaryFrame(p,frame);
+          break;
+      case ews_close:
+          LOG_WSPH_WARN_FMT("proxy_state::onRead unkown opcode close: %d , value=%d",frame.opcode(),*(short *)frame.data());
+          this->onClose(p,ews_exit_normal);
+          break;
+      case ews_ping:
+          this->onPing(p);
+          break;
+      case ews_pong:
+          this->onPong(p);
+          break;
+      default:
+          LOG_WSPH_WARN_FMT("proxy_state::onRead unkown opcode : %d",frame.opcode());
+   ;
+  }
+}
+
+void proxy_state::doActivity(ws_proxy_handler &p)
+{
+    ;
+}
+
+//
+// CONNECTING
+//
+CONNECTING::CONNECTING()
+  : proxy_state()
+{
+}
+
+CONNECTING * CONNECTING::m_Instance = NULL;
+
+CONNECTING * CONNECTING::getInstance()
+{
+  if (m_Instance == NULL)
+         m_Instance = new CONNECTING();
+  return m_Instance;
+}
+
+void CONNECTING::onRead(ws_proxy_handler &p,const ws_frame &buffer) 
+{
+  std::istringstream stream((char *)buffer.data());
+  char result[256];
+  
+  LOG_WSPH_DEBUG("CONNECTING::onRead");
+  
+  while( ! stream.getline(result,256).eof() ) {
+    int pos;
+    std::string s(result);
+    if ( (pos = s.find(SEC_WEBSOCKET_KEY)) != std::string::npos && (pos == 0)) {
+      p.set_header(std::string(SEC_WEBSOCKET_KEY),s.substr(s.find(":")+1));
+      p.set_challenge(s.substr(s.find(":")+1));
+    } 
+    else if ( ((pos = s.find(WS_UPGRADE)) != std::string::npos ) && (pos == 0 )) {
+          p.set_header(WS_UPGRADE,s.substr(s.find(":")+1));
+    }
+    else if ( ((pos = s.find(WS_ORIGIN)) != std::string::npos ) && (pos == 0 )) {
+          p.set_header(WS_ORIGIN,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(SEC_WEBSOCKET_VERSION)) != std::string::npos && (pos == 0)) {
+      p.set_header(SEC_WEBSOCKET_VERSION,s.substr(s.find(":")+1));
+    }
+    else if ( (pos = s.find(WS_CONNECTION)) != std::string::npos) {
+          p.set_header(WS_CONNECTION,s.substr(s.find(":")+1));
+    }
+    else if ( ((pos = s.find(SEC_WEBSOCKET_PROTOCOL)) != std::string::npos) && (pos == 0)) {
+          p.set_header(SEC_WEBSOCKET_PROTOCOL,s.substr(s.find(":")+1));
+    } else {
+      LOG_WSPH_NOTICE_FMT("CONNECTING::onRead Unknown header: %s",s.c_str());
+    }
+
+  }
+
+  p.send_response(101);
+  p.set_state(OPEN::getInstance());
+  OPEN::getInstance()->doActivity(p);
+}
+
+void CONNECTING::onClose(ws_proxy_handler &p,unsigned short _code) 
+{
+}
+
+void CONNECTING::onPing(ws_proxy_handler &p) 
+{
+}
+
+void CONNECTING::onPong(ws_proxy_handler &p) 
+{
+}
+
+void CONNECTING::onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CONNECTING::onTextFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CONNECTING::doActivity(ws_proxy_handler &p)
+{
+    ;
+}
+
+
+//OPEN
+OPEN::OPEN()
+{
+}
+
+OPEN * OPEN::m_Instance = NULL;
+
+OPEN * OPEN::getInstance()
+{
+  if (m_Instance == NULL)
+         m_Instance = new OPEN();
+  return m_Instance;
+}
+
+void OPEN::onRead(ws_proxy_handler &p,const ws_frame &buffer)
+{
+  LOG_WSPH_DEBUG("OPEN::onRead");
+  proxy_state::onRead(p,buffer);
+}
+
+void OPEN::onClose(ws_proxy_handler &p,unsigned short _code) 
+{
+    std::string s;
+    LOG_WSPH_DEBUG("OPEN::onClose");
+    
+    //p.send_close(ews_exit_normal,s);
+    p.send_close(_code,s);
+
+    p.set_state(CLOSING::getInstance());
+    CLOSING::getInstance()->doActivity(p);
+}
+
+void OPEN::onPing(ws_proxy_handler &p) 
+{
+}
+
+void OPEN::onPong(ws_proxy_handler &p) 
+{
+}
+
+void OPEN::onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+  LOG_WSPH_DEBUG_FMT("OPEN::onBinaryFrame got (%s)",f.data());
+}
+
+void OPEN::onTextFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+  std::string proto;
+  LOG_WSPH_DEBUG_FMT("OPEN::onTextFrame got (%s)",f.data());
+  if ( ! p.protocol(proto)) {
+      p.send_frame_text(std::string("Hello"));
+  } else {
+      p.send_backend(f);
+  }
+}
+
+void OPEN::doActivity(ws_proxy_handler &p)
+{
+  // Try to connect to endpoint, ...
+    std::string proto;
+  wsproxy::ReverseProxyType_skel::application_sequence::iterator it;
+  wsproxy::ReverseProxyType_skel::application_sptr appli;
+  if (p.protocol(proto))
+  {
+      if (p.support_application(proto,appli)) {
+        LOG_WSPH_DEBUG_FMT("OPEN::doActivity found protocol %s open host %s port %ld",proto.c_str(),appli->attr_host().c_str(),appli->attr_port());
+        if (appli->attr_max_frame_size() > 0) {
+            long m_max_frame_size = appli->attr_max_frame_size();
+            LOG_WSPH_DEBUG_FMT("ws_proxy_handler::support_application max_frame_size =%d",m_max_frame_size);
+        }
+        p.open_backend(appli);
+      } else
+      {
+        LOG_WSPH_WARN_FMT("OPEN::doActivity Given protocol unsupported %s",proto.c_str());
+      }
+  } else {
+    LOG_WSPH_DEBUG_FMT("OPEN::doActivity (%s)",proto.c_str());
+  }
+}
+
+
+//
+// CLOSING
+//
+CLOSING::CLOSING()
+{
+}
+
+CLOSING * CLOSING::m_Instance = NULL;
+
+CLOSING * CLOSING::getInstance()
+{
+  if (m_Instance == NULL)
+    m_Instance = new CLOSING();
+  return m_Instance;
+}
+
+void CLOSING::onRead(ws_proxy_handler &p,const ws_frame &buffer)
+{
+  LOG_WSPH_DEBUG("CLOSING::onRead");
+  proxy_state::onRead(p,buffer);
+}
+
+void CLOSING::onClose(ws_proxy_handler &p,unsigned short _code) 
+{
+  LOG_WSPH_DEBUG("CLOSING::onClose");
+    p.set_state(CLOSED::getInstance());
+    CLOSED::getInstance()->doActivity(p);
+}
+
+void CLOSING::onPing(ws_proxy_handler &p) 
+{
+}
+
+void CLOSING::onPong(ws_proxy_handler &p) 
+{
+}
+
+void CLOSING::onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CLOSING::onTextFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CLOSING::doActivity(ws_proxy_handler &p)
+{
+    std::string s("");
+    LOG_WSPH_DEBUG("CLOSING::doActivity");
+    p.close();
+    p.set_state(CLOSED::getInstance());
+}
+
+
+//
+// CLOSED
+//
+CLOSED::CLOSED()
+{
+}
+
+CLOSED * CLOSED::m_Instance = NULL;
+
+CLOSED * CLOSED::getInstance()
+{
+  if (m_Instance == NULL)
+         m_Instance = new CLOSED();
+  return m_Instance;
+}
+
+void CLOSED::onRead(ws_proxy_handler &p,const ws_frame &buffer)
+{
+  proxy_state::onRead(p,buffer);
+}
+
+void CLOSED::onClose(ws_proxy_handler &p,unsigned short _code) 
+{
+    LOG_WSPH_DEBUG("CLOSED::onClose");
+    doActivity(p);
+}
+
+void CLOSED::onPing(ws_proxy_handler &p) 
+{
+}
+
+void CLOSED::onPong(ws_proxy_handler &p) 
+{
+}
+
+void CLOSED::onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CLOSED::onTextFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void CLOSED::doActivity(ws_proxy_handler &p)
+{
+    LOG_WSPH_DEBUG("CLOSED::doActivity");
+    LOG_WSPH_DEBUG("------------------\n");
+    p.close();
+    p.io_unregister();
+    // Here was release
+}
+
+
+//
+// Proxy Handler implementation
+//
+ws_proxy_handler::ws_proxy_handler(detail::socket_type s,const wsproxy::ReverseProxyType_skel::application_sequence &apps)
+//ws_proxy_handler::ws_proxy_handler(detail::socket_type s) 
+     : event_handler<detail::socket_type,ip::tcp>(s), m_ref(0), m_stream(s),m_state(NULL)
+     ,m_applications(apps)
+     ,m_max_frame_size(1024*4)
+{
+  LOG_WSPH_DEBUG("ws_proxy_handler::ws_proxy_handler");
+  io_service *io = aeb::singleton<io_service>::get_instance();
+  io->register_handler(0,this);
+  set_state(CONNECTING::getInstance());
+}
+
+ws_proxy_handler::~ws_proxy_handler()
+{
+    LOG_WSPH_DEBUG("ws_proxy_handler::~ws_proxy_handler");
+    io_unregister();
+}
+
+//
+void ws_proxy_handler::io_register()
+{
+  LOG_WSPH_DEBUG("ws_proxy_handler::io_register ");
+  io_service *io = aeb::singleton<io_service>::get_instance();
+  io->register_handler(0,this);
+}
+
+//
+void ws_proxy_handler::io_unregister()
+{
+    LOG_WSPH_DEBUG("ws_proxy_handler::io_unregister ");
+    io_service *io = aeb::singleton<io_service>::get_instance();
+    io->unregister_handler(0,this);
+    m_stream.close();
+}
+
+bool ws_proxy_handler::available () const 
+{
+   LOG_WSPH_DEBUG("ws_proxy_handler::available");
+   return ! m_stream.is_open();
+}
+
+// reuse handler with a new socket
+void ws_proxy_handler::reuse(aeb::net::detail::socket_type s)
+{
+   LOG_WSPH_DEBUG_FMT("ws_proxy_handler::reuse handler with s=%d",s);
+   aeb::net::ip::tcp p = m_stream.local_endpoint().protocol();
+   m_stream.assign(p,s);
+  
+   set_state(CONNECTING::getInstance());
+
+   io_register();
+}
+
+void
+ws_proxy_handler::on_write()
+{
+}
+
+#define BS  (1024*4)
+void
+ws_proxy_handler::on_read()
+{
+  char buf[BS];
+  memset(buf,0x00,BS);
+  int res = m_stream.receive(buf,BS);
+  if ( res== 0)
+  {
+    LOG_WSPH_DEBUG("ws_proxy_handler::on_read read 0 close");
+    if (m_state) {
+        onClose(ews_exit_normal);
+        //m_state->onClose(*this);
+        //m_state->doActivity(*this);
+    // release();
+    }
+  } else
+  {
+    ws_frame frame((unsigned char *)buf,res);
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::on_read size=%d dispatch",res);
+    if (m_state)
+        m_state->onRead(*this,frame);
+  }
+}
+
+void ws_proxy_handler::on_accept()
+{
+}
+
+void ws_proxy_handler::onRead(ws_proxy_handler &p,const ws_frame &buffer)
+{
+}
+
+void ws_proxy_handler::onClose(unsigned short _code) 
+{
+    if (m_state)
+        m_state->onClose(*this,_code);
+}
+
+void ws_proxy_handler::onPing(ws_proxy_handler &p) 
+{
+}
+
+void ws_proxy_handler::onPong(ws_proxy_handler &p) 
+{
+}
+
+void ws_proxy_handler::onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void ws_proxy_handler::onTextFrame(ws_proxy_handler &p,const ws_frame &f) 
+{
+}
+
+void
+ws_proxy_handler::set_header(const std::string &key,const std::string &v)
+{
+    std::string s(v.substr(1,v.size()-2));
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::set_header key=%s Value(%s)",key.c_str(),s.c_str());
+    m_header[key] = s;
+}
+
+void
+ws_proxy_handler::set_challenge(const std::string &v)
+{
+   unsigned char sh[60];
+   char hexstr[60];
+   std::string complete;
+   std::string vs(v.substr(1,v.size()-2));
+   std::string result;
+   // That's important because you never now the content of uninitialized arrays. Sometimes it works
+   // some times it does not
+   memset(sh,0x00,60);
+   memset(hexstr,0x00,60);
+   LOG_WSPH_DEBUG_FMT("ws_proxy_handler::set_challenge String(%s)",vs.c_str());
+   complete = vs + WS_HANDSHACK;
+   
+   LOG_WSPH_DEBUG_FMT("ws_proxy_handler::set_challenge complete<%s>",complete.c_str());
+   sha1::calc(complete.c_str(),complete.size(),sh);
+   sha1::toHexString(sh,hexstr);
+   
+   encode_base64((const unsigned char *)sh,20,result);
+   m_header[std::string(SEC_WEBSOCKET_ACCEPT)] = result;
+   LOG_WSPH_NOTICE_FMT("ws_proxy_handler::set_challenge String(%s) Hash=<%s>",vs.c_str(),result.c_str());
+}
+
+
+void ws_proxy_handler::send_response(int status)
+{
+    std::ostringstream os;
+    std::string response;
+    char date[125];
+    time_t t;
+    struct tm *tmp;
+    t   = time(NULL);
+    tmp = localtime(&t);
+    os<<"HTTP/1.1 ";
+    switch (status)
+    {
+        case 101:
+            {
+            os<<"101 Web Socket Protocol Handshake\r\n";
+            std::map<std::string,std::string>::iterator it = m_header.find(SEC_WEBSOCKET_PROTOCOL);
+            if (it != m_header.end())
+              os<<SEC_WEBSOCKET_PROTOCOL<<": "<<m_header[SEC_WEBSOCKET_PROTOCOL]<<"\n";
+#if 0
+            os<<"Access-Control-Allow-Headers: content-type\r\n";
+            os<<"Access-Control-Allow-Headers: authorization\r\n";
+            os<<"Access-Control-Allow-Headers: x-websocket-extensions\r\n";
+            os<<"Access-Control-Allow-Headers: x-websocket-version\r\n";
+            os<<"Access-Control-Allow-Headers: x-websocket-protocol\r\n";
+            it = m_header.find(WS_ORIGIN);
+            if (it != m_header.end()) 
+              os<<"Access-Control-Allow-Origin:"<<it->second.substr(0,it->second.size()-1)<<"\r\n";
+
+#endif
+            //os<<SEC_WEBSOCKET_VERSION<<": 13\r\n";
+            //os<<WS_CONNECTION<<": "<<m_header[WS_CONNECTION]<<"\r\n";
+            strftime(date,125,"Date: %a, %d %b %Y %T GMT\r\n",tmp);
+            os<<date;
+            os<<SEC_WEBSOCKET_ACCEPT<<": "<<m_header[SEC_WEBSOCKET_ACCEPT]<<"\r\n";
+            os<<"Server"<<": WsDede"<<"\r\n";
+            os<<WS_CONNECTION<<": Upgrade"<<"\r\n";
+            os<<WS_UPGRADE<<": websocket\r\n";
+            //Date: Thu, 20 Nov 2014 09:12:40 GMT
+            }
+            break;
+        case 400:
+        default:
+            ;
+    }
+    os<<"\r\n";
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::send_response()\n[%s]",os.str().c_str());
+    m_stream.send(os.str().c_str(),os.str().size());
+}
+
+//
+//
+//
+void 
+ws_proxy_handler::send_frame_text(const std::string &s)
+{
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::send_frame_text(buffer=<%s> size=%lu)",s.c_str(),s.size());
+    
+    ws_frame frame;
+    if (! frame.encode((unsigned const char *)s.c_str(),s.size(),ews_text) ) {
+       LOG_WSPH_DEBUG_FMT("ws_proxy_handler::send_frame_binary send buffer length %d",frame.buffer_length());
+       m_stream.send((const char *)frame.buffer(),frame.buffer_length());  
+    } else {
+        LOG_WSPH_ERROR("ws_proxy_handler::send_frame_binary Failed encode frame");
+    
+    }
+}
+
+
+void 
+ws_proxy_handler::send_frame_binary(const unsigned char *_b,int len)
+{
+    ws_frame frame;
+    if (! frame.encode(_b,len) ) {
+       LOG_WSPH_DEBUG_FMT("ws_proxy_handler::send_frame_binary send buffer length %d",frame.buffer_length());
+       m_stream.send((const char *)frame.buffer(),frame.buffer_length());  
+    } else {
+        LOG_WSPH_ERROR("ws_proxy_handler::send_frame_binary Failed encode frame");
+    
+    }
+}
+
+void ws_proxy_handler::send_close(unsigned short code,const std::string &cause)
+{
+    char buffer[10];
+    memset(buffer,0x00,10);
+    ws_header *h = (ws_header *)buffer;
+    unsigned char *len = (unsigned char *)&buffer[1];
+    unsigned short  *c = (unsigned short *)&buffer[2];
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::send_close(%d)",code);
+
+    *len    = 2;
+#if 0
+    *c      = htons(code);
+#else
+    *c      = code;
+#endif
+    h->opcode   = ews_close;
+    h->fin      = 1;
+    m_stream.send(buffer,4);
+}
+
+//
+void 
+ws_proxy_handler::close()
+{
+    LOG_WSPH_DEBUG_FMT("ws_proxy_handler::close(%d)",m_stream.native());
+    m_stream.shutdown(SHUT_WR);
+    
+    if ( ! ! m_backend)
+    {
+       ws_proxy_endpoint::ptr release_backend(NULL);
+       LOG_WSPH_DEBUG("ws_proxy_handler::close backend");
+       m_backend->close();
+       m_backend = release_backend;
+    }
+}
+
+
+bool ws_proxy_handler::support_application(const std::string n,wsproxy::ReverseProxyType_skel::application_sptr &app) const
+{
+  // Try to connect to endpoint, ...
+  wsproxy::ReverseProxyType_skel::application_sequence::const_iterator it;
+  it = std::find_if(m_applications.begin(),m_applications.end(),find_application(n));
+  if (it != m_applications.end()) {
+    app = *it;
+    return true;
+  } 
+  return false;
+}
+
+/**
+ * Tells if ws_protocol was set. If so, set s to the selected protocol
+ */
+bool ws_proxy_handler::protocol(std::string &s) 
+{
+    std::map<std::string,std::string>::iterator it = m_header.find(SEC_WEBSOCKET_PROTOCOL);
+    if (it != m_header.end()) 
+    {
+      s = m_header[SEC_WEBSOCKET_PROTOCOL];
+      return true;
+    } else 
+    {
+      return false;
+    }
+}
+
+
+void ws_proxy_handler::open_backend(const wsproxy::ReverseProxyType_skel::application_sptr &app)
+{
+    ptr p(this); // I have a problem with this.
+
+    m_backend = ws_proxy_endpoint::ptr( new ws_proxy_endpoint(app,p));
+    m_backend->open();
+}
+
+void ws_proxy_handler::send_backend(const ws_frame &f)
+{
+  if (  ! m_backend ) {
+    LOG_WSPH_ERROR("ws_proxy_handler::send_backend not available reconnect?");
+#if 0
+    ptr p(this); // I have a problem with this.
+
+    m_backend = ws_proxy_endpoint::ptr( new ws_proxy_endpoint(app,p));
+    m_backend->open();
+#endif
+ } else
+  m_backend->send(f.data(),f.length());
+}
diff --git a/wsproxy/ws_proxy_handler.h b/wsproxy/ws_proxy_handler.h
new file mode 100644 (file)
index 0000000..76d549d
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef WS_PROXY_HANDLER
+#define WS_PROXY_HANDLER
+
+
+class ws_proxy_handler;
+
+class proxy_state {
+  public:
+    proxy_state() {};
+    // Depending on state data from socket have a different meaning
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    // has a meaning when state is OPEN
+   virtual void onClose(ws_proxy_handler &p,unsigned short _code) {std::cout<<"proxy_state::onClose"<<std::endl;};
+    virtual void onPing(ws_proxy_handler &p) {};
+    virtual void onPong(ws_proxy_handler &p) {};
+    virtual void onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) {};
+    virtual void onTextFrame(ws_proxy_handler &p,const ws_frame &f) {std::cout<<"proxy_state::onTextFrame\n";};
+    virtual void doActivity(ws_proxy_handler &p);
+  protected:
+};
+
+//
+//
+//
+class CONNECTING : public proxy_state {
+  public:
+    
+    static CONNECTING *getInstance();
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    // has a meaning when state is OPEN
+    virtual void onClose(ws_proxy_handler &p,unsigned short _code) ;
+    virtual void onPing(ws_proxy_handler &p) ;
+    virtual void onPong(ws_proxy_handler &p) ;
+    virtual void onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void onTextFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void doActivity(ws_proxy_handler &p);
+  protected:
+  private:
+    CONNECTING();
+    static CONNECTING *m_Instance;
+};
+
+//
+//
+//
+class OPEN : public proxy_state {
+  public:
+    static OPEN *getInstance();
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    // has a meaning when state is OPEN
+    virtual void onClose(ws_proxy_handler &p,unsigned short _code) ;
+    virtual void onPing(ws_proxy_handler &p) ;
+    virtual void onPong(ws_proxy_handler &p) ;
+    virtual void onBinaryFrame(ws_proxy_handler &p, const ws_frame &f) ;
+    virtual void onTextFrame(ws_proxy_handler &p, const ws_frame &f) ;
+    virtual void doActivity(ws_proxy_handler &p);
+  protected:
+
+  private:
+    OPEN();
+    static OPEN *m_Instance;
+};
+
+//
+//
+//
+class CLOSING : public proxy_state {
+  public:
+    
+    static CLOSING *getInstance();
+    
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    // has a meaning when state is OPEN
+    virtual void onClose(ws_proxy_handler &p,unsigned short _code) ;
+    virtual void onPing(ws_proxy_handler &p) ;
+    virtual void onPong(ws_proxy_handler &p) ;
+    virtual void onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void onTextFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void doActivity(ws_proxy_handler &p);
+  protected:
+  private:
+    CLOSING();
+    static CLOSING *m_Instance;
+};
+
+//
+//
+//
+class CLOSED : public proxy_state {
+  public:
+    
+    static CLOSED *getInstance();
+    
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    // has a meaning when state is OPEN
+    virtual void onClose(ws_proxy_handler &p,unsigned short _code) ;
+    virtual void onPing(ws_proxy_handler &p) ;
+    virtual void onPong(ws_proxy_handler &p) ;
+    virtual void onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void onTextFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void doActivity(ws_proxy_handler &p);
+  protected:
+  private:
+    CLOSED();
+    static CLOSED *m_Instance;
+};
+
+
+// 
+// ws_proxy_handler
+//
+class ws_proxy_handler : public event_handler<detail::socket_type,ip::tcp>
+{
+  private:
+      int m_ref;
+  public: 
+    typedef aeb::intrusive_ptr<ws_proxy_handler> ptr;
+
+    inline void add_ref() {m_ref++;};
+    inline void release() {
+#if 0
+      std::cout<<"ws_proy_handler::release ref="<<m_ref<<" before decrement"<<std::endl;
+#endif
+      if (--m_ref == 0) delete this;
+    };
+    bool available () const;   
+  public:
+    ws_proxy_handler(detail::socket_type s,const wsproxy::ReverseProxyType_skel::application_sequence &apps);
+    virtual ~ws_proxy_handler() ;
+    
+    inline  void set_state(proxy_state *_s) {m_state = _s; };
+    inline  proxy_state *get_state() const {return m_state;};
+
+    virtual void onRead(ws_proxy_handler &p,const ws_frame &buffer);
+    
+    virtual void onClose(unsigned short _code) ;
+    virtual void onPing(ws_proxy_handler &p) ;
+    virtual void onPong(ws_proxy_handler &p) ;
+    virtual void onBinaryFrame(ws_proxy_handler &p,const ws_frame &f) ;
+    virtual void onTextFrame(ws_proxy_handler &p,const ws_frame &f) ;
+
+    void on_write() ;
+    void on_read() ;
+    void on_accept();
+
+    // helper function
+    void set_header(const std::string &key,const std::string &value);
+    void set_challenge(const std::string &value);
+    void send_response(int status);
+    void send_frame_text(const std::string &s);
+    void send_frame_binary(const unsigned char *buffer,int len);
+    void send_close(unsigned short code,const std::string &cause);
+    void close();
+    bool support_application(const std::string n,wsproxy::ReverseProxyType_skel::application_sptr &app) const;
+    void open_backend(const wsproxy::ReverseProxyType_skel::application_sptr &app);
+    void send_backend(const ws_frame &f);
+    
+    void io_register();
+    void io_unregister();
+    // reuse handler with a new socket
+    void reuse(aeb::net::detail::socket_type s);
+    /**
+     * Tells if ws_protocol was set. If so, set s to the selected protocol
+     */
+    bool protocol(std::string &s) ;
+  protected:
+    ws_proxy_handler(const ws_proxy_handler &p) ;
+    // Should own an endpoint 
+    proxy_state                         *m_state;
+    basic_socket_stream<ip::tcp>        m_stream;
+    std::map<std::string,std::string>   m_header;
+    ws_proxy_endpoint::ptr              m_backend;
+    wsproxy::ReverseProxyType_skel::application_sequence m_applications;
+    long                                m_max_frame_size;
+};
+
+/**
+vim:et:sw=2:ts=2
+ */
+#endif
diff --git a/xml-transform b/xml-transform
new file mode 160000 (submodule)
index 0000000..9bb0eda
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 9bb0eda673f41d6e5125c1606e69f77ec1198198