forked from halfgaar/FlashMQ
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iowrapper.h
156 lines (126 loc) · 3.9 KB
/
iowrapper.h
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
This file is part of FlashMQ (https://www.flashmq.org)
Copyright (C) 2021-2023 Wiebe Cazemier
FlashMQ is free software: you can redistribute it and/or modify
it under the terms of The Open Software License 3.0 (OSL-3.0).
See LICENSE for license details.
*/
#ifndef IOWRAPPER_H
#define IOWRAPPER_H
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <exception>
#include "forward_declarations.h"
#include "logger.h"
#include "haproxy.h"
#include "cirbuf.h"
#include "x509manager.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,
WantRead = 5
};
enum class WebsocketOpcode
{
Continuation = 0x00,
Text = 0x1,
Binary = 0x2,
Close = 0x8,
Ping = 0x9,
Pong = 0xA,
Unknown = 0xF
};
/**
* @brief The IncompleteSslWrite struct facilities the SSL retry
*
* 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"
*
* Note that we use SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER.
*/
struct IncompleteSslWrite
{
bool valid = false;
size_t nbytes = 0;
IncompleteSslWrite() = default;
IncompleteSslWrite(size_t nbytes);
bool hasPendingWrite() const;
void reset();
};
struct IncompleteWebsocketRead
{
size_t frame_bytes_left = 0;
char maskingKey[4];
unsigned int maskingKeyI = 0;
WebsocketOpcode opcode;
void reset();
bool sillWorkingOnFrame() const;
char getNextMaskingByte();
IncompleteWebsocketRead();
};
enum class WebsocketState
{
NotUpgraded,
Upgrading,
Upgraded
};
/**
* @brief provides a unified wrapper for SSL and websockets to read() and write().
*
*
*/
class IoWrapper
{
Client *parentClient;
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;
bool _needsHaProxyParsing = false;
Logger *logger = Logger::getInstance();
ssize_t websocketBytesToReadBuffer(void *buf, const size_t nbytes, IoWrapResult *error);
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, const size_t nbytes, WebsocketOpcode opcode = WebsocketOpcode::Binary);
void startOrContinueSslConnect();
void startOrContinueSslAccept();
public:
IoWrapper(SSL *ssl, bool websocket, const size_t initialBufferSize, Client *parent);
~IoWrapper();
void startOrContinueSslHandshake();
bool getSslReadWantsWrite() const;
bool getSslWriteWantsRead() const;
bool isSslAccepted() const;
bool isSsl() const;
void setSslVerify(int mode, const std::string &hostname);
bool hasPendingWrite() const;
bool hasProcessedBufferedBytesToRead() const;
bool isWebsocket() const;
WebsocketState getWebsocketState() const;
X509Manager getPeerCertificate() const;
bool needsHaProxyParsing() const;
HaProxyConnectionType readHaProxyData(int fd, struct sockaddr *addr);
void setHaProxy(bool val);
#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);
void resetBuffersIfEligible();
};
#endif // IOWRAPPER_H