From: Ebersold Date: Wed, 22 Dec 2021 20:08:12 +0000 (+0100) Subject: Initial import from svn X-Git-Url: https://git.ebersold.fr/?a=commitdiff_plain;h=cc2f13d948d7605be5053e3c97313c29af001c86;p=wsproxy.git Initial import from svn --- cc2f13d948d7605be5053e3c97313c29af001c86 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cc376c5 --- /dev/null +++ b/.gitmodules @@ -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 index 0000000..26bbef5 --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..1cd7385 --- /dev/null +++ b/data-models/CMakeLists.txt @@ -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 index 0000000..a0a0dd5 --- /dev/null +++ b/data-models/reverse_proxy.xsd @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Field that defines the path of the request. Ex: /app/toto + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the user name the process should have once running. + + + + + + + Defines the group name the process should have once running. + + + + + + + + + + + + + + + + + + diff --git a/rules b/rules new file mode 160000 index 0000000..aeca878 --- /dev/null +++ b/rules @@ -0,0 +1 @@ +Subproject commit aeca878a84169490996e427211493ac306f00c7c diff --git a/utils b/utils new file mode 160000 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 index 0000000..ca1adb1 --- /dev/null +++ b/wsproxy/CMakeLists.txt @@ -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 index 0000000..80ea61a --- /dev/null +++ b/wsproxy/TODO.txt @@ -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 index 0000000..b97f6f6 --- /dev/null +++ b/wsproxy/config/wsproxy.xml @@ -0,0 +1,27 @@ + + + + + + + + + + aebersol + users + + + localhost + 10323 + test.cert + + + + + + + + + + + diff --git a/wsproxy/config/wsproxy_plugin.xml b/wsproxy/config/wsproxy_plugin.xml new file mode 100644 index 0000000..509e324 --- /dev/null +++ b/wsproxy/config/wsproxy_plugin.xml @@ -0,0 +1,54 @@ + + + + + + + + + + aebersol + users + + + + + + + localhost + 8082 + test.cert + + + localhost + 11323 + test.cert + + + + + /services/ + + + + + + + /services/telnet + + + + /services/XmlPhone + + + + /services/XmlAdmin + + + + + + + + + diff --git a/wsproxy/jsTerm-master/LICENSE b/wsproxy/jsTerm-master/LICENSE new file mode 100644 index 0000000..ce2a40c --- /dev/null +++ b/wsproxy/jsTerm-master/LICENSE @@ -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 index 0000000..e69de29 diff --git a/wsproxy/jsTerm-master/example/index.html b/wsproxy/jsTerm-master/example/index.html new file mode 100755 index 0000000..d4647e7 --- /dev/null +++ b/wsproxy/jsTerm-master/example/index.html @@ -0,0 +1,93 @@ + + + + jsTerm Example + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + diff --git a/wsproxy/jsTerm-master/example/palawan.html b/wsproxy/jsTerm-master/example/palawan.html new file mode 100755 index 0000000..d4647e7 --- /dev/null +++ b/wsproxy/jsTerm-master/example/palawan.html @@ -0,0 +1,93 @@ + + + + jsTerm Example + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + 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 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 index 0000000..b78bb67 --- /dev/null +++ b/wsproxy/jsTerm-master/src/Term.js @@ -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 index 0000000..b008328 --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/AnsiParser.js @@ -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 index 0000000..27f41ba --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/ByteArray.js @@ -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 index 0000000..e1684af --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/CharacterCodes.js @@ -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 index 0000000..afbb831 --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/EscapeSequencer.js @@ -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 0){ + lineArray = params.slice(2, params.length-1); + for( i=0; i0) ? 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 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 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 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 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 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 index 0000000..0854a13 --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/Keyboard.js @@ -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 index 0000000..5e4f947 --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/NVTCodes.js @@ -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 index 0000000..fdf658a --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/SixteenColors.js @@ -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 index 0000000..74d68f2 --- /dev/null +++ b/wsproxy/jsTerm-master/src/parser/Telnet.js @@ -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 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 index 0000000..9287e68 --- /dev/null +++ b/wsproxy/jsTerm-master/src/viewer/Cursor.js @@ -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 index 0000000..794290e --- /dev/null +++ b/wsproxy/jsTerm-master/src/viewer/Font.js @@ -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 index 0000000..b31b4c9 --- /dev/null +++ b/wsproxy/jsTerm-master/src/viewer/Point.js @@ -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 index 0000000..2df0976 --- /dev/null +++ b/wsproxy/main.cpp @@ -0,0 +1,450 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if defined(__MINGW32__) +#include +#endif + +// Signal stuff +#include +#include +#include +using namespace aeb::net; +typedef aeb::net::io_dispatcher io_service; +typedef aeb::net::basic_socket tcp_socket; + +#include + +#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 +#include + +#include + +#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::iterator acceptor_iterator; + +std::list 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"<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 ws32_alloc; +typedef std::basic_string,ws32_alloc> ws32_string; + +// +// Main entry point +// +int main(int argc, char **argv) +{ + + ConfigurationType_skel config; + ip::basic_endpoint ep(ip::tcp::v4(),10222); + + std::vector endpoints; + + { + ws32_alloc alloc; + ws32_string str; + str = "DEDE"; + std::cout<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 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::get_instance(); + try + { + // Register all ws application with all acceptors + for ( std::vector::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<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 index 0000000..562478b --- /dev/null +++ b/wsproxy/plugins/CMakeLists.txt @@ -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 index 0000000..67882f3 --- /dev/null +++ b/wsproxy/plugins/plugin_auth.h @@ -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 index 0000000..5a8070c --- /dev/null +++ b/wsproxy/plugins/plugin_default.cpp @@ -0,0 +1,66 @@ +#include +#include +#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"< +#include +#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"< +#include +#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"< +#include +#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"< + + + +WebSocket Test + + + +

WebSocket Test

+ +
diff --git a/wsproxy/ressources/oxo.html b/wsproxy/ressources/oxo.html new file mode 100644 index 0000000..12c7c3c --- /dev/null +++ b/wsproxy/ressources/oxo.html @@ -0,0 +1,71 @@ + + + + +WebSocket Test + + + +

WebSocket Test

+ +
diff --git a/wsproxy/sha1.cpp b/wsproxy/sha1.cpp new file mode 100755 index 0000000..49c5045 --- /dev/null +++ b/wsproxy/sha1.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "sha1.h" + +namespace sha1 +{ + namespace // local + { + // Rotate an integer value to left. + inline const unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + void calc(const void* src, const int bytelength, unsigned char* hash) + { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = (const unsigned char*) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + + void toHexString(const unsigned char* hash, char* hexstring) + { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; + } +} // namespace sha1 diff --git a/wsproxy/sha1.h b/wsproxy/sha1.h new file mode 100755 index 0000000..540c156 --- /dev/null +++ b/wsproxy/sha1.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace sha1 +{ + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + void calc(const void* src, const int bytelength, unsigned char* hash); + + /** + @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. + @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. + */ + void toHexString(const unsigned char* hash, char* hexstring); + +} // namespace sha1 + +#endif // SHA1_DEFINED diff --git a/wsproxy/test.html b/wsproxy/test.html new file mode 100644 index 0000000..061997c --- /dev/null +++ b/wsproxy/test.html @@ -0,0 +1,70 @@ + + + + +WebSocket Test + + + +

WebSocket Test

+ +
diff --git a/wsproxy/ws_acceptor.cpp b/wsproxy/ws_acceptor.cpp new file mode 100644 index 0000000..3d4427c --- /dev/null +++ b/wsproxy/ws_acceptor.cpp @@ -0,0 +1,78 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if defined(__MINGW32__) +#include +#endif + +using namespace aeb::net; +typedef aeb::net::io_dispatcher io_service; +typedef aeb::net::basic_socket 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 &e, const wsproxy::ReverseProxyType_skel::application_sequence &apps) + : basic_socket_acceptor(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(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 index 0000000..fb2ac6e --- /dev/null +++ b/wsproxy/ws_acceptor.h @@ -0,0 +1,32 @@ +#ifndef WS_ACCEPTOR_H +#define WS_ACCEPTOR_H + + +class ws_acceptor : public basic_socket_acceptor +{ + private: + int m_ref; + + ws_acceptor(ws_acceptor &a) { + std::cout<<"ws_acceptor:: copy"< 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 &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 index 0000000..4720f7f --- /dev/null +++ b/wsproxy/ws_allocator.h @@ -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 +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::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(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 + struct rebind { typedef ws_allocator other; } ; + protected: +}; + +template +inline bool operator ==(ws_allocator const &,ws_allocator const &) { + return true; +} + +#endif /*WS_ALLOCATOR_H*/ diff --git a/wsproxy/ws_base64.cpp b/wsproxy/ws_base64.cpp new file mode 100644 index 0000000..82c9439 --- /dev/null +++ b/wsproxy/ws_base64.cpp @@ -0,0 +1,60 @@ +#include +#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(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 index 0000000..6b698e4 --- /dev/null +++ b/wsproxy/ws_base64.h @@ -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 index 0000000..08e58d1 --- /dev/null +++ b/wsproxy/ws_conn_handler.h @@ -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 index 0000000..49ae5df --- /dev/null +++ b/wsproxy/ws_constant.h @@ -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 index 0000000..f2dbd18 --- /dev/null +++ b/wsproxy/ws_frame.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#include // for calloc +#include + +#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< 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 index 0000000..0424ed2 --- /dev/null +++ b/wsproxy/ws_frame.h @@ -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 index 0000000..c288aec --- /dev/null +++ b/wsproxy/ws_handler.h @@ -0,0 +1,60 @@ +#ifndef WS_HANDLER_H +#define WS_HANDLER_H + + +// +// ws_proxy_handler +// +class ws_handler : public event_handler +{ + private: + int m_ref; + public: + + typedef basic_socket_stream Stream; + /// aeb::ssl::stream ? or detail::socket_type + typedef basic_socket_stream SSLStream; + + typedef aeb::intrusive_ptr 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 index 0000000..1f656ad --- /dev/null +++ b/wsproxy/ws_handler_factory.cpp @@ -0,0 +1,138 @@ +#include +#include +#include +#include // find_if + +#include +#include +#include +#include +#include +#include +#include +#if defined(__MINGW32__) +#include +#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 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 index 0000000..f6d58c6 --- /dev/null +++ b/wsproxy/ws_handler_factory.h @@ -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 handler_map; + typedef std::list 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 index 0000000..7e2656f --- /dev/null +++ b/wsproxy/ws_http_handler.h @@ -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 index 0000000..360543e --- /dev/null +++ b/wsproxy/ws_http_header.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +#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 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:"< ws256_alloc; + typedef ws_allocator ws32_alloc; + typedef std::basic_string,ws256_alloc> string256; + typedef std::basic_string,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 m_header; + +}; + +#endif diff --git a/wsproxy/ws_https_handler.h b/wsproxy/ws_https_handler.h new file mode 100644 index 0000000..f7b4370 --- /dev/null +++ b/wsproxy/ws_https_handler.h @@ -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 index 0000000..8396c95 --- /dev/null +++ b/wsproxy/ws_log.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include // for memset +#include + +#include "ws_log.h" + + +ws_log *ws_log::getInstance(const std::string &cls) +{ +// std::cout<<"ws_log::getInstance "<second; + } + ws_log *l = new ws_log(cls); + ws_log::m_loggers[cls] = l; + // std::cout<<"ws_log::getInstance before return "< 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 index 0000000..2d309c0 --- /dev/null +++ b/wsproxy/ws_log.h @@ -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 logger_type; + typedef std::map::const_iterator logger_const_iterator; + typedef std::map::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 index 0000000..6d7268a --- /dev/null +++ b/wsproxy/ws_plugin.h @@ -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 index 0000000..f37effc --- /dev/null +++ b/wsproxy/ws_plugin_manager.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + +#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(reinterpret_cast(lt_dlsym(m_Handle,"create_plugin"))); + if ( _create ) + { + ws_plugin *p = static_cast(_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"< 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 index 0000000..8d8c699 --- /dev/null +++ b/wsproxy/ws_plugin_request.h @@ -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 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 index 0000000..5b07b29 --- /dev/null +++ b/wsproxy/ws_proxy_endpoint.cpp @@ -0,0 +1,150 @@ +#include + +#include // for memset in linux +#include +#include +#include +#include + +#include + +#include +#if defined(__MINGW32__) +#include +#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 io_service; +typedef aeb::net::basic_socket 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(-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(-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::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::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 index 0000000..885835f --- /dev/null +++ b/wsproxy/ws_proxy_endpoint.h @@ -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 +{ + private: + int m_ref; + public: + typedef aeb::intrusive_ptr ptr; + typedef aeb::intrusive_ptr handler_ptr; + + inline void add_ref() {m_ref++;}; + inline void release() {if (--m_ref == 0) delete this;}; + + public: + typedef aeb::net::ip::basic_endpoint endpoint_type; + typedef aeb::net::basic_socket_stream 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 index 0000000..783863c --- /dev/null +++ b/wsproxy/ws_proxy_handler.cpp @@ -0,0 +1,669 @@ +#include +#include +#include +#include +#include +#include // find_if +#include +#include +#include +#include +#include +#include +#include +#if defined(__MINGW32__) +#include +#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 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(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::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::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::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::iterator it = m_header.find(SEC_WEBSOCKET_PROTOCOL); + if (it != m_header.end()) + os<second.substr(0,it->second.size()-1)<<"\r\n"; + +#endif + //os< 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::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 index 0000000..76d549d --- /dev/null +++ b/wsproxy/ws_proxy_handler.h @@ -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"< +{ + private: + int m_ref; + public: + typedef aeb::intrusive_ptr ptr; + + inline void add_ref() {m_ref++;}; + inline void release() { +#if 0 + std::cout<<"ws_proy_handler::release ref="< m_stream; + std::map 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 index 0000000..9bb0eda --- /dev/null +++ b/xml-transform @@ -0,0 +1 @@ +Subproject commit 9bb0eda673f41d6e5125c1606e69f77ec1198198