finished implementing amqps:// support
This commit is contained in:
parent
67056f6fd9
commit
28b6c903e1
|
|
@ -75,6 +75,7 @@ int main()
|
||||||
|
|
||||||
// make a connection
|
// make a connection
|
||||||
AMQP::Address address("amqp://guest:guest@localhost/");
|
AMQP::Address address("amqp://guest:guest@localhost/");
|
||||||
|
// AMQP::Address address("amqps://guest:guest@localhost/");
|
||||||
AMQP::TcpConnection connection(&handler, address);
|
AMQP::TcpConnection connection(&handler, address);
|
||||||
|
|
||||||
// we need a channel too
|
// we need a channel too
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Implementation of an AMQP connection
|
* Implementation of an AMQP connection
|
||||||
*
|
*
|
||||||
* @copyright 2014 - 2017 Copernica BV
|
* @copyright 2014 - 2018 Copernica BV
|
||||||
*/
|
*/
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "protocolheaderframe.h"
|
#include "protocolheaderframe.h"
|
||||||
|
|
@ -147,7 +147,7 @@ uint64_t ConnectionImpl::parse(const Buffer &buffer)
|
||||||
// data we need for the next frame, otherwise we need at least 7
|
// data we need for the next frame, otherwise we need at least 7
|
||||||
// bytes for processing the header of the next frame
|
// bytes for processing the header of the next frame
|
||||||
_expected = receivedFrame.header() ? (uint32_t)receivedFrame.totalSize() : 7;
|
_expected = receivedFrame.header() ? (uint32_t)receivedFrame.totalSize() : 7;
|
||||||
|
|
||||||
// we're ready for now
|
// we're ready for now
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,21 @@ int SSL_set_fd(SSL *ssl, int fd)
|
||||||
return func(ssl, fd);
|
return func(ssl, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bytes availabe in the ssl struct that have been read
|
||||||
|
* from the socket, but that have not been returned the SSL_read()
|
||||||
|
* @param ssl SSL object
|
||||||
|
* @return int number of bytes
|
||||||
|
*/
|
||||||
|
int SSL_pending(const SSL *ssl)
|
||||||
|
{
|
||||||
|
// create a function
|
||||||
|
static Function<decltype(::SSL_pending)> func("SSL_pending");
|
||||||
|
|
||||||
|
// call the openssl function
|
||||||
|
return func(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free an allocated ssl context
|
* Free an allocated ssl context
|
||||||
* @param ctx
|
* @param ctx
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ int SSL_do_handshake(SSL *ssl);
|
||||||
int SSL_read(SSL *ssl, void *buf, int num);
|
int SSL_read(SSL *ssl, void *buf, int num);
|
||||||
int SSL_write(SSL *ssl, const void *buf, int num);
|
int SSL_write(SSL *ssl, const void *buf, int num);
|
||||||
int SSL_shutdown(SSL *ssl);
|
int SSL_shutdown(SSL *ssl);
|
||||||
|
int SSL_pending(const SSL *ssl);
|
||||||
int SSL_set_fd(SSL *ssl, int fd);
|
int SSL_set_fd(SSL *ssl, int fd);
|
||||||
int SSL_get_shutdown(const SSL *ssl);
|
int SSL_get_shutdown(const SSL *ssl);
|
||||||
int SSL_get_error(const SSL *ssl, int ret);
|
int SSL_get_error(const SSL *ssl, int ret);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ private:
|
||||||
* Are we now busy with sending or receiving?
|
* Are we now busy with sending or receiving?
|
||||||
* @var enum
|
* @var enum
|
||||||
*/
|
*/
|
||||||
enum {
|
enum State {
|
||||||
state_idle,
|
state_idle,
|
||||||
state_sending,
|
state_sending,
|
||||||
state_receiving
|
state_receiving
|
||||||
|
|
@ -131,9 +131,6 @@ private:
|
||||||
// if we still have an outgoing buffer we want to send out data
|
// if we still have an outgoing buffer we want to send out data
|
||||||
if (_out)
|
if (_out)
|
||||||
{
|
{
|
||||||
// we still have a buffer with outgoing data
|
|
||||||
_state = state_sending;
|
|
||||||
|
|
||||||
// let's wait until the socket becomes writable
|
// let's wait until the socket becomes writable
|
||||||
_handler->monitor(_connection, _socket, readable | writable);
|
_handler->monitor(_connection, _socket, readable | writable);
|
||||||
}
|
}
|
||||||
|
|
@ -150,9 +147,6 @@ private:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// outgoing buffer is empty, we're idle again waiting for further input
|
|
||||||
_state = state_idle;
|
|
||||||
|
|
||||||
// let's wait until the socket becomes readable
|
// let's wait until the socket becomes readable
|
||||||
_handler->monitor(_connection, _socket, readable);
|
_handler->monitor(_connection, _socket, readable);
|
||||||
}
|
}
|
||||||
|
|
@ -164,14 +158,18 @@ private:
|
||||||
/**
|
/**
|
||||||
* Method to repeat the previous call\
|
* Method to repeat the previous call\
|
||||||
* @param monitor monitor to check if connection object still exists
|
* @param monitor monitor to check if connection object still exists
|
||||||
|
* @param state the state that we were in
|
||||||
* @param result result of an earlier SSL_get_error call
|
* @param result result of an earlier SSL_get_error call
|
||||||
* @return TcpState*
|
* @return TcpState*
|
||||||
*/
|
*/
|
||||||
TcpState *repeat(const Monitor &monitor, int error)
|
TcpState *repeat(const Monitor &monitor, enum State state, int error)
|
||||||
{
|
{
|
||||||
// check the error
|
// check the error
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
|
// remember state
|
||||||
|
_state = state;
|
||||||
|
|
||||||
// the operation must be repeated when readable
|
// the operation must be repeated when readable
|
||||||
_handler->monitor(_connection, _socket, readable);
|
_handler->monitor(_connection, _socket, readable);
|
||||||
|
|
||||||
|
|
@ -179,6 +177,9 @@ private:
|
||||||
return monitor.valid() ? this : nullptr;
|
return monitor.valid() ? this : nullptr;
|
||||||
|
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
// remember state
|
||||||
|
_state = state;
|
||||||
|
|
||||||
// wait until socket becomes writable again
|
// wait until socket becomes writable again
|
||||||
_handler->monitor(_connection, _socket, readable | writable);
|
_handler->monitor(_connection, _socket, readable | writable);
|
||||||
|
|
||||||
|
|
@ -188,7 +189,7 @@ private:
|
||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
// we're ready for the next instruction from userspace
|
// we're ready for the next instruction from userspace
|
||||||
_state = state_idle;
|
_state = state_idle;
|
||||||
|
|
||||||
// turns out no error occured, an no action has to be rescheduled
|
// turns out no error occured, an no action has to be rescheduled
|
||||||
_handler->monitor(_connection, _socket, _out || _closed ? readable | writable : readable);
|
_handler->monitor(_connection, _socket, _out || _closed ? readable | writable : readable);
|
||||||
|
|
||||||
|
|
@ -224,7 +225,7 @@ private:
|
||||||
|
|
||||||
// parse the buffer
|
// parse the buffer
|
||||||
auto processed = _connection->parse(buffer);
|
auto processed = _connection->parse(buffer);
|
||||||
|
|
||||||
// "this" could be removed by now, check this
|
// "this" could be removed by now, check this
|
||||||
if (!monitor.valid()) return nullptr;
|
if (!monitor.valid()) return nullptr;
|
||||||
|
|
||||||
|
|
@ -235,7 +236,7 @@ private:
|
||||||
_in = std::move(buffer);
|
_in = std::move(buffer);
|
||||||
|
|
||||||
// do we have to reallocate?
|
// do we have to reallocate?
|
||||||
if (!_reallocate) return proceed();
|
if (!_reallocate) return this;
|
||||||
|
|
||||||
// reallocate the buffer
|
// reallocate the buffer
|
||||||
_in.reallocate(_reallocate);
|
_in.reallocate(_reallocate);
|
||||||
|
|
@ -244,8 +245,60 @@ private:
|
||||||
_reallocate = 0;
|
_reallocate = 0;
|
||||||
|
|
||||||
// done
|
// done
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a write operation
|
||||||
|
* @param monitor
|
||||||
|
* @return TcpState*
|
||||||
|
*/
|
||||||
|
TcpState *write(const Monitor &monitor)
|
||||||
|
{
|
||||||
|
// assume default state
|
||||||
|
_state = state_idle;
|
||||||
|
|
||||||
|
// try to send more data from the outgoing buffer
|
||||||
|
auto result = _out.sendto(_ssl);
|
||||||
|
|
||||||
|
// if this is a success, we can proceed with the event loop
|
||||||
|
if (result > 0) return proceed();
|
||||||
|
|
||||||
|
// the operation failed, we may have to repeat our call
|
||||||
|
return repeat(monitor, state_sending, OpenSSL::SSL_get_error(_ssl, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a receive operation
|
||||||
|
* @param monitor
|
||||||
|
* @return TcpState
|
||||||
|
*/
|
||||||
|
TcpState *receive(const Monitor &monitor)
|
||||||
|
{
|
||||||
|
// start a loop
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// assume default state
|
||||||
|
_state = state_idle;
|
||||||
|
|
||||||
|
// read data from ssl into the buffer
|
||||||
|
auto result = _in.receivefrom(_ssl, _connection->expected());
|
||||||
|
|
||||||
|
// if this is a failure, we are going to repeat the operation
|
||||||
|
if (result <= 0) return repeat(monitor, state_receiving, OpenSSL::SSL_get_error(_ssl, result));
|
||||||
|
|
||||||
|
// go process the received data
|
||||||
|
auto *nextstate = parse(monitor, result);
|
||||||
|
|
||||||
|
// leap out if we moved to a different state
|
||||||
|
if (nextstate != this) return nextstate;
|
||||||
|
}
|
||||||
|
while (OpenSSL::SSL_pending(_ssl) > 0);
|
||||||
|
|
||||||
|
// go to the next state
|
||||||
return proceed();
|
return proceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -295,29 +348,22 @@ public:
|
||||||
// the socket must be the one this connection writes to
|
// the socket must be the one this connection writes to
|
||||||
if (fd != _socket) return this;
|
if (fd != _socket) return this;
|
||||||
|
|
||||||
// are we busy with sending or receiving data?
|
// if we were busy with a write operation, we have to repeat that
|
||||||
if (_state == state_sending)
|
if (_state == state_sending) return write(monitor);
|
||||||
{
|
|
||||||
// try to send more data from the outgoing buffer
|
// same is true for read operations, they should also be repeated
|
||||||
auto result = _out.sendto(_ssl);
|
if (_state == state_receiving) return receive(monitor);
|
||||||
|
|
||||||
// if this is a success, we can proceed with the event loop
|
// if the socket is readable, we are going to receive data
|
||||||
if (result > 0) return proceed();
|
if (flags & readable) return receive(monitor);
|
||||||
|
|
||||||
// the operation failed, we may have to repeat our call
|
// socket is not readable (so it must be writable), do we have data to write?
|
||||||
else return repeat(monitor, OpenSSL::SSL_get_error(_ssl, result));
|
if (_out) return write(monitor);
|
||||||
}
|
|
||||||
else
|
// the only scenario in which we can end up here is the socket should be
|
||||||
{
|
// closed, but instead of moving to the shutdown-state right, we call proceed()
|
||||||
// read data from ssl into the buffer
|
// because that function is a little more careful
|
||||||
auto result = _in.receivefrom(_ssl, _connection->expected());
|
return proceed();
|
||||||
|
|
||||||
// if this is a success, we may have to update the monitor
|
|
||||||
if (result > 0) return parse(monitor, result);
|
|
||||||
|
|
||||||
// the operation failed, we may have to repeat our call
|
|
||||||
else return repeat(monitor, OpenSSL::SSL_get_error(_ssl, result));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -336,14 +382,17 @@ public:
|
||||||
// keep looping while we have an outgoing buffer
|
// keep looping while we have an outgoing buffer
|
||||||
while (_out)
|
while (_out)
|
||||||
{
|
{
|
||||||
|
// move to the idle-state
|
||||||
|
_state = state_idle;
|
||||||
|
|
||||||
// try to send more data from the outgoing buffer
|
// try to send more data from the outgoing buffer
|
||||||
auto result = _out.sendto(_ssl);
|
auto result = _out.sendto(_ssl);
|
||||||
|
|
||||||
// was this a success?
|
// was this a success?
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
// parse the buffer
|
// proceed to the next state
|
||||||
auto *nextstate = parse(monitor, result);
|
auto *nextstate = proceed();
|
||||||
|
|
||||||
// leap out if we move to a different state
|
// leap out if we move to a different state
|
||||||
if (nextstate != this) return nextstate;
|
if (nextstate != this) return nextstate;
|
||||||
|
|
@ -353,8 +402,8 @@ public:
|
||||||
// error was returned, so we must investigate what is going on
|
// error was returned, so we must investigate what is going on
|
||||||
auto error = OpenSSL::SSL_get_error(_ssl, result);
|
auto error = OpenSSL::SSL_get_error(_ssl, result);
|
||||||
|
|
||||||
// get the next state given this error
|
// get the next state given the error
|
||||||
auto *nextstate = repeat(monitor, error);
|
auto *nextstate = repeat(monitor, state_sending, error);
|
||||||
|
|
||||||
// leap out if we move to a different state
|
// leap out if we move to a different state
|
||||||
if (nextstate != this) return nextstate;
|
if (nextstate != this) return nextstate;
|
||||||
|
|
@ -385,9 +434,6 @@ public:
|
||||||
// for that operation to complete before we can move on
|
// for that operation to complete before we can move on
|
||||||
if (_state != state_idle) return;
|
if (_state != state_idle) return;
|
||||||
|
|
||||||
// object is now busy sending
|
|
||||||
_state = state_sending;
|
|
||||||
|
|
||||||
// let's wait until the socket becomes writable
|
// let's wait until the socket becomes writable
|
||||||
_handler->monitor(_connection, _socket, readable | writable);
|
_handler->monitor(_connection, _socket, readable | writable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,9 @@ public:
|
||||||
// close the connection
|
// close the connection
|
||||||
auto result = OpenSSL::SSL_shutdown(_ssl);
|
auto result = OpenSSL::SSL_shutdown(_ssl);
|
||||||
|
|
||||||
|
// on result==0 we need an additional call
|
||||||
|
while (result == 0) result = OpenSSL::SSL_shutdown(_ssl);
|
||||||
|
|
||||||
// if this is a success, we can proceed with the event loop
|
// if this is a success, we can proceed with the event loop
|
||||||
if (result > 0) return proceed(monitor);
|
if (result > 0) return proceed(monitor);
|
||||||
|
|
||||||
|
|
@ -212,6 +215,9 @@ public:
|
||||||
{
|
{
|
||||||
// close the connection
|
// close the connection
|
||||||
auto result = OpenSSL::SSL_shutdown(_ssl);
|
auto result = OpenSSL::SSL_shutdown(_ssl);
|
||||||
|
|
||||||
|
// on result==0 we need an additional call
|
||||||
|
while (result == 0) result = OpenSSL::SSL_shutdown(_ssl);
|
||||||
|
|
||||||
// if this is a success, we can proceed with the event loop
|
// if this is a success, we can proceed with the event loop
|
||||||
if (result > 0) return proceed(monitor);
|
if (result > 0) return proceed(monitor);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue