iowrapper.h
3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifndef IOWRAPPER_H
#define IOWRAPPER_H
#include "unistd.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include <exception>
#include "forward_declarations.h"
#include "types.h"
#include "utils.h"
#include "logger.h"
#include "exceptions.h"
#define WEBSOCKET_MIN_HEADER_BYTES_NEEDED 2
#define WEBSOCKET_MAX_SENDING_HEADER_SIZE 10
#define OPENSSL_ERROR_STRING_SIZE 256 // OpenSSL requires at least 256.
#define OPENSSL_WRONG_VERSION_NUMBER 336130315
enum class IoWrapResult
{
Success = 0,
Interrupted = 1,
Wouldblock = 2,
Disconnected = 3,
Error = 4
};
enum class WebsocketOpcode
{
Continuation = 0x00,
Text = 0x1,
Binary = 0x2,
Close = 0x8,
Ping = 0x9,
Pong = 0xA,
Unknown = 0xF
};
/*
* OpenSSL doc: "When a write function call has to be repeated because SSL_get_error(3) returned
* SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be repeated with the same arguments"
*/
struct IncompleteSslWrite
{
const void *buf = nullptr;
size_t nbytes = 0;
IncompleteSslWrite() = default;
IncompleteSslWrite(const void *buf, size_t nbytes);
bool hasPendingWrite() const;
void reset();
};
struct IncompleteWebsocketRead
{
size_t frame_bytes_left = 0;
char maskingKey[4];
int maskingKeyI = 0;
WebsocketOpcode opcode;
void reset();
bool sillWorkingOnFrame() const;
char getNextMaskingByte();
};
enum class WebsocketState
{
NotUpgraded,
Upgrading,
Upgraded
};
/**
* @brief provides a unified wrapper for SSL and websockets to read() and write().
*
*
*/
class IoWrapper
{
Client *parentClient;
const size_t initialBufferSize;
SSL *ssl = nullptr;
bool sslAccepted = false;
IncompleteSslWrite incompleteSslWrite;
bool sslReadWantsWrite = false;
bool sslWriteWantsRead = false;
bool websocket;
WebsocketState websocketState = WebsocketState::NotUpgraded;
CirBuf websocketPendingBytes;
IncompleteWebsocketRead incompleteWebsocketRead;
CirBuf websocketWriteRemainder;
Logger *logger = Logger::getInstance();
ssize_t websocketBytesToReadBuffer(void *buf, const size_t nbytes);
ssize_t readOrSslRead(int fd, void *buf, size_t nbytes, IoWrapResult *error);
ssize_t writeOrSslWrite(int fd, const void *buf, size_t nbytes, IoWrapResult *error);
ssize_t writeAsMuchOfBufAsWebsocketFrame(const void *buf, size_t nbytes, WebsocketOpcode opcode = WebsocketOpcode::Binary);
public:
IoWrapper(SSL *ssl, bool websocket, const size_t initialBufferSize, Client *parent);
~IoWrapper();
void startOrContinueSslAccept();
bool getSslReadWantsWrite() const;
bool getSslWriteWantsRead() const;
bool isSslAccepted() const;
bool isSsl() const;
bool hasPendingWrite() const;
bool isWebsocket() const;
WebsocketState getWebsocketState() const;
#ifndef NDEBUG
void setFakeUpgraded();
#endif
ssize_t readWebsocketAndOrSsl(int fd, void *buf, size_t nbytes, IoWrapResult *error);
ssize_t writeWebsocketAndOrSsl(int fd, const void *buf, size_t nbytes, IoWrapResult *error);
};
#endif // IOWRAPPER_H