initial commit
This commit is contained in:
79
third_party/libhv/examples/kcptun/smux/smux.cpp
vendored
Executable file
79
third_party/libhv/examples/kcptun/smux/smux.cpp
vendored
Executable file
@@ -0,0 +1,79 @@
|
||||
#include "smux.h"
|
||||
|
||||
#define SMUX_USE_LITTLE_ENDIAN 1
|
||||
|
||||
int smux_frame_pack(const smux_frame_t* frame, void* buf, int len) {
|
||||
if (!frame || !buf || !len) return -1;
|
||||
const smux_head_t* head = &(frame->head);
|
||||
unsigned int packlen = smux_package_length(head);
|
||||
// Check is buffer enough
|
||||
if (len < packlen) {
|
||||
return -2;
|
||||
}
|
||||
unsigned char* p = (unsigned char*)buf;
|
||||
*p++ = head->version;
|
||||
*p++ = head->cmd;
|
||||
#if SMUX_USE_LITTLE_ENDIAN
|
||||
*p++ = head->length;
|
||||
*p++ = (head->length >> 8) & 0xFF;
|
||||
#else
|
||||
// hton length
|
||||
*p++ = (head->length >> 8) & 0xFF;
|
||||
*p++ = head->length;
|
||||
#endif
|
||||
|
||||
uint32_t sid = head->sid;
|
||||
#if SMUX_USE_LITTLE_ENDIAN
|
||||
*p++ = sid & 0xFF;
|
||||
*p++ = (sid >> 8) & 0xFF;
|
||||
*p++ = (sid >> 16) & 0xFF;
|
||||
*p++ = (sid >> 24) & 0xFF;
|
||||
#else
|
||||
// hton sid
|
||||
*p++ = (sid >> 24) & 0xFF;
|
||||
*p++ = (sid >> 16) & 0xFF;
|
||||
*p++ = (sid >> 8) & 0xFF;
|
||||
*p++ = sid & 0xFF;
|
||||
#endif
|
||||
// memcpy data
|
||||
if (frame->data && head->length) {
|
||||
memcpy(p, frame->data, frame->head.length);
|
||||
}
|
||||
return packlen;
|
||||
}
|
||||
|
||||
int smux_frame_unpack(smux_frame_t* frame, const void* buf, int len) {
|
||||
if (!frame || !buf || !len) return -1;
|
||||
if (len < SMUX_HEAD_LENGTH) return -2;
|
||||
smux_head_t* head = &(frame->head);
|
||||
unsigned char* p = (unsigned char*)buf;
|
||||
head->version = *p++;
|
||||
head->cmd = *p++;
|
||||
#if SMUX_USE_LITTLE_ENDIAN
|
||||
head->length = *p++;
|
||||
head->length |= ((uint16_t)*p++) << 8;
|
||||
#else
|
||||
// ntoh length
|
||||
head->length = ((uint16_t)*p++) << 8;
|
||||
head->length |= *p++;
|
||||
#endif
|
||||
|
||||
#if SMUX_USE_LITTLE_ENDIAN
|
||||
head->sid = *p++;
|
||||
head->sid |= ((uint32_t)*p++) << 8;
|
||||
head->sid |= ((uint32_t)*p++) << 16;
|
||||
head->sid |= ((uint32_t)*p++) << 24;
|
||||
#else
|
||||
// ntoh sid
|
||||
head->sid = ((uint32_t)*p++) << 24;
|
||||
head->sid |= ((uint32_t)*p++) << 16;
|
||||
head->sid |= ((uint32_t)*p++) << 8;
|
||||
head->sid |= *p++;
|
||||
#endif
|
||||
// NOTE: just shadow copy
|
||||
if (len > SMUX_HEAD_LENGTH) {
|
||||
frame->data = (const char*)buf + SMUX_HEAD_LENGTH;
|
||||
}
|
||||
unsigned int packlen = smux_package_length(head);
|
||||
return MIN(len, packlen);
|
||||
}
|
||||
138
third_party/libhv/examples/kcptun/smux/smux.h
vendored
Executable file
138
third_party/libhv/examples/kcptun/smux/smux.h
vendored
Executable file
@@ -0,0 +1,138 @@
|
||||
#ifndef HV_SMUX_H_
|
||||
#define HV_SMUX_H_
|
||||
|
||||
/*
|
||||
* smux: Simple MUltipleXing used by kcptun
|
||||
* @see: https://github.com/xtaci/smux
|
||||
*
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "hplatform.h"
|
||||
#include "hbase.h"
|
||||
#include "hbuf.h"
|
||||
#include "hloop.h"
|
||||
|
||||
typedef enum {
|
||||
// v1
|
||||
SMUX_CMD_SYN = 0, // stream open
|
||||
SMUX_CMD_FIN = 1, // stream close
|
||||
SMUX_CMD_PSH = 2, // data push
|
||||
SMUX_CMD_NOP = 3, // no operation
|
||||
// v2
|
||||
SMUX_CMD_UPD = 4, // update
|
||||
} smux_cmd_e;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t cmd;
|
||||
uint16_t length;
|
||||
uint32_t sid;
|
||||
} smux_head_t;
|
||||
|
||||
#define SMUX_HEAD_LENGTH 8
|
||||
|
||||
typedef struct {
|
||||
smux_head_t head;
|
||||
const char* data;
|
||||
} smux_frame_t;
|
||||
|
||||
static inline unsigned int smux_package_length(const smux_head_t* head) {
|
||||
return SMUX_HEAD_LENGTH + head->length;
|
||||
}
|
||||
|
||||
static inline void smux_head_init(smux_head_t* head) {
|
||||
head->version = 1;
|
||||
head->cmd = (uint8_t)SMUX_CMD_PSH;
|
||||
head->length = 0;
|
||||
head->sid = 0;
|
||||
}
|
||||
|
||||
static inline void smux_frame_init(smux_frame_t* frame) {
|
||||
smux_head_init(&frame->head);
|
||||
frame->data = NULL;
|
||||
}
|
||||
|
||||
// @retval >0 package_length, <0 error
|
||||
int smux_frame_pack(const smux_frame_t* frame, void* buf, int len);
|
||||
// @retval >0 package_length, <0 error
|
||||
int smux_frame_unpack(smux_frame_t* frame, const void* buf, int len);
|
||||
|
||||
typedef struct smux_config_s {
|
||||
int version;
|
||||
int keepalive_interval;
|
||||
int keepalive_timeout;
|
||||
int max_frame_size;
|
||||
|
||||
smux_config_s() {
|
||||
version = 1;
|
||||
keepalive_interval = 10000;
|
||||
keepalive_timeout = 30000;
|
||||
max_frame_size = 1024;
|
||||
}
|
||||
} smux_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t stream_id;
|
||||
smux_frame_t frame;
|
||||
hbuf_t rbuf;
|
||||
hbuf_t wbuf;
|
||||
hio_t* io;
|
||||
htimer_t* timer;
|
||||
} smux_stream_t;
|
||||
|
||||
// @retval >0 package_length, <0 error, data => wbuf
|
||||
static inline int smux_stream_output(smux_stream_t* stream, smux_frame_t* frame) {
|
||||
return smux_frame_pack(frame, stream->wbuf.base, stream->wbuf.len);
|
||||
}
|
||||
|
||||
static inline int smux_stream_output(smux_stream_t* stream, smux_cmd_e cmd) {
|
||||
smux_frame_t frame;
|
||||
smux_frame_init(&frame);
|
||||
frame.head.sid = stream->stream_id;
|
||||
frame.head.cmd = (uint8_t)cmd;
|
||||
return smux_frame_pack(&frame, stream->wbuf.base, stream->wbuf.len);
|
||||
}
|
||||
|
||||
// @retval >0 package_length, <0 error, data => frame
|
||||
static inline int smux_stream_input(smux_stream_t* stream, const void* buf, int len) {
|
||||
return smux_frame_unpack(&stream->frame, buf, len);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t next_stream_id;
|
||||
// stream_id => smux_stream_t
|
||||
std::map<uint32_t, smux_stream_t*> streams;
|
||||
} smux_session_t;
|
||||
|
||||
static inline smux_stream_t* smux_session_open_stream(smux_session_t* session, uint32_t stream_id = 0, hio_t* io = NULL) {
|
||||
smux_stream_t* stream = NULL;
|
||||
HV_ALLOC_SIZEOF(stream);
|
||||
if (stream_id == 0) {
|
||||
session->next_stream_id += 2;
|
||||
stream_id = session->next_stream_id;
|
||||
}
|
||||
stream->stream_id = stream_id;
|
||||
session->streams[stream_id] = stream;
|
||||
stream->io = io;
|
||||
return stream;
|
||||
}
|
||||
|
||||
static inline smux_stream_t* smux_session_get_stream(smux_session_t* session, uint32_t stream_id) {
|
||||
auto iter = session->streams.find(stream_id);
|
||||
if (iter != session->streams.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void smux_session_close_stream(smux_session_t* session, uint32_t stream_id) {
|
||||
auto iter = session->streams.find(stream_id);
|
||||
if (iter != session->streams.end()) {
|
||||
HV_FREE(iter->second);
|
||||
session->streams.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HV_SMUX_H_
|
||||
Reference in New Issue
Block a user