relay: add experimental websocket server support (RFC 6455) for irc and weechat protocols, new option relay.network.websocket_allowed_origins

It is a partial implementation of RFC 6455: fragmentation and control frames are
not yet supported.
Text and binary frames are supported.
v2.8-utf8proc
Sebastien Helleu 2013-02-10 20:22:13 +01:00
parent eb11921f16
commit c2aeb69c46
42 changed files with 1385 additions and 199 deletions

View File

@ -1,7 +1,7 @@
WeeChat ChangeLog
=================
Sébastien Helleu <flashcode@flashtux.org>
v0.4.1-dev, 2013-02-07
v0.4.1-dev, 2013-02-10
Version 0.4.1 (under dev!)
@ -22,6 +22,8 @@ Version 0.4.1 (under dev!)
* irc: add color in output of /names when result is on server buffer (channel
not joined) (bug #38070)
* perl: simplify code to load scripts
* relay: add websocket server support (RFC 6455) for irc and weechat protocols,
new option relay.network.websocket_allowed_origins
* relay: add options "buffers" and "upgrade" for commands sync/desync in weechat
protocol
* relay: fix commands sync/desync in weechat protocol (bug #38215)

View File

@ -113,3 +113,8 @@
** Typ: Zeichenkette
** Werte: beliebige Zeichenkette (Standardwert: `"%h/ssl/relay.pem"`)
* [[option_relay.network.websocket_allowed_origins]] *relay.network.websocket_allowed_origins*
** Beschreibung: `regular expression with origins allowed in websockets (case insensitive, use "(?-i)" at beginning to make it case sensitive), example: "^http://(www\.)?example\.(com|org)"`
** Typ: Zeichenkette
** Werte: beliebige Zeichenkette (Standardwert: `""`)

View File

@ -2403,6 +2403,29 @@ um dann die Relay-Verbindung, mit SSL Verschlüsselung, anzulegen:
/relay add ssl.weechat 9001
----------------------------------------
// TRANSLATION MISSING
[[relay_websocket]]
Websocket
^^^^^^^^^
WebSocket protocol (http://tools.ietf.org/html/rfc6455[RFC 6455]) is supported
in Relay plugin for all protocols.
The WebSocket handshake is automatically detected and socket becomes ready for
WebSocket if required headers are found in handshake and if origin is allowed
(see option
<<option_relay.network.websocket_allowed_origins,relay.network.websocket_allowed_origins>>).
A WebSocket can be opened in a HTML5 with a single line of JavaScript:
[source,js]
----------------------------------------
websocket = new WebSocket("ws://server.com:5000/weechat");
----------------------------------------
The port (5000 in example) is the port defined in Relay plugin.
The URI must always ends with "/weechat" (for both IRC and WeeChat protocols).
[[rmodifier_plugin]]
Rmodifier Erweiterung
~~~~~~~~~~~~~~~~~~~~~

View File

@ -113,3 +113,8 @@
** type: string
** values: any string (default value: `"%h/ssl/relay.pem"`)
* [[option_relay.network.websocket_allowed_origins]] *relay.network.websocket_allowed_origins*
** description: `regular expression with origins allowed in websockets (case insensitive, use "(?-i)" at beginning to make it case sensitive), example: "^http://(www\.)?example\.(com|org)"`
** type: string
** values: any string (default value: `""`)

View File

@ -246,6 +246,7 @@ Plugins
| relay-raw.c | Relay raw buffer
| relay-server.c | Relay server
| relay-upgrade.c | Save/restore relay data when upgrading WeeChat
| relay-websocket.c | Websocket server functions for relay (RFC 6455)
| irc/ | IRC proxy
| relay-irc.c | Main IRC proxy functions
| weechat/ | Relay for remote interface

View File

@ -2354,6 +2354,28 @@ And then add relay with SSL, for example:
/relay add ssl.weechat 9001
----------------------------------------
[[relay_websocket]]
Websocket
^^^^^^^^^
WebSocket protocol (http://tools.ietf.org/html/rfc6455[RFC 6455]) is supported
in Relay plugin for all protocols.
The WebSocket handshake is automatically detected and socket becomes ready for
WebSocket if required headers are found in handshake and if origin is allowed
(see option
<<option_relay.network.websocket_allowed_origins,relay.network.websocket_allowed_origins>>).
A WebSocket can be opened in a HTML5 with a single line of JavaScript:
[source,js]
----------------------------------------
websocket = new WebSocket("ws://server.com:5000/weechat");
----------------------------------------
The port (5000 in example) is the port defined in Relay plugin.
The URI must always ends with "/weechat" (for both IRC and WeeChat protocols).
[[rmodifier_plugin]]
Rmodifier plugin
~~~~~~~~~~~~~~~~

View File

@ -113,3 +113,8 @@
** type: chaîne
** valeurs: toute chaîne (valeur par défaut: `"%h/ssl/relay.pem"`)
* [[option_relay.network.websocket_allowed_origins]] *relay.network.websocket_allowed_origins*
** description: `expression régulière avec les origines autorisées dans les websockets (insensible à la casse, utilisez "(?-i)" en début de chaîne pour la rendre insensible à la casse), exemple: "^http://(www\.)?example\.(com|org)"`
** type: chaîne
** valeurs: toute chaîne (valeur par défaut: `""`)

View File

@ -2428,6 +2428,30 @@ Et ajoutez le relai avec SSL, par exemple :
/relay add ssl.weechat 9001
----------------------------------------
[[relay_websocket]]
Websocket
^^^^^^^^^
Le protocole WebSocket (http://tools.ietf.org/html/rfc6455[RFC 6455]) est
supporté dans l'extension Relay pour tous les protocoles.
La poignée de main ("handshake") WebSocket est automatiquement détectée et le
socket devient prêt pour WebSocket si les en-tête requis sont trouvés dans la
poignée de main et si l'origine est autorisée (voir l'option
<<option_relay.network.websocket_allowed_origins,relay.network.websocket_allowed_origins>>).
Un WebSocket peut être ouvert dans une page HTML5 avec une seule ligne de
JavaScript :
[source,js]
----------------------------------------
websocket = new WebSocket("ws://server.com:5000/weechat");
----------------------------------------
Le port (5000 dans l'exemple) est le port défini dans l'extension Relay.
L'URI doit toujours se terminer par "/weechat" (pour les protocoles IRC et
WeeChat).
[[rmodifier_plugin]]
Extension Rmodifier
~~~~~~~~~~~~~~~~~~~

View File

@ -113,3 +113,8 @@
** tipo: stringa
** valori: qualsiasi stringa (valore predefinito: `"%h/ssl/relay.pem"`)
* [[option_relay.network.websocket_allowed_origins]] *relay.network.websocket_allowed_origins*
** descrizione: `regular expression with origins allowed in websockets (case insensitive, use "(?-i)" at beginning to make it case sensitive), example: "^http://(www\.)?example\.(com|org)"`
** tipo: stringa
** valori: qualsiasi stringa (valore predefinito: `""`)

View File

@ -2416,6 +2416,29 @@ E poi aggiungere il relay con SSL, ad esempio:
/relay add ssl.weechat 9001
----------------------------------------
// TRANSLATION MISSING
[[relay_websocket]]
Websocket
^^^^^^^^^
WebSocket protocol (http://tools.ietf.org/html/rfc6455[RFC 6455]) is supported
in Relay plugin for all protocols.
The WebSocket handshake is automatically detected and socket becomes ready for
WebSocket if required headers are found in handshake and if origin is allowed
(see option
<<option_relay.network.websocket_allowed_origins,relay.network.websocket_allowed_origins>>).
A WebSocket can be opened in a HTML5 with a single line of JavaScript:
[source,js]
----------------------------------------
websocket = new WebSocket("ws://server.com:5000/weechat");
----------------------------------------
The port (5000 in example) is the port defined in Relay plugin.
The URI must always ends with "/weechat" (for both IRC and WeeChat protocols).
[[rmodifier_plugin]]
Plugin Rmodifier
~~~~~~~~~~~~~~~~

View File

@ -113,3 +113,8 @@
** タイプ: 文字列
** 値: 未制約文字列 (デフォルト値: `"%h/ssl/relay.pem"`)
* [[option_relay.network.websocket_allowed_origins]] *relay.network.websocket_allowed_origins*
** 説明: `regular expression with origins allowed in websockets (case insensitive, use "(?-i)" at beginning to make it case sensitive), example: "^http://(www\.)?example\.(com|org)"`
** タイプ: 文字列
** 値: 未制約文字列 (デフォルト値: `""`)

View File

@ -2270,6 +2270,29 @@ WeeChat が既に起動している場合、
/relay add ssl.weechat 9001
----------------------------------------
// TRANSLATION MISSING
[[relay_websocket]]
Websocket
^^^^^^^^^
WebSocket protocol (http://tools.ietf.org/html/rfc6455[RFC 6455]) is supported
in Relay plugin for all protocols.
The WebSocket handshake is automatically detected and socket becomes ready for
WebSocket if required headers are found in handshake and if origin is allowed
(see option
<<option_relay.network.websocket_allowed_origins,relay.network.websocket_allowed_origins>>).
A WebSocket can be opened in a HTML5 with a single line of JavaScript:
[source,js]
----------------------------------------
websocket = new WebSocket("ws://server.com:5000/weechat");
----------------------------------------
The port (5000 in example) is the port defined in Relay plugin.
The URI must always ends with "/weechat" (for both IRC and WeeChat protocols).
[[rmodifier_plugin]]
=== Rmodifier プラグイン ===

View File

@ -217,6 +217,8 @@
./src/plugins/relay/relay-server.h
./src/plugins/relay/relay-upgrade.c
./src/plugins/relay/relay-upgrade.h
./src/plugins/relay/relay-websocket.c
./src/plugins/relay/relay-websocket.h
./src/plugins/relay/irc/relay-irc.c
./src/plugins/relay/irc/relay-irc.h
./src/plugins/relay/weechat/relay-weechat.c

View File

@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:07+0100\n"
"Last-Translator: Jiri Golembiovsky <golemj@gmail.com>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7684,6 +7684,18 @@ msgstr "%s%s: čtu data ze soketu: chyba %d %s"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: TLS handshake selhal"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: TLS handshake selhal"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: adresa \"%s\" nenalezena"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: čtu data ze soketu: chyba %d %s"
#, fuzzy, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: čtu data ze soketu: chyba %d %s"
@ -7936,6 +7948,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
#, fuzzy
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr "maximální počet řádků v historii bufferu (0 = nekonečně)"

View File

@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-04 08:34+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:07+0100\n"
"Last-Translator: Nils Görs <weechatter@arcor.de>\n"
"Language-Team: German <weechatter@arcor.de>\n"
@ -8372,6 +8372,18 @@ msgstr "%s%s: TLS Handshake fehlgeschlagen für Client %s%s%s: Fehler %d %s"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: TLS Handshake Zeitüberschreitung für Client %s%s%s"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: TLS Handshake Zeitüberschreitung für Client %s%s%s"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: IP Adresse \"%s\" für Relay nicht gültig"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: Fehler beim Senden von Daten an den Client %d (%s)"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: lese Daten von Socket für Client %s%s%s: Fehler %d %s"
@ -8653,6 +8665,12 @@ msgstr ""
"Datei mit SSL Zertifikat und privatem Schlüssel (zur Nutzung von Clients mit "
"SSL)"
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""
"maximale Anzahl an Zeilen im Verlaufsspeicher. Dies gilt für jeden IRC "
@ -10316,9 +10334,6 @@ msgstr "Konstanten"
#~ msgid "display message when (un)marking as away"
#~ msgstr "bei Abwesenheit und Rückkehr eine Nachricht anzeigen"
#~ msgid "%s%s: error sending data to client %d (%s)"
#~ msgstr "%s%s: Fehler beim Senden von Daten an den Client %d (%s)"
#~ msgid "display channel modes in \"buffer_name\" bar item"
#~ msgstr "zeigt die Channel-Modi mittels \"buffer_name\" in der Bar-Item an"

View File

@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:07+0100\n"
"Last-Translator: Elián Hanisch <lambdae2@gmail.com>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7929,6 +7929,18 @@ msgstr "%s%s: saludo TLS falló para el cliente %s%s%s: error %d %s"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: agotado el tiempo de espera del saludo TLS del cliente %s%s%s"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: agotado el tiempo de espera del saludo TLS del cliente %s%s%s"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: dirección IP \"%s\" no permitida por el repetidor"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: leyendo datos en socket para el cliente %s%s%s: error %d %s"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: leyendo datos en socket para el cliente %s%s%s: error %d %s"
@ -8197,6 +8209,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""
"número máximo de líneas del registro por cada canal IRC (0 = ilimitado)"

View File

@ -21,8 +21,8 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"PO-Revision-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-02-10 08:29+0100\n"
"Last-Translator: Sebastien Helleu <flashcode@flashtux.org>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
"Language: French\n"
@ -8143,6 +8143,19 @@ msgstr ""
"%s%s: délai maximum dépassé pour la poignée de main (handshake) de TLS pour "
"le client %s%s%s"
#, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr ""
"%s%s: poignée de main (handshake) websocket invalide pour le client %s%s%s"
#, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: origine \"%s\" non autorisée pour le websocket"
#, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: erreur de décodage d'un message websocket pour le client %s%s%s"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr ""
@ -8422,6 +8435,15 @@ msgstr ""
"fichier avec le certificat et la clé privée SSL (pour servir les clients "
"avec SSL)"
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
"expression régulière avec les origines autorisées dans les websockets "
"(insensible à la casse, utilisez \"(?-i)\" en début de chaîne pour la rendre "
"insensible à la casse), exemple: \"^http://(www\\.)?example\\.(com|org)\""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""
"nombre maximum de lignes dans l'historique par canal IRC (0 = sans limite)"

View File

@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:07+0100\n"
"Last-Translator: Andras Voroskoi <voroskoi@frugalware.org>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7183,6 +7183,18 @@ msgstr "%s adatküldési hiba az IRC szerveren\n"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s gnutls kézfogás sikertelen\n"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s gnutls kézfogás sikertelen\n"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s cím \"%s\" nem található\n"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s adatküldési hiba az IRC szerveren\n"
#, fuzzy, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s adatküldési hiba az IRC szerveren\n"
@ -7414,6 +7426,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
#, fuzzy
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""

View File

@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-03 16:17+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-02-03 12:13+0100\n"
"Last-Translator: Marco Paolone <marcopaolone@gmail.com>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7945,6 +7945,18 @@ msgstr "%s%s: handshake TLS fallito per il client %s%s%s: errore %d %s"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: timeout per l'handshake per il client %s%s%s"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: timeout per l'handshake per il client %s%s%s"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: indirizzo IP \"%s\" non consentito per il relay"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: lettura dei dati sul socket per il client %s%s%s: errore %d %s"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: lettura dei dati sul socket per il client %s%s%s: errore %d %s"
@ -8223,6 +8235,12 @@ msgstr ""
"file con il certificato SSL e la chiave privata (per servire i client con "
"SSL)"
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""
"numero massimo di righe nella cronologia per canale IRC (0 = nessun limite)"

View File

@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:07+0100\n"
"Last-Translator: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp>\n"
"Language-Team: Japanese <https://github.com/l/WeeChat>\n"
@ -7860,6 +7860,19 @@ msgstr "%s%s: クライアント %s%s%s との TLS ハンドシェイクが失
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: クライアント %s%s%s との TLS ハンドシェイクがタイムアウト"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: クライアント %s%s%s との TLS ハンドシェイクがタイムアウト"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: IP アドレス \"%s\" はリレーの許可がありません"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr ""
"%s%s: クライアント %s%s%s のソケットからデータを読み取り中: エラー %d %s"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr ""
@ -8130,6 +8143,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr "SSL 証明書と秘密鍵のファイル (SSL 接続を利用するクライアント用)"
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr "IRC チャンネルごとのバックログの最大行数 (0 = 制限無し)"

View File

@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:08+0100\n"
"Last-Translator: Krzysztof Korościk <soltys@szluug.org>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -8005,6 +8005,18 @@ msgstr ""
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: upłynął czas na nawiązanie połączenia TLS dla klienta %s%s%s"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: upłynął czas na nawiązanie połączenia TLS dla klienta %s%s%s"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: adres IP \"%s\" nie posiada zezwolenia na połączenie"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: odczyt danych z gniazda dla klienta %s%s%s: błąd %d %s"
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: odczyt danych z gniazda dla klienta %s%s%s: błąd %d %s"
@ -8279,6 +8291,12 @@ msgstr ""
"plik z certyfikatem SSL i kluczem prywatnym (dla obsługi klientów poprzez "
"SSL)"
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""
"maksymalna ilość linii w historii każdego bufora dla kanału IRC (0 = bez "

View File

@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:08+0100\n"
"Last-Translator: Sergio Durigan Junior <sergiosdj@gmail.com>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7339,6 +7339,18 @@ msgstr "%s%s: lendo dados no socket: erro %d %s"
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s%s: handshake TLS falhou"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s%s: handshake TLS falhou"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s%s: endereço IP \"%s\" não permitido para relay"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s%s: lendo dados no socket: erro %d %s"
#, fuzzy, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s%s: lendo dados no socket: erro %d %s"
@ -7575,6 +7587,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
#, fuzzy
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr "número máximo de linhas no histórico por buffer (0 = ilimitado)"

View File

@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: WeeChat 0.4.1-dev\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: 2013-01-20 12:08+0100\n"
"Last-Translator: Aleksey V Zapparov AKA ixti <ixti@member.fsf.org>\n"
"Language-Team: weechat-dev <weechat-dev@nongnu.org>\n"
@ -7209,6 +7209,18 @@ msgstr "%s ошибка при отправке данных IRC серверу\
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr "%s инициализация gnutls не удалось\n"
#, fuzzy, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr "%s инициализация gnutls не удалось\n"
#, fuzzy, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr "%s адрес \"%s\" не найден\n"
#, fuzzy, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr "%s ошибка при отправке данных IRC серверу\n"
#, fuzzy, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr "%s ошибка при отправке данных IRC серверу\n"
@ -7440,6 +7452,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
#, fuzzy
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr "максимальное количество команд в истории (0 = не ограничено)"

View File

@ -210,6 +210,8 @@ SET(WEECHAT_SOURCES
./src/plugins/relay/relay-server.h
./src/plugins/relay/relay-upgrade.c
./src/plugins/relay/relay-upgrade.h
./src/plugins/relay/relay-websocket.c
./src/plugins/relay/relay-websocket.h
./src/plugins/relay/irc/relay-irc.c
./src/plugins/relay/irc/relay-irc.h
./src/plugins/relay/weechat/relay-weechat.c

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
"POT-Creation-Date: 2013-02-01 11:12+0100\n"
"POT-Creation-Date: 2013-02-10 20:17+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -6318,6 +6318,18 @@ msgstr ""
msgid "%s%s: TLS handshake timeout for client %s%s%s"
msgstr ""
#, c-format
msgid "%s%s: invalid websocket handshake received for client %s%s%s"
msgstr ""
#, c-format
msgid "%s%s: origin \"%s\" not allowed for websocket"
msgstr ""
#, c-format
msgid "%s%s: error decoding websocket frame for client %s%s%s"
msgstr ""
#, c-format
msgid "%s%s: reading data on socket for client %s%s%s: error %d %s"
msgstr ""
@ -6534,6 +6546,12 @@ msgid ""
"file with SSL certificate and private key (for serving clients with SSL)"
msgstr ""
msgid ""
"regular expression with origins allowed in websockets (case insensitive, use "
"\"(?-i)\" at beginning to make it case sensitive), example: \"^http://(www"
"\\.)?example\\.(com|org)\""
msgstr ""
msgid "maximum number of lines in backlog per IRC channel (0 = unlimited)"
msgstr ""

View File

@ -32,7 +32,8 @@ relay-info.c relay-info.h
relay-network.c relay-network.h
relay-raw.c relay-raw.h
relay-server.c relay-server.h
relay-upgrade.c relay-upgrade.h)
relay-upgrade.c relay-upgrade.h
relay-websocket.c relay-websocket.h)
SET_TARGET_PROPERTIES(relay PROPERTIES PREFIX "")
SET (LINK_LIBS)

View File

@ -52,7 +52,9 @@ relay_la_SOURCES = relay.c \
relay-server.c \
relay-server.h \
relay-upgrade.c \
relay-upgrade.h
relay-upgrade.h \
relay-websocket.c \
relay-websocket.h
relay_la_LDFLAGS = -module
relay_la_LIBADD = $(RELAY_LFLAGS) $(ZLIB_LFLAGS) $(GNUTLS_LFLAGS)

View File

@ -231,13 +231,12 @@ relay_irc_sendf (struct t_relay_client *client, const char *format, ...)
str_message = weechat_hashtable_get (hashtable_out, hash_key);
if (!str_message)
break;
relay_raw_print (client, RELAY_RAW_FLAG_SEND, "%s", str_message);
length = strlen (str_message) + 16 + 1;
message = malloc (length);
if (message)
{
snprintf (message, length, "%s\r\n", str_message);
relay_client_send (client, message, strlen (message));
relay_client_send (client, message, strlen (message), NULL);
free (message);
}
number++;
@ -1290,9 +1289,9 @@ relay_irc_recv_command_capab (struct t_relay_client *client,
*/
void
relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
relay_irc_recv (struct t_relay_client *client, const char *data)
{
char *pos, str_time[128], str_signal[128], str_server_channel[256];
char str_time[128], str_signal[128], str_server_channel[256];
char str_command[128], *target, **irc_argv;
const char *irc_command, *irc_channel, *irc_args, *irc_args2;
int irc_argc, redirect_msg;
@ -1304,11 +1303,6 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
irc_argv = NULL;
irc_argc = 0;
/* remove \r at the end of message */
pos = strchr (data, '\r');
if (pos)
pos[0] = '\0';
/* display debug message */
if (weechat_relay_plugin->debug >= 2)
{
@ -1320,9 +1314,6 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
data);
}
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_RECV, "%s", data);
/* parse IRC message */
hash_parsed = relay_irc_message_parse (data);
if (!hash_parsed)
@ -1707,27 +1698,6 @@ end:
weechat_string_free_split (irc_argv);
}
/*
* Reads data from a client.
*/
void
relay_irc_recv (struct t_relay_client *client, const char *data)
{
char **items;
int items_count, i;
items = weechat_string_split (data, "\n", 0, 0, &items_count);
if (items)
{
for (i = 0; i < items_count; i++)
{
relay_irc_recv_one_msg (client, items[i]);
}
weechat_string_free_split (items);
}
}
/*
* Closes connection with client.
*/

View File

@ -63,7 +63,7 @@ enum t_relay_irc_server_capab
};
extern void relay_irc_recv (struct t_relay_client *client,
const char *data);
const char *data);
extern void relay_irc_close_connection (struct t_relay_client *client);
extern void relay_irc_alloc (struct t_relay_client *client);
extern void relay_irc_alloc_with_infolist (struct t_relay_client *client,

View File

@ -41,7 +41,9 @@
#include "relay-config.h"
#include "relay-buffer.h"
#include "relay-network.h"
#include "relay-raw.h"
#include "relay-server.h"
#include "relay-websocket.h"
char *relay_client_status_string[] = /* strings for status */
@ -49,6 +51,9 @@ char *relay_client_status_string[] = /* strings for status */
N_("connected"), N_("auth failed"), N_("disconnected")
};
char *relay_client_data_type_string[] = /* strings for data types */
{ "text", "binary" };
struct t_relay_client *relay_clients = NULL;
struct t_relay_client *last_relay_client = NULL;
int relay_client_count = 0; /* number of clients */
@ -216,6 +221,168 @@ relay_client_handshake_timer_cb (void *data, int remaining_calls)
}
#endif
/*
* Reads text data from a client: splits data on '\n' and keep a partial message
* if date does not end with '\n'.
*/
void
relay_client_recv_text (struct t_relay_client *client, const char *data)
{
char *new_partial, *raw_msg, **lines, *pos, *tmp, *handshake;
int i, num_lines, length, rc;
if (client->partial_message)
{
new_partial = realloc (client->partial_message,
strlen (client->partial_message) +
strlen (data) + 1);
if (!new_partial)
return;
client->partial_message = new_partial;
strcat (client->partial_message, data);
}
else
client->partial_message = strdup (data);
pos = strrchr (client->partial_message, '\n');
if (pos)
{
/* print message in raw buffer */
raw_msg = weechat_strndup (client->partial_message,
pos - client->partial_message + 1);
if (raw_msg)
{
relay_raw_print (client, RELAY_RAW_FLAG_RECV,
raw_msg, strlen (raw_msg) + 1);
free (raw_msg);
}
pos[0] = '\0';
lines = weechat_string_split (client->partial_message, "\n",
0, 0, &num_lines);
if (lines)
{
for (i = 0; i < num_lines; i++)
{
/* remove final '\r' */
length = strlen (lines[i]);
if ((length > 0) && (lines[i][length - 1] == '\r'))
lines[i][length - 1] = '\0';
/* if websocket is initializing */
if (client->websocket == 1)
{
if (lines[i][0])
{
/* web socket is initializing, read HTTP headers */
relay_websocket_save_header (client, lines[i]);
}
else
{
/*
* empty line means that we have received all HTTP
* headers: then we check the validity of websocket, and
* if it is OK, we'll do the handshake and answer to the
* client
*/
rc = relay_websocket_client_handshake_valid (client);
if (rc == 0)
{
/* handshake from client is valid */
handshake = relay_websocket_build_handshake (client);
if (handshake)
{
relay_client_send (client, handshake,
strlen (handshake), NULL);
free (handshake);
client->websocket = 2;
}
}
else
{
switch (rc)
{
case -1:
relay_websocket_send_http (client,
"400 Bad Request");
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf_tags (NULL, "relay_client",
_("%s%s: invalid websocket "
"handshake received for "
"client %s%s%s"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
RELAY_COLOR_CHAT_CLIENT,
client->desc,
RELAY_COLOR_CHAT);
}
break;
case -2:
relay_websocket_send_http (client,
"403 Forbidden");
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf_tags (NULL, "relay_client",
_("%s%s: origin \"%s\" "
"not allowed for websocket"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
weechat_hashtable_get (client->http_headers,
"Origin"));
}
break;
}
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
}
/* remove HTTP headers */
weechat_hashtable_free (client->http_headers);
client->http_headers = NULL;
/*
* discard all received data after the handshake
* received from client, and return immediately
*/
free (client->partial_message);
client->partial_message = NULL;
return;
}
}
else
{
/* receive text from client */
switch (client->protocol)
{
case RELAY_PROTOCOL_WEECHAT:
relay_weechat_recv (client, lines[i]);
break;
case RELAY_PROTOCOL_IRC:
relay_irc_recv (client, lines[i]);
break;
case RELAY_NUM_PROTOCOLS:
break;
}
}
}
weechat_string_free_split (lines);
}
if (pos[1])
{
tmp = strdup (pos + 1);
free (client->partial_message);
client->partial_message = tmp;
}
else
{
free (client->partial_message);
client->partial_message = NULL;
}
}
}
/*
* Reads data from a client.
*/
@ -224,7 +391,8 @@ int
relay_client_recv_cb (void *arg_client, int fd)
{
struct t_relay_client *client;
static char buffer[4096 + 2];
static char buffer[4096], decoded[4096];
const char *ptr_buffer;
int num_read;
/* make C compiler happy */
@ -245,18 +413,63 @@ relay_client_recv_cb (void *arg_client, int fd)
if (num_read > 0)
{
client->bytes_recv += num_read;
buffer[num_read] = '\0';
switch (client->protocol)
ptr_buffer = buffer;
/*
* if we are receiving the first message from client, check if it looks
* like a websocket
*/
if (client->bytes_recv == 0)
{
case RELAY_PROTOCOL_WEECHAT:
relay_weechat_recv (client, buffer);
break;
case RELAY_PROTOCOL_IRC:
relay_irc_recv (client, buffer);
break;
case RELAY_NUM_PROTOCOLS:
break;
if (relay_websocket_is_http_get_weechat (buffer))
{
/*
* web socket is just initializing for now, it's not accepted
* (we will check later with "http_headers" if web socket is
* valid or not)
*/
client->websocket = 1;
client->http_headers = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
}
}
client->bytes_recv += num_read;
if (client->websocket == 2)
{
/* websocket used, decode message */
if (!relay_websocket_decode_frame ((unsigned char *)buffer, num_read,
(unsigned char *)decoded))
{
/* error when decoding frame: close connection */
weechat_printf_tags (NULL, "relay_client",
_("%s%s: error decoding websocket frame "
"for client %s%s%s"),
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
RELAY_COLOR_CHAT_CLIENT,
client->desc,
RELAY_COLOR_CHAT);
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
return WEECHAT_RC_OK;
}
ptr_buffer = decoded;
}
if ((client->websocket == 1)
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT))
{
/* websocket initializing or text data for this client */
relay_client_recv_text (client, ptr_buffer);
}
else
{
/* receive buffer as-is (binary data) */
/* currently, all supported protocols receive only text, no binary */
}
relay_buffer_refresh (NULL);
}
@ -310,10 +523,13 @@ relay_client_recv_cb (void *arg_client, int fd)
*/
void
relay_client_outqueue_add (struct t_relay_client *client, const char *data,
int data_size)
relay_client_outqueue_add (struct t_relay_client *client,
const char *data, int data_size,
int raw_flags[2], const char *raw_message[2],
int raw_size[2])
{
struct t_relay_client_outqueue *new_outqueue;
int i;
if (!client || !data || (data_size <= 0))
return;
@ -329,6 +545,23 @@ relay_client_outqueue_add (struct t_relay_client *client, const char *data,
}
memcpy (new_outqueue->data, data, data_size);
new_outqueue->data_size = data_size;
for (i = 0; i < 2; i++)
{
new_outqueue->raw_flags[i] = 0;
new_outqueue->raw_message[i] = NULL;
new_outqueue->raw_size[i] = 0;
if (raw_message && raw_message[i] && (raw_size[i] > 0))
{
new_outqueue->raw_message[i] = malloc (raw_size[i]);
if (new_outqueue->raw_message[i])
{
new_outqueue->raw_flags[i] = raw_flags[i];
memcpy (new_outqueue->raw_message[i], raw_message[i],
raw_size[i]);
new_outqueue->raw_size[i] = raw_size[i];
}
}
}
new_outqueue->prev_outqueue = client->last_outqueue;
new_outqueue->next_outqueue = NULL;
@ -367,6 +600,10 @@ relay_client_outqueue_free (struct t_relay_client *client,
/* free data */
if (outqueue->data)
free (outqueue->data);
if (outqueue->raw_message[0])
free (outqueue->raw_message[0]);
if (outqueue->raw_message[1])
free (outqueue->raw_message[1]);
free (outqueue);
/* set new head */
@ -389,18 +626,88 @@ relay_client_outqueue_free_all (struct t_relay_client *client)
/*
* Sends data to client (adds in out queue if it's impossible to send now).
*
* If "message_raw_buffer" is not NULL, it is used for display in raw buffer
* and replaces display of data, which is default.
*
* Returns number of bytes sent to client, -1 if error.
*/
int
relay_client_send (struct t_relay_client *client, const char *data,
int data_size)
int data_size, const char *message_raw_buffer)
{
int num_sent;
int num_sent, raw_size[2], raw_flags[2], i;
char *websocket_frame;
unsigned long long length_frame;
const char *ptr_data, *raw_msg[2];
if (client->sock < 0)
return -1;
ptr_data = data;
websocket_frame = NULL;
/* set raw messages */
for (i = 0; i < 2; i++)
{
raw_flags[i] = RELAY_RAW_FLAG_SEND;
raw_msg[i] = NULL;
raw_size[i] = 0;
}
if (message_raw_buffer)
{
if (weechat_relay_plugin->debug >= 2)
{
raw_msg[0] = message_raw_buffer;
raw_size[0] = strlen (message_raw_buffer) + 1;
raw_msg[1] = data;
raw_size[1] = data_size;
raw_flags[1] |= RELAY_RAW_FLAG_BINARY;
if ((client->websocket == 1)
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT))
{
raw_size[1]--;
}
}
else
{
raw_msg[0] = message_raw_buffer;
raw_size[0] = strlen (message_raw_buffer) + 1;
}
}
else
{
raw_msg[0] = data;
raw_size[0] = data_size;
if ((client->websocket != 1)
&& (client->send_data_type == RELAY_CLIENT_DATA_BINARY))
{
/*
* set binary flag if we send binary to client
* (except if websocket == 1, which means that websocket is
* initializing, and then we are sending HTTP data, as text)
*/
raw_flags[0] |= RELAY_RAW_FLAG_BINARY;
}
else
{
/* count the final '\0' in size */
raw_size[0]++;
}
}
/* if websocket is initialized, encode data in a websocket frame */
if (client->websocket == 2)
{
websocket_frame = relay_websocket_encode_frame (client, data, data_size,
&length_frame);
if (websocket_frame)
{
ptr_data = websocket_frame;
data_size = length_frame;
}
}
num_sent = -1;
/*
@ -409,19 +716,28 @@ relay_client_send (struct t_relay_client *client, const char *data,
*/
if (client->outqueue)
{
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
#ifdef HAVE_GNUTLS
if (client->ssl)
num_sent = gnutls_record_send (client->gnutls_sess, data, data_size);
num_sent = gnutls_record_send (client->gnutls_sess, ptr_data, data_size);
else
#endif
num_sent = send (client->sock, data, data_size, 0);
num_sent = send (client->sock, ptr_data, data_size, 0);
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
{
if (raw_msg[i])
{
relay_raw_print (client,
raw_flags[i], raw_msg[i], raw_size[i]);
}
}
if (num_sent > 0)
{
client->bytes_sent += num_sent;
@ -430,8 +746,9 @@ relay_client_send (struct t_relay_client *client, const char *data,
if (num_sent < data_size)
{
/* some data was not sent, add it to outqueue */
relay_client_outqueue_add (client, data + num_sent,
data_size - num_sent);
relay_client_outqueue_add (client, ptr_data + num_sent,
data_size - num_sent,
NULL, NULL, NULL);
}
}
else if (num_sent < 0)
@ -443,7 +760,8 @@ relay_client_send (struct t_relay_client *client, const char *data,
|| (num_sent == GNUTLS_E_INTERRUPTED))
{
/* add message to queue (will be sent later) */
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
@ -466,7 +784,8 @@ relay_client_send (struct t_relay_client *client, const char *data,
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
/* add message to queue (will be sent later) */
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
@ -486,6 +805,9 @@ relay_client_send (struct t_relay_client *client, const char *data,
}
}
if (websocket_frame)
free (websocket_frame);
return num_sent;
}
@ -497,7 +819,7 @@ int
relay_client_timer_cb (void *data, int remaining_calls)
{
struct t_relay_client *ptr_client;
int num_sent;
int num_sent, i;
char *buf;
/* make C compiler happy */
@ -527,6 +849,26 @@ relay_client_timer_cb (void *data, int remaining_calls)
}
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
{
if (ptr_client->outqueue->raw_message
&& ptr_client->outqueue->raw_message[i])
{
/*
* print raw message and remove it from outqueue
* (so that it is displayed only one time, even if
* message is sent in many chunks)
*/
relay_raw_print (ptr_client,
ptr_client->outqueue->raw_flags[i],
ptr_client->outqueue->raw_message[i],
ptr_client->outqueue->raw_size[i]);
ptr_client->outqueue->raw_flags[i] = 0;
free (ptr_client->outqueue->raw_message[i]);
ptr_client->outqueue->raw_message[i] = NULL;
ptr_client->outqueue->raw_size[i] = 0;
}
}
if (num_sent > 0)
{
ptr_client->bytes_sent += num_sent;
@ -644,6 +986,8 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
#ifdef HAVE_GNUTLS
new_client->hook_timer_handshake = NULL;
#endif
new_client->websocket = 0;
new_client->http_headers = NULL;
new_client->address = strdup ((address) ? address : "?");
new_client->status = RELAY_STATUS_CONNECTED;
new_client->protocol = server->protocol;
@ -656,6 +1000,22 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
new_client->last_activity = new_client->start_time;
new_client->bytes_recv = 0;
new_client->bytes_sent = 0;
switch (new_client->protocol)
{
case RELAY_PROTOCOL_WEECHAT:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_BINARY;
break;
case RELAY_PROTOCOL_IRC:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
break;
default:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
break;
}
new_client->partial_message = NULL;
relay_client_set_desc (new_client);
@ -792,6 +1152,8 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
new_client->gnutls_sess = NULL;
new_client->hook_timer_handshake = NULL;
#endif
new_client->websocket = weechat_infolist_integer (infolist, "websocket");
new_client->http_headers = NULL;
new_client->address = strdup (weechat_infolist_string (infolist, "address"));
new_client->status = weechat_infolist_integer (infolist, "status");
new_client->protocol = weechat_infolist_integer (infolist, "protocol");
@ -816,6 +1178,10 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
"%lu", &(new_client->bytes_recv));
sscanf (weechat_infolist_string (infolist, "bytes_sent"),
"%lu", &(new_client->bytes_sent));
new_client->recv_data_type = weechat_infolist_integer (infolist, "recv_data_type");
new_client->send_data_type = weechat_infolist_integer (infolist, "send_data_type");
str = weechat_infolist_string (infolist, "partial_message");
new_client->partial_message = (str) ? strdup (str) : NULL;
str = weechat_infolist_string (infolist, "desc");
if (str)
@ -972,8 +1338,12 @@ relay_client_free (struct t_relay_client *client)
if (client->hook_timer_handshake)
weechat_unhook (client->hook_timer_handshake);
#endif
if (client->http_headers)
weechat_hashtable_free (client->http_headers);
if (client->hook_fd)
weechat_unhook (client->hook_fd);
if (client->partial_message)
free (client->partial_message);
if (client->protocol_data)
{
switch (client->protocol)
@ -1078,6 +1448,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
if (!weechat_infolist_new_var_pointer (ptr_item, "hook_timer_handshake", client->hook_timer_handshake))
return 0;
#endif
if (!weechat_infolist_new_var_integer (ptr_item, "websocket", client->websocket))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "address", client->address))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "status", client->status))
@ -1108,6 +1480,12 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
snprintf (value, sizeof (value), "%lu", client->bytes_sent);
if (!weechat_infolist_new_var_string (ptr_item, "bytes_sent", value))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "recv_data_type", client->recv_data_type))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "send_data_type", client->send_data_type))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "partial_message", client->partial_message))
return 0;
switch (client->protocol)
{
@ -1146,6 +1524,10 @@ relay_client_print_log ()
weechat_log_printf (" gnutls_sess . . . . . : 0x%lx", ptr_client->gnutls_sess);
weechat_log_printf (" hook_timer_handshake. : 0x%lx", ptr_client->hook_timer_handshake);
#endif
weechat_log_printf (" websocket . . . . . . : %d", ptr_client->websocket);
weechat_log_printf (" http_headers. . . . . : 0x%lx (hashtable: '%s')",
ptr_client->http_headers,
weechat_hashtable_get_string (ptr_client->http_headers, "keys_values"));
weechat_log_printf (" address . . . . . . . : '%s'", ptr_client->address);
weechat_log_printf (" status. . . . . . . . : %d (%s)",
ptr_client->status,
@ -1162,6 +1544,13 @@ relay_client_print_log ()
weechat_log_printf (" last_activity . . . . : %ld", ptr_client->last_activity);
weechat_log_printf (" bytes_recv. . . . . . : %lu", ptr_client->bytes_recv);
weechat_log_printf (" bytes_sent. . . . . . : %lu", ptr_client->bytes_sent);
weechat_log_printf (" recv_data_type. . . . : %d (%s)",
ptr_client->recv_data_type,
relay_client_data_type_string[ptr_client->recv_data_type]);
weechat_log_printf (" send_data_type. . . . : %d (%s)",
ptr_client->send_data_type,
relay_client_data_type_string[ptr_client->send_data_type]);
weechat_log_printf (" partial_message . . . : '%s'", ptr_client->partial_message);
weechat_log_printf (" protocol_data . . . . : 0x%lx", ptr_client->protocol_data);
switch (ptr_client->protocol)
{

View File

@ -39,6 +39,16 @@ enum t_relay_status
RELAY_NUM_STATUS,
};
/* type of data exchanged with client */
enum t_relay_client_data_type
{
RELAY_CLIENT_DATA_TEXT = 0, /* text messages */
RELAY_CLIENT_DATA_BINARY, /* binary messages */
/* number of data types */
RELAY_NUM_CLIENT_DATA_TYPES,
};
/* macros for status */
#define RELAY_CLIENT_HAS_ENDED(client) \
@ -51,6 +61,9 @@ struct t_relay_client_outqueue
{
char *data; /* data to send */
int data_size; /* number of bytes */
int raw_flags[2]; /* flags for raw messages */
char *raw_message[2]; /* msgs for raw buffer (can be NULL)*/
int raw_size[2]; /* size (in bytes) of raw messages */
struct t_relay_client_outqueue *next_outqueue; /* next msg in queue */
struct t_relay_client_outqueue *prev_outqueue; /* prev msg in queue */
};
@ -67,6 +80,8 @@ struct t_relay_client
gnutls_session_t gnutls_sess; /* gnutls session (only if SSL used) */
struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/
#endif
int websocket; /* 0=not a ws, 1=init ws, 2=ws ready */
struct t_hashtable *http_headers; /* HTTP headers for websocket */
char *address; /* string with IP address */
enum t_relay_status status; /* status (connecting, active,..) */
enum t_relay_protocol protocol; /* protocol (irc,..) */
@ -80,6 +95,9 @@ struct t_relay_client
time_t last_activity; /* time of last byte received/sent */
unsigned long bytes_recv; /* bytes received from client */
unsigned long bytes_sent; /* bytes sent to client */
enum t_relay_client_data_type recv_data_type; /* type recv from client */
enum t_relay_client_data_type send_data_type; /* type sent to client */
char *partial_message; /* partial text message received */
void *protocol_data; /* data depending on protocol used */
struct t_relay_client_outqueue *outqueue; /* queue for outgoing msgs */
struct t_relay_client_outqueue *last_outqueue; /* last outgoing msg */
@ -97,7 +115,7 @@ extern struct t_relay_client *relay_client_search_by_number (int number);
extern struct t_relay_client *relay_client_search_by_id (int id);
extern int relay_client_recv_cb (void *arg_client, int fd);
extern int relay_client_send (struct t_relay_client *client, const char *data,
int data_size);
int data_size, const char *message_raw_buffer);
extern int relay_client_timer_cb (void *data, int remaining_calls);
extern struct t_relay_client *relay_client_new (int sock, const char *address,
struct t_relay_server *server);

View File

@ -57,6 +57,7 @@ struct t_config_option *relay_config_network_ipv6;
struct t_config_option *relay_config_network_max_clients;
struct t_config_option *relay_config_network_password;
struct t_config_option *relay_config_network_ssl_cert_key;
struct t_config_option *relay_config_network_websocket_allowed_origins;
/* relay config, irc section */
@ -69,6 +70,7 @@ struct t_config_option *relay_config_irc_backlog_time_format;
/* other */
regex_t *relay_config_regex_allowed_ips = NULL;
regex_t *relay_config_regex_websocket_allowed_origins = NULL;
struct t_hashtable *relay_config_hashtable_irc_backlog_tags = NULL;
@ -187,6 +189,44 @@ relay_config_change_network_ssl_cert_key (void *data,
relay_network_set_ssl_cert_key (1);
}
/*
* Callback for changes on option "relay.network.websocker_allowed_origins".
*/
void
relay_config_change_network_websocket_allowed_origins (void *data,
struct t_config_option *option)
{
const char *allowed_origins;
/* make C compiler happy */
(void) data;
(void) option;
if (relay_config_regex_websocket_allowed_origins)
{
regfree (relay_config_regex_websocket_allowed_origins);
free (relay_config_regex_websocket_allowed_origins);
relay_config_regex_websocket_allowed_origins = NULL;
}
allowed_origins = weechat_config_string (relay_config_network_websocket_allowed_origins);
if (allowed_origins && allowed_origins[0])
{
relay_config_regex_websocket_allowed_origins = malloc (sizeof (*relay_config_regex_websocket_allowed_origins));
if (relay_config_regex_websocket_allowed_origins)
{
if (weechat_string_regcomp (relay_config_regex_websocket_allowed_origins,
allowed_origins,
REG_EXTENDED | REG_ICASE) != 0)
{
free (relay_config_regex_websocket_allowed_origins);
relay_config_regex_websocket_allowed_origins = NULL;
}
}
}
}
/*
* Callback for changes on option "relay.irc.backlog_tags".
*/
@ -606,6 +646,14 @@ relay_config_init ()
"with SSL)"),
NULL, 0, 0, "%h/ssl/relay.pem", NULL, 0, NULL, NULL,
&relay_config_change_network_ssl_cert_key, NULL, NULL, NULL);
relay_config_network_websocket_allowed_origins = weechat_config_new_option (
relay_config_file, ptr_section,
"websocket_allowed_origins", "string",
N_("regular expression with origins allowed in websockets (case "
"insensitive, use \"(?-i)\" at beginning to make it case sensitive), "
"example: \"^http://(www\\.)?example\\.(com|org)\""),
NULL, 0, 0, "", NULL, 0, NULL, NULL,
&relay_config_change_network_websocket_allowed_origins, NULL, NULL, NULL);
/* section irc */
ptr_section = weechat_config_new_section (relay_config_file, "irc",

View File

@ -51,6 +51,7 @@ extern struct t_config_option *relay_config_irc_backlog_tags;
extern struct t_config_option *relay_config_irc_backlog_time_format;
extern regex_t *relay_config_regex_allowed_ips;
extern regex_t *relay_config_regex_websocket_allowed_origins;
extern struct t_hashtable *relay_config_hashtable_irc_backlog_tags;
extern int relay_config_create_option_port (void *data,

View File

@ -215,46 +215,99 @@ relay_raw_message_add_to_list (time_t date, const char *prefix,
/*
* Adds a new raw message to list.
*
* Returns pointer to new raw message, NULL if error.
*/
struct t_relay_raw_message *
void
relay_raw_message_add (struct t_relay_client *client, int flags,
const char *message)
const char *data, int data_size)
{
char *buf, *buf2, prefix[256], prefix_arrow[16];
char str_hexa[(16 * 3) + 1], str_ascii[(16 * 2) + 1], str_line[256];
const unsigned char *ptr_buf;
const char *hexa = "0123456789ABCDEF";
int pos_buf, pos_buf2, char_size, i;
int pos_buf, pos_buf2, char_size, i, hexa_pos, ascii_pos;
struct t_relay_raw_message *new_raw_message;
buf = weechat_iconv_to_internal (NULL, message);
buf2 = malloc ((strlen (buf) * 3) + 1);
if (buf2)
buf = NULL;
buf2 = NULL;
if (flags & RELAY_RAW_FLAG_BINARY)
{
ptr_buf = (buf) ? (unsigned char *)buf : (unsigned char *)message;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
/* binary message */
buf = malloc ((data_size * 6) + 128 + 1);
if (buf)
{
if (ptr_buf[pos_buf] < 32)
buf[0] = '\0';
hexa_pos = 0;
ascii_pos = 0;
for (i = 0; i < data_size; i++)
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
snprintf (str_hexa + hexa_pos, 4,
"%02X ", (unsigned char)(data[i]));
hexa_pos += 3;
snprintf (str_ascii + ascii_pos, 3, "%c ",
((((unsigned char)data[i]) < 32)
|| (((unsigned char)data[i]) > 127)) ?
'.' : (unsigned char)(data[i]));
ascii_pos += 2;
if (ascii_pos == 32)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
if (buf[0])
strcat (buf, "\n");
snprintf (str_line, sizeof (str_line),
"%-48s %s", str_hexa, str_ascii);
strcat (buf, str_line);
hexa_pos = 0;
ascii_pos = 0;
}
}
if (ascii_pos > 0)
{
if (buf[0])
strcat (buf, "\n");
snprintf (str_line, sizeof (str_line),
"%-48s %s", str_hexa, str_ascii);
strcat (buf, str_line);
}
}
}
else
{
/* text message */
buf = weechat_iconv_to_internal (NULL, data);
buf2 = weechat_string_replace (buf, "\r", "");
if (buf2)
{
free (buf);
buf = buf2;
buf2 = NULL;
}
buf2 = malloc ((strlen (buf) * 3) + 1);
if (buf2)
{
ptr_buf = (buf) ? (unsigned char *)buf : (unsigned char *)data;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
{
if ((ptr_buf[pos_buf] < 32) && (ptr_buf[pos_buf] != '\n'))
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
}
}
}
buf2[pos_buf2] = '\0';
}
buf2[pos_buf2] = '\0';
}
/* build prefix with arrow */
@ -302,35 +355,8 @@ relay_raw_message_add (struct t_relay_client *client, int flags,
new_raw_message = relay_raw_message_add_to_list (time (NULL),
prefix,
(buf2) ? buf2 : ((buf) ? buf : message));
(buf2) ? buf2 : ((buf) ? buf : data));
if (buf)
free (buf);
if (buf2)
free (buf2);
return new_raw_message;
}
/*
* Prints a message on relay raw buffer.
*/
void
relay_raw_print (struct t_relay_client *client, int flags,
const char *format, ...)
{
struct t_relay_raw_message *new_raw_message;
weechat_va_format (format);
if (!vbuffer)
return;
/* auto-open Relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
new_raw_message = relay_raw_message_add (client, flags, vbuffer);
if (new_raw_message)
{
if (relay_raw_buffer)
@ -339,7 +365,25 @@ relay_raw_print (struct t_relay_client *client, int flags,
relay_raw_message_free (new_raw_message);
}
free (vbuffer);
if (buf)
free (buf);
if (buf2)
free (buf2);
}
/*
* Prints a message on relay raw buffer.
*/
void
relay_raw_print (struct t_relay_client *client, int flags,
const char *data, int data_size)
{
/* auto-open Relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
relay_raw_message_add (client, flags, data, data_size);
}
/*

View File

@ -26,6 +26,7 @@
#define RELAY_RAW_FLAG_RECV 1
#define RELAY_RAW_FLAG_SEND 2
#define RELAY_RAW_FLAG_BINARY 4
struct t_relay_raw_message
{
@ -47,7 +48,7 @@ extern struct t_relay_raw_message *relay_raw_message_add_to_list (time_t date,
const char *prefix,
const char *message);
extern void relay_raw_print (struct t_relay_client *client, int flags,
const char *format, ...);
const char *data, int data_size);
extern void relay_raw_message_free_all ();
extern int relay_raw_add_to_infolist (struct t_infolist *infolist,
struct t_relay_raw_message *raw_message);

View File

@ -286,7 +286,7 @@ relay_server_sock_cb (void *data, int fd)
if (relay_config_regex_allowed_ips
&& (regexec (relay_config_regex_allowed_ips, ptr_ip_address, 0, NULL, 0) != 0))
{
if (weechat_relay_plugin->debug >= 2)
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf (NULL,
_("%s%s: IP address \"%s\" not allowed for relay"),

View File

@ -0,0 +1,379 @@
/*
* relay-websocket.c - websocket server functions for relay plugin (RFC 6455)
*
* Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
#include "../weechat-plugin.h"
#include "relay.h"
#include "relay-client.h"
#include "relay-config.h"
/*
* globally unique identifier that is concatenated to HTTP header
* "Sec-WebSocket-Key"
*/
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
/*
* Checks if a message is a HTTP GET with resource "/weechat".
*
* Returns:
* 1: message is a HTTP GET with resource "/weechat"
* 0: message is NOT a HTTP GET with resource "/weechat"
*/
int
relay_websocket_is_http_get_weechat (const char *message)
{
/* the message must start with "GET /weechat" */
if (strncmp (message, "GET /weechat", 12) != 0)
return 0;
/* after "GET /weechat", only a new line or " HTTP" is allowed */
if ((message[12] != '\r') && (message[12] != '\n')
&& (strncmp (message + 12, " HTTP", 5) != 0))
{
return 0;
}
/* valid HTTP GET for resource "/weechat" */
return 1;
}
/*
* Saves a HTTP header in hashtable "http_header" of client.
*/
void
relay_websocket_save_header (struct t_relay_client *client,
const char *message)
{
char *pos, *name;
const char *ptr_value;
/* ignore the "GET" request */
if (strncmp (message, "GET ", 4) == 0)
return;
pos = strchr (message, ':');
/* not a valid header */
if (!pos || (pos == message))
return;
/* get header name */
name = weechat_strndup (message, pos - message);
if (!name)
return;
/* get pointer on header value */
ptr_value = pos + 1;
while (ptr_value[0] == ' ')
{
ptr_value++;
}
/* add header in the hashtable */
weechat_hashtable_set (client->http_headers, name, ptr_value);
free (name);
}
/*
* Checks if a client handshake is valid.
*
* A websocket query looks like:
* GET /weechat HTTP/1.1
* Upgrade: websocket
* Connection: Upgrade
* Host: myhost:5000
* Origin: http://example.org.org
* Pragma: no-cache
* Cache-Control: no-cache
* Sec-WebSocket-Key: fo1J9uHSsrfDP3BkwUylzQ==
* Sec-WebSocket-Version: 13
* Sec-WebSocket-Extensions: x-webkit-deflate-frame
* Cookie: csrftoken=acb65377798f32dc377ebb50316a12b5
*
* Expected HTTP headers with values are:
*
* header | value
* --------------------+----------------
* "Upgrade" | "websocket"
* "Sec-WebSocket-Key" | non-empty value
*
* If option relay.network.websocket_allowed_origins is set, the HTTP header
* "Origin" is checked against this regex. If header "Origin" is not set or does
* not match regex, the handshake is considered as invalid.
*
* Returns:
* 0: handshake is valid
* -1: handshake is invalid (headers missing or with bad value)
* -2: origin is not allowed (option relay.network.websocket_allowed_origins)
*/
int
relay_websocket_client_handshake_valid (struct t_relay_client *client)
{
const char *value;
/* check if we have header "Upgrade" with value "websocket" */
value = weechat_hashtable_get (client->http_headers, "Upgrade");
if (!value)
return -1;
if (strcmp (value, "websocket") != 0)
return -1;
/* check if we have header "Sec-WebSocket-Key" with non-empty value */
value = weechat_hashtable_get (client->http_headers, "Sec-WebSocket-Key");
if (!value || !value[0])
return -1;
if (relay_config_regex_websocket_allowed_origins)
{
value = weechat_hashtable_get (client->http_headers, "Origin");
if (!value || !value[0])
return -2;
if (regexec (relay_config_regex_websocket_allowed_origins, value, 0,
NULL, 0) != 0)
{
return -2;
}
}
/* client handshake is valid */
return 0;
}
/*
* Builds the handshake that will be returned to client, to initialize and use
* the websocket.
*
* Returns a string with content of handshake to send to client, it looks like:
* HTTP/1.1 101 Switching Protocols
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Accept: 73OzoF/IyV9znm7Tsb4EtlEEmn4=
*
* Note: result must be freed after use.
*/
char *
relay_websocket_build_handshake (struct t_relay_client *client)
{
const char *sec_websocket_key;
char *key, sec_websocket_accept[128], handshake[1024];
unsigned char *result;
gcry_md_hd_t hd;
int length;
sec_websocket_key = weechat_hashtable_get (client->http_headers,
"Sec-WebSocket-Key");
if (!sec_websocket_key || !sec_websocket_key[0])
return NULL;
length = strlen (sec_websocket_key) + strlen (WEBSOCKET_GUID) + 1;
key = malloc (length);
if (!key)
return NULL;
/*
* concatenate header "Sec-WebSocket-Key" with the GUID
* (globally unique identifier)
*/
snprintf (key, length, "%s%s", sec_websocket_key, WEBSOCKET_GUID);
/* compute 160-bit SHA1 on the key and encode it with base64 */
gcry_md_open (&hd, GCRY_MD_SHA1, 0);
length = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
gcry_md_write (hd, key, strlen (key));
result = gcry_md_read (hd, GCRY_MD_SHA1);
weechat_string_encode_base64 ((char *)result, length, sec_websocket_accept);
gcry_md_close (hd);
/* build the handshake (it will be sent as-is to client) */
snprintf (handshake, sizeof (handshake),
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
//"Sec-WebSocket-Protocol: chat\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"\r\n",
sec_websocket_accept);
return strdup (handshake);
}
/*
* Sends a HTTP message to client.
*
* Argument "http" is a HTTP code + message, for example:
* "403 Forbidden".
*/
void
relay_websocket_send_http (struct t_relay_client *client,
const char *http)
{
char *message;
int length;
length = 32 + strlen (http) + 1;
message = malloc (length);
if (message)
{
snprintf (message, length, "HTTP/1.1 %s\r\n\r\n", http);
relay_client_send (client, message, strlen (message), NULL);
free (message);
}
}
/*
* Decodes a websocket frame.
*
* Returns:
* 1: frame decoded successfully
* 0: error decoding frame (connection must be closed if it happens)
*/
int
relay_websocket_decode_frame (const unsigned char *buffer,
unsigned long long length,
unsigned char *decoded)
{
unsigned long long i, index, length_frame_size, length_frame;
if (length < 2)
return 0;
/*
* check if frame is masked: client MUST send a masked frame; if frame is
* not masked, we MUST reject it and close the connection (see RFC 6455)
*/
if (!(buffer[1] & 128))
return 0;
/* decode frame */
index = 2;
length_frame_size = 1;
length_frame = buffer[1] & 127;
if ((length_frame == 126) || (length_frame == 127))
{
length_frame_size = (length_frame == 126) ? 2 : 8;
if (length < 1 + length_frame_size)
return 0;
length_frame = 0;
for (i = 0; i < length_frame_size; i++)
{
length_frame += (unsigned long long)buffer[index + i] << ((length_frame_size - i - 1) * 8);
}
index += length_frame_size;
}
if (length < 1 + length_frame_size + 4 + length_frame)
return 0;
/* read masks (4 bytes) */
int masks[4];
for (i = 0; i < 4; i++)
{
masks[i] = (int)((unsigned char)buffer[index + i]);
}
index += 4;
/* decode data using masks */
for (i = 0; i < length_frame; i++)
{
decoded[i] = (int)((unsigned char)buffer[index + i]) ^ masks[i % 4];
}
decoded[length_frame] = '\0';
return 1;
}
/*
* Encodes data in a websocket frame.
*
* Returns websocket frame, NULL if error.
* Argument "length_frame" is set with the length of frame built.
*
* Note: result must be freed after use.
*/
char *
relay_websocket_encode_frame (struct t_relay_client *client,
const char *buffer,
unsigned long long length,
unsigned long long *length_frame)
{
unsigned char *frame;
unsigned long long index;
*length_frame = 0;
frame = malloc (length + 10);
if (!frame)
return NULL;
frame[0] = (client->send_data_type == RELAY_CLIENT_DATA_TEXT) ? 0x81 : 0x82;
if (length <= 125)
{
/* length on one byte */
frame[1] = length;
index = 2;
}
else if ((length >= 126) && (length <= 65535))
{
/* length on 2 bytes */
frame[1] = 126;
frame[2] = (length >> 8) & 0xFF;
frame[3] = length & 0xFF;
index = 4;
}
else
{
/* length on 8 bytes */
frame[1] = 127;
frame[2] = (length >> 56) & 0xFF;
frame[3] = (length >> 48) & 0xFF;
frame[4] = (length >> 40) & 0xFF;
frame[5] = (length >> 32) & 0xFF;
frame[6] = (length >> 24) & 0xFF;
frame[7] = (length >> 16) & 0xFF;
frame[8] = (length >> 8) & 0xFF;
frame[9] = length & 0xFF;
index = 10;
}
/* copy buffer after length */
memcpy (frame + index, buffer, length);
*length_frame = index + length;
return (char *)frame;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_RELAY_WEBSOCKET_H
#define __WEECHAT_RELAY_WEBSOCKET_H 1
extern int relay_websocket_is_http_get_weechat (const char *message);
extern void relay_websocket_save_header (struct t_relay_client *client,
const char *message);
extern int relay_websocket_client_handshake_valid (struct t_relay_client *client);
extern char *relay_websocket_build_handshake (struct t_relay_client *client);
extern void relay_websocket_send_http (struct t_relay_client *client,
const char *http);
extern int relay_websocket_decode_frame (const unsigned char *buffer,
int length,
unsigned char *decoded);
extern char *relay_websocket_encode_frame (struct t_relay_client *client,
const char *buffer,
unsigned long long length,
unsigned long long *length_frame);
#endif /* __WEECHAT_RELAY_WEBSOCKET_H */

View File

@ -958,7 +958,7 @@ relay_weechat_msg_send (struct t_relay_client *client,
struct t_relay_weechat_msg *msg)
{
uint32_t size32;
char compression;
char compression, raw_message[1024];
int rc;
Bytef *dest;
uLongf dest_size;
@ -986,16 +986,17 @@ relay_weechat_msg_send (struct t_relay_client *client,
dest[4] = 1;
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_SEND,
"obj: %d/%d bytes (%d%%, %ldms), id: %s",
(int)dest_size + 5,
msg->data_size,
100 - ((((int)dest_size + 5) * 100) / msg->data_size),
time_diff,
msg->id);
snprintf (raw_message, sizeof (raw_message),
"obj: %d/%d bytes (%d%%, %ldms), id: %s",
(int)dest_size + 5,
msg->data_size,
100 - ((((int)dest_size + 5) * 100) / msg->data_size),
time_diff,
msg->id);
/* send compressed data */
relay_client_send (client, (const char *)dest, dest_size + 5);
relay_client_send (client, (const char *)dest, dest_size + 5,
raw_message);
free (dest);
return;
@ -1012,12 +1013,10 @@ relay_weechat_msg_send (struct t_relay_client *client,
compression = 0;
relay_weechat_msg_set_bytes (msg, 4, &compression, 1);
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_SEND,
"obj: %d bytes", msg->data_size);
/* send uncompressed data */
relay_client_send (client, msg->data, msg->data_size);
snprintf (raw_message, sizeof (raw_message),
"obj: %d bytes", msg->data_size);
relay_client_send (client, msg->data, msg->data_size, raw_message);
}
/*

View File

@ -1053,7 +1053,7 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(quit)
*/
void
relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
relay_weechat_protocol_recv (struct t_relay_client *client, const char *data)
{
char *pos, *id, *command, **argv, **argv_eol;
int i, argc, return_code;
@ -1074,11 +1074,6 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
if (!data || !data[0] || RELAY_CLIENT_HAS_ENDED(client))
return;
/* remove \r at the end of message */
pos = strchr (data, '\r');
if (pos)
pos[0] = '\0';
/* display debug message */
if (weechat_relay_plugin->debug >= 2)
{
@ -1090,9 +1085,6 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
data);
}
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_RECV, "cmd: %s", data);
/* extract id */
id = NULL;
if (data[0] == '(')

View File

@ -96,6 +96,6 @@ extern int relay_weechat_protocol_signal_upgrade_cb (void *data,
extern int relay_weechat_protocol_timer_nicklist_cb (void *data,
int remaining_calls);
extern void relay_weechat_protocol_recv (struct t_relay_client *client,
char *data);
const char *data);
#endif /* __WEECHAT_RELAY_WEECHAT_PROTOCOL_H */

View File

@ -42,8 +42,6 @@
char *relay_weechat_compression_string[] = /* strings for compressions */
{ "off", "gzip" };
char *relay_weechat_partial_message = NULL;
/*
* Searches for a compression.
@ -132,48 +130,7 @@ relay_weechat_hook_timer_nicklist (struct t_relay_client *client)
void
relay_weechat_recv (struct t_relay_client *client, const char *data)
{
char *new_partial, *pos, *tmp, **commands;
int num_commands, i;
if (relay_weechat_partial_message)
{
new_partial = realloc (relay_weechat_partial_message,
strlen (relay_weechat_partial_message) +
strlen (data) + 1);
if (!new_partial)
return;
relay_weechat_partial_message = new_partial;
strcat (relay_weechat_partial_message, data);
}
else
relay_weechat_partial_message = strdup (data);
pos = strrchr (relay_weechat_partial_message, '\n');
if (pos)
{
pos[0] = '\0';
commands = weechat_string_split (relay_weechat_partial_message, "\n",
0, 0, &num_commands);
if (commands)
{
for (i = 0; i < num_commands; i++)
{
relay_weechat_protocol_recv (client, commands[i]);
}
weechat_string_free_split (commands);
}
if (pos[1])
{
tmp = strdup (pos + 1);
free (relay_weechat_partial_message);
relay_weechat_partial_message = tmp;
}
else
{
free (relay_weechat_partial_message);
relay_weechat_partial_message = NULL;
}
}
relay_weechat_protocol_recv (client, data);
}
/*