Как использовать Haxe SSL Socket? - PullRequest
6 голосов
/ 02 июня 2019

Я пытаюсь настроить сервер https, но не могу найти пример того, как использовать Haxe sys.ssl.Socket, и документация мне не совсем понятна.

Пока что я получил следующий код, который выдает «Нарушение прав доступа».

var _aSocketDistant = new List<Socket>();

var _oSocketMaster =  new SocketSSL();
_oSocketMaster.setCA(Certificate.loadFile('ssl/homeplanet.pem'));
_oSocketMaster.setCertificate( 
    Certificate.loadFile('ssl/homeplanet.pem'), 
    Key.loadFile('ssl/homeplanet.key', false, 'homeplanet') 
);
_oSocketMaster.setHostname('localhost');

_oSocketMaster.bind( new Host( 'localhost' ), 8000);
_oSocketMaster.setBlocking( false );
_oSocketMaster.listen( 9999 );

while(true) {

    // Accepting socket
    var oSocketDistant = _oSocketMaster.accept();
    if ( oSocketDistant != null ) {
        trace( 'opening : ' + oSocketDistant.peer() );
        oSocketDistant.setBlocking( false );
        _aSocketDistant.add( oSocketDistant );
    }

    // Trying to read from each socket 
    for ( oSocketDistant in _aSocketDistant ) {
        try {
            Sys.print( oSocketDistant.input.readString(1) );
        } catch ( e :Dynamic ) {
            if ( e != Error.Blocked )
                throw e;
        }
    }
}

Это дает мне следующий результат:

Uncaught exception: Access violation
Called from sys.ssl.Socket.accept(D:\HaxeToolkit4\haxe\std/hl/_std/sys/ssl/Socket.hx:203)
Called from $Main.main(Main.hx:39)
Called from fun$517(?:1)

Файлы ключей / сертификатов были сгенерированы с использованием этого руководства .

Правильно ли я использую розетку?

1 Ответ

7 голосов
/ 20 июня 2019

Хорошо, я решил, что хочу сам протестировать сокеты Haxe SSL.Из-за большого количества предостережений это, вероятно, не будет решением вашей проблемы, но, возможно, некоторые из них помогут.И начинать с «что-то, что работает» лучше, чем ничего!

Во-первых, я нахожусь на Linux.Я обнаружил, что сокеты (и потоки) могут демонстрировать другое поведение и проблемы в Windows, чем в Linux / OSX.

Во-вторых, я сначала пробую это с допустимым именем хоста.Я никогда не использовал SSL на localhost и хотел удалить все неизвестные.Так что у меня есть действующий сертификат / ключ, который я использую.В приведенном ниже коде это называется foo.example.com.Вы можете получить бесплатный сертификат для домена, которым вы владеете, по адресу letsencrypt.org .

В-третьих, я столкнулся с проблемой в библиотеке Haxe std.Чтобы обойти это, я просто изменил строку 17 в haxe/std/cpp/_std/sys/ssl/Key.hx:

var str = data.toString(); // cpp.Lib.stringReference(data);

В-четвертых, я понятия не имею о проблеме «нарушения доступа».Вероятно, это будет зависеть от Windows.Я бы догадался, возможно, проблема с разрешениями или брандмауэром, но, прибегая к помощи «Нарушение доступа к сокету Windows», я вижу много случайных обсуждений.

Наконец, я не уверен, что ваши неблокирующие сокеты с while-цикламихорошая идея.Может быть, это можно сделать и так ... но мне всегда больше везло с блокировкой сокетов и потоков (опять же, потоки могут работать лучше в 'nix, чем в Windows.)

Примечание: если выработайте с неблокирующими сокетами, иногда вам приходится ловить / игнорировать как haxe.io.Error.Blocked, так и haxe.io.Error.Custom(Blocked).Раздражение, но мех.Используйте это:

  try {
    Sys.print( oSocketDistant.input.readString(1) );
  } catch ( e:haxe.io.Error ) {
    switch e {
      case haxe.io.Error.Blocked: // no problem
      case haxe.io.Error.Custom(c) if (c==haxe.io.Error.Blocked): // no problem
      default: throw e;
    }
  } catch ( e:haxe.io.Eof ) {
    trace('Got Eof');
  }

Более эффективно использовать потоки с блокирующими сокетами.Таким образом, нить просто спит, пока сокет ее не разбудит.Это именно то, что вам нужно, чтобы процессор не вращался во время цикла, постоянно проверяя наличие разблокированных сокетов.

Итак, я немного изменил ваш код.Мой пример использует основной поток для приема соединений, а затем передает сокет потоку чтения.Поток читателя печатает все полученное (как ваш пример), а затем завершается на Eof.

import sys.net.Host;
import sys.net.Socket;
import sys.ssl.Socket as SocketSSL;
import sys.ssl.Certificate;
import sys.ssl.Key;

import cpp.vm.Mutex;
import cpp.vm.Thread;

class Main
{
  static var _mutex:Mutex = new Mutex();

  public static function main()
  {
    var _oSocketMaster =  new SocketSSL();
    var cert = Certificate.loadFile('my_chain.pem');
    _oSocketMaster.setCA(cert);
    _oSocketMaster.setCertificate(cert, 
                                  Key.loadFile('my_key.key'));
    _oSocketMaster.setHostname('foo.example.com');

    // e.g. for an application like an HTTPs server, the client
    // doesn't need to provide a certificate. Otherwise we get:
    // Error: SSL - No client certification received from the client, but required by the authentication mode
    _oSocketMaster.verifyCert = false;

    // Binding 0.0.0.0 means, listen on "any / all IP addresses on this host"
    _oSocketMaster.bind( new Host( '0.0.0.0' ), 8000);
    _oSocketMaster.listen( 9999 );

    while(true) {

      // Accepting socket
      trace('waiting to accept...');
      var oSocketDistant:SocketSSL = _oSocketMaster.accept();
      if ( oSocketDistant != null ) {
        trace( 'got connection from : ' + oSocketDistant.peer() );
        oSocketDistant.handshake(); // This may not be necessary, if !verifyCert

        // Spawn a reader thread for this connection:
        var thrd = Thread.create(reader);
        trace('sending socket...');
        thrd.sendMessage(oSocketDistant);
        trace('ok...');
      }

    }
  }

  static function reader()
  {
    var oSocketDistant:sys.net.Socket = cast Thread.readMessage(true);
    trace('new reader thread...');

    while(true) {

      try {
        Sys.print( oSocketDistant.input.readString(1) );
      } catch ( e:haxe.io.Eof ) {
        trace('Eof, reader thread exiting...');
        return;
      } catch ( e:Dynamic ) {
        trace('Uncaught: ${ e }'); // throw e;
      }
    }
  }
}

Итак, давайте посмотрим на это в действии!

Я скомпилировал и запустил вышеуказанный серверв одном терминале:

> haxe -main Main -debug -cpp out && ./out/Main-debug
...compiling info removed...
Main.hx:37: waiting to accept...

А потом я подключаюсь с другого терминала к клиенту, это утилита командной строки для тестирования ssl-соединений:

> openssl s_client -connect foo.example.com:8000
...lots of info about the cert...
SSL handshake has read 3374 bytes and written 370 bytes
Verification: OK
---

И она там висит, ждет васнабрать ввод.На стороне сервера мы видим:

Main.hx:38: got connection from : { host => Host, port => 57394 }
Main.hx:43: sending socket...
Main.hx:45: ok...
Main.hx:35: waiting to accept...
Main.hx:54: new reader thread...

Мы можем открыть много клиентов в отдельных терминалах, каждый из которых получает свой собственный поток чтения.Ввод сообщений в клиентские терминалы отображается в серверном терминале, поэтому потоки считывателя работают.

На клиенте CTRL + C для выхода, а на сервере мы видим:

Main.hx:61: Eof, reader thread exiting...

Все работает как положено!

...