mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
107 lines
2.8 KiB
C++
107 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
|
|
#include "Common/Net/HTTPServer.h"
|
|
#include "Common/Net/Sinks.h"
|
|
|
|
namespace net {
|
|
|
|
enum class WebSocketClose : uint16_t {
|
|
NORMAL = 1000,
|
|
GOING_AWAY = 1001,
|
|
PROTOCOL_ERROR = 1002,
|
|
UNSUPPORTED_DATA = 1003,
|
|
INVALID_DATA = 1007,
|
|
POLICY_VIOLATION = 1008,
|
|
MESSAGE_TOO_LONG = 1009,
|
|
MISSING_EXTENSION = 1010,
|
|
INTERNAL_ERROR = 1011,
|
|
SERVICE_RESTART = 1012,
|
|
TRY_AGAIN_LATER = 1013,
|
|
BAD_GATEWAY = 1014,
|
|
|
|
NO_STATUS = 1005,
|
|
ABNORMAL = 1006,
|
|
};
|
|
|
|
// RFC 6455
|
|
class WebSocketServer {
|
|
public:
|
|
static WebSocketServer *CreateAsUpgrade(const http::ServerRequest &request, const std::string &protocol = "");
|
|
|
|
void Send(const std::string &str);
|
|
void Send(const std::vector<uint8_t> &payload);
|
|
|
|
// Call with finish = false to start and continue, then finally with finish = true to complete.
|
|
// Note: Fragmented data cannot be interleaved, per protocol.
|
|
void AddFragment(bool finish, const std::string &str);
|
|
void AddFragment(bool finish, const std::vector<uint8_t> &payload);
|
|
|
|
void Ping(const std::vector<uint8_t> &payload = {});
|
|
void Pong(const std::vector<uint8_t> &payload = {});
|
|
void Close(WebSocketClose reason = WebSocketClose::GOING_AWAY);
|
|
|
|
// Note: may interrupt early. Call in a loop.
|
|
bool Process(float timeout = -1.0f);
|
|
|
|
void SetTextHandler(std::function<void(const std::string &)> func) {
|
|
text_ = func;
|
|
}
|
|
void SetBinaryHandler(std::function<void(const std::vector<uint8_t> &)> func) {
|
|
binary_ = func;
|
|
}
|
|
// Doesn't need to send a Pong.
|
|
void SetPingHandler(std::function<void(const std::vector<uint8_t> &)> func) {
|
|
ping_ = func;
|
|
}
|
|
void SetPongHandler(std::function<void(const std::vector<uint8_t> &)> func) {
|
|
pong_ = func;
|
|
}
|
|
|
|
bool IsOpen() {
|
|
return open_;
|
|
}
|
|
WebSocketClose CloseReason() {
|
|
return closeReason_;
|
|
}
|
|
|
|
protected:
|
|
WebSocketServer(size_t fd, InputSink *in, OutputSink *out) : fd_(fd), in_(in), out_(out) {
|
|
}
|
|
|
|
void SendHeader(bool fin, int opcode, size_t sz);
|
|
void SendBytes(const void *p, size_t sz);
|
|
void SendFlush();
|
|
bool ReadFrames();
|
|
bool ReadFrame();
|
|
bool ReadPending();
|
|
bool ReadControlFrame(int opcode, size_t sz);
|
|
|
|
bool open_ = true;
|
|
bool sentClose_ = false;
|
|
int fragmentOpcode_ = -1;
|
|
size_t fd_ = 0;
|
|
InputSink *in_ = nullptr;
|
|
OutputSink *out_ = nullptr;
|
|
WebSocketClose closeReason_ = WebSocketClose::NO_STATUS;
|
|
std::vector<uint8_t> outBuf_;
|
|
size_t lastPressure_ = 0;
|
|
|
|
std::vector<uint8_t> pendingBuf_;
|
|
uint8_t pendingMask_[4]{};
|
|
// Bytes left to read in the frame (in case of a partial frame read.)
|
|
uint64_t pendingLeft_ = 0;
|
|
int pendingOpcode_ = -1;
|
|
// Waiting for a frame with FIN.
|
|
bool pendingFin_ = false;
|
|
|
|
std::function<void(const std::string &)> text_;
|
|
std::function<void(const std::vector<uint8_t> &)> binary_;
|
|
std::function<void(const std::vector<uint8_t> &)> ping_;
|
|
std::function<void(const std::vector<uint8_t> &)> pong_;
|
|
};
|
|
|
|
};
|