代码重构
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
# gquic
|
# gquic
|
||||||
|
|
||||||
gquic protocol parse plugin
|
gquic protocol parse plugin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Chromium currently support two kinds of QUIC versions, GoogleQUIC and IETF QUIC.
|
||||||
|
|
||||||
|
https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/core/quic_versions.h
|
||||||
93
src/gquic.h
93
src/gquic.h
@@ -8,24 +8,6 @@
|
|||||||
#ifndef SRC_GQUIC_H_
|
#ifndef SRC_GQUIC_H_
|
||||||
#define SRC_GQUIC_H_
|
#define SRC_GQUIC_H_
|
||||||
|
|
||||||
enum GQUIC_VERSION
|
|
||||||
{
|
|
||||||
GQUIC_UNKNOWN=0,
|
|
||||||
GQUIC_OTHERS,
|
|
||||||
GQUIC_Q046
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#include <MESA/stream.h>
|
|
||||||
#define MAX_EXTENSION_NUM 128
|
|
||||||
#define MAX_TAG_VALUE_LEN 257
|
|
||||||
#define SERVER_NAME_LEN 128
|
|
||||||
//add in 20191207
|
|
||||||
#define USER_AGENT_LEN 512
|
|
||||||
#define RANDOM_LEN 32
|
|
||||||
#define QUIC_VERSION_LEN 4
|
|
||||||
|
|
||||||
|
|
||||||
#define QUIC_INTEREST_KEY (1<<QUIC_INTEREST_KEY_MASK)
|
#define QUIC_INTEREST_KEY (1<<QUIC_INTEREST_KEY_MASK)
|
||||||
#define QUIC_CLIENT_HELLO (1<<QUIC_CLIENT_HELLO_MASK)
|
#define QUIC_CLIENT_HELLO (1<<QUIC_CLIENT_HELLO_MASK)
|
||||||
#define QUIC_SERVER_HELLO (1<<QUIC_SERVER_HELLO_MASK)
|
#define QUIC_SERVER_HELLO (1<<QUIC_SERVER_HELLO_MASK)
|
||||||
@@ -47,50 +29,55 @@ enum quic_interested_region {
|
|||||||
QUIC_VERSION_MASK
|
QUIC_VERSION_MASK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _quic_tlv
|
||||||
typedef struct quic_tlv{
|
{
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
void *ptr_value;
|
void *value;
|
||||||
}quic_tlv_t;
|
}quic_tlv_t;
|
||||||
|
|
||||||
struct quic_business_info
|
#define MAX_CONNECT_ID_LEN 18
|
||||||
|
|
||||||
|
struct _quic_public_header
|
||||||
{
|
{
|
||||||
void* param;
|
unsigned char public_flags;
|
||||||
uint8_t return_value;
|
unsigned int quic_version;
|
||||||
|
unsigned int server_CID_len;
|
||||||
|
unsigned int client_CID_len;
|
||||||
|
unsigned long long packet_number;
|
||||||
|
unsigned char server_CID[MAX_CONNECT_ID_LEN]; ////use first 8 bytes if GQUIC version 1~43
|
||||||
|
unsigned char client_CID[MAX_CONNECT_ID_LEN]; // no used if GQUIC version 1~43
|
||||||
};
|
};
|
||||||
|
struct _gquic_frame_header
|
||||||
struct quic_client_hello {
|
{
|
||||||
int server_name_len;
|
unsigned char frame_type;
|
||||||
char server_name[SERVER_NAME_LEN];
|
unsigned char fin_state;
|
||||||
int user_agent_len;
|
unsigned short data_len;
|
||||||
char user_agent[USER_AGENT_LEN];
|
unsigned int stream_id;
|
||||||
uint16_t ext_tag_num; //number of extensions or tags
|
unsigned long long offset;
|
||||||
quic_tlv_t** ext_tags; //extensions or tags
|
|
||||||
};
|
|
||||||
|
|
||||||
struct quic_server_hello {
|
|
||||||
/*include random,session,ciphersuit,compress_method...*/
|
|
||||||
uint16_t ext_tag_num; //number of extensions or tags
|
|
||||||
quic_tlv_t** ext_tags; //extensions or tags
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct quic_stream {
|
struct _quic_stream
|
||||||
unsigned char link_state;
|
{
|
||||||
uint8_t version_cfm;
|
unsigned char count;
|
||||||
uint32_t version;
|
unsigned char sni_idx;
|
||||||
uint8_t fin_flag;
|
unsigned char ua_idx;
|
||||||
uint8_t is_quic_stream;
|
unsigned char ver_idx;
|
||||||
uint64_t gquic_cID;
|
unsigned int ext_tag_num; //number of extensions or tags
|
||||||
struct quic_client_hello st_client_hello;
|
quic_tlv_t *ext_tags; //extensions or tags
|
||||||
struct quic_server_hello st_server_hello;
|
|
||||||
struct quic_tlv cert_chain;
|
|
||||||
struct quic_tlv cached_cert;
|
|
||||||
struct quic_tlv common_cert;
|
|
||||||
struct quic_business_info* business;
|
|
||||||
enum quic_interested_region output_region_mask;
|
|
||||||
uint64_t output_region_flag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _quic_info
|
||||||
|
{
|
||||||
|
struct _quic_stream *rej;
|
||||||
|
struct _quic_stream *client_hello;
|
||||||
|
struct _quic_stream *server_hello;
|
||||||
|
struct _gquic_frame_header frame_hdr;
|
||||||
|
struct _quic_public_header quic_hdr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//buff_len minimun 32bytes
|
||||||
|
int quic_version_int2string(unsigned int version, char *buff, int buff_len);
|
||||||
|
|
||||||
#endif /* SRC_GQUIC_H_ */
|
#endif /* SRC_GQUIC_H_ */
|
||||||
|
|||||||
1117
src/gquic_process.c
1117
src/gquic_process.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* gquic_process.h
|
* quic_process.h
|
||||||
*
|
*
|
||||||
* Created on: 2019<31><39>4<EFBFBD><34>2<EFBFBD><32>
|
* Created on: 2019<31><39>4<EFBFBD><34>2<EFBFBD><32>
|
||||||
* Author: root
|
* Author: root
|
||||||
@@ -14,94 +14,177 @@
|
|||||||
|
|
||||||
#include "gquic.h"
|
#include "gquic.h"
|
||||||
|
|
||||||
#define VERSION_LEN 4
|
//#define VERSION_LEN 4
|
||||||
#define VER_Q046 0x51303436
|
//#define VER_Q046
|
||||||
/**************************************************************************/
|
|
||||||
/* Public flag */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
|
#define GQUIC_PUBLIC_FLAG_VERSION 0x01
|
||||||
|
#define GQUIC_PUBLIC_FLAG_RST 0x02
|
||||||
|
#define GQUIC_PUBLIC_FLAG_NONCE 0x04
|
||||||
|
#define GQUIC_PUBLIC_FLAG_CID 0x08
|
||||||
|
#define GQUIC_PUBLIC_FLAG_PKT_NUM 0x30
|
||||||
|
|
||||||
|
//https://github.com/quicwg/base-drafts/wiki/QUIC-Versions
|
||||||
|
|
||||||
|
enum _QUIC_VERSION
|
||||||
|
{
|
||||||
|
QUIC_VERSION_UNKNOWN=0,
|
||||||
|
//google
|
||||||
|
GQUIC_VERSION_Q001=0x51303031,
|
||||||
|
GQUIC_VERSION_Q002=0x51303032,
|
||||||
|
GQUIC_VERSION_Q003=0x51303033,
|
||||||
|
GQUIC_VERSION_Q004=0x51303034,
|
||||||
|
GQUIC_VERSION_Q005=0x51303035,
|
||||||
|
GQUIC_VERSION_Q006=0x51303036,
|
||||||
|
GQUIC_VERSION_Q007=0x51303037,
|
||||||
|
GQUIC_VERSION_Q008=0x51303038,
|
||||||
|
GQUIC_VERSION_Q009=0x51303039,
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q010=0x51303130,
|
||||||
|
GQUIC_VERSION_Q011=0x51303131,
|
||||||
|
GQUIC_VERSION_Q012=0x51303132,
|
||||||
|
GQUIC_VERSION_Q013=0x51303133,
|
||||||
|
GQUIC_VERSION_Q014=0x51303134,
|
||||||
|
GQUIC_VERSION_Q015=0x51303135,
|
||||||
|
GQUIC_VERSION_Q016=0x51303136,
|
||||||
|
GQUIC_VERSION_Q017=0x51303137,
|
||||||
|
GQUIC_VERSION_Q018=0x51303138,
|
||||||
|
GQUIC_VERSION_Q019=0x51303139,
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q020=0x51303230,
|
||||||
|
GQUIC_VERSION_Q021=0x51303231,
|
||||||
|
GQUIC_VERSION_Q022=0x51303332,
|
||||||
|
GQUIC_VERSION_Q023=0x51303333,
|
||||||
|
GQUIC_VERSION_Q024=0x51303234,
|
||||||
|
GQUIC_VERSION_Q025=0x51303235,
|
||||||
|
GQUIC_VERSION_Q026=0x51303236,
|
||||||
|
GQUIC_VERSION_Q027=0x51303237,
|
||||||
|
GQUIC_VERSION_Q028=0x51303238,
|
||||||
|
GQUIC_VERSION_Q029=0x51303239,
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q030=0x51303330,
|
||||||
|
GQUIC_VERSION_Q031=0x51303331,
|
||||||
|
GQUIC_VERSION_Q032=0x51303332,
|
||||||
|
GQUIC_VERSION_Q033=0x51303333,
|
||||||
|
GQUIC_VERSION_Q034=0x51303334,
|
||||||
|
GQUIC_VERSION_Q035=0x51303335,
|
||||||
|
GQUIC_VERSION_Q036=0x51303336,
|
||||||
|
GQUIC_VERSION_Q037=0x51303337,
|
||||||
|
GQUIC_VERSION_Q038=0x51303338,
|
||||||
|
GQUIC_VERSION_Q039=0x51303339,
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q040=0x51303430,
|
||||||
|
GQUIC_VERSION_Q041=0x51303431,
|
||||||
|
GQUIC_VERSION_Q042=0x51303432,
|
||||||
|
GQUIC_VERSION_Q043=0x51303433,
|
||||||
|
GQUIC_VERSION_Q044=0x51303434,
|
||||||
|
GQUIC_VERSION_Q045=0x51303435,
|
||||||
|
GQUIC_VERSION_Q046=0x51303436,
|
||||||
|
GQUIC_VERSION_Q047=0x51303437,
|
||||||
|
GQUIC_VERSION_Q048=0x51303438, //Google QUIC with TLS
|
||||||
|
GQUIC_VERSION_Q049=0x51303439, //Google QUIC with TLS
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q050=0x51303530,
|
||||||
|
GQUIC_VERSION_Q051=0x51303531,
|
||||||
|
GQUIC_VERSION_Q052=0x51303532,
|
||||||
|
GQUIC_VERSION_Q053=0x51303533,
|
||||||
|
GQUIC_VERSION_Q054=0x51303534,
|
||||||
|
GQUIC_VERSION_Q055=0x51303535,
|
||||||
|
GQUIC_VERSION_Q056=0x51303536,
|
||||||
|
GQUIC_VERSION_Q057=0x51303537,
|
||||||
|
GQUIC_VERSION_Q058=0x51303538,
|
||||||
|
GQUIC_VERSION_Q059=0x51303539,
|
||||||
|
|
||||||
|
GQUIC_VERSION_Q099=0x51303939,
|
||||||
|
|
||||||
|
//Google Proxied QUIC
|
||||||
|
PQUIC_VERSION_PROX=0x50524f58
|
||||||
|
//GOQUIC_VERSION_GO=0x51474f[0-255],
|
||||||
|
//quicly
|
||||||
|
//QUICKLY_VERSION_QUICLY=0x91c170[0-255]
|
||||||
|
|
||||||
|
//IETF
|
||||||
|
//IQUIC_VERSION_=0xf10000
|
||||||
|
|
||||||
#define PACKET_PUBLIC_FLAGS_MAX 0x7f
|
|
||||||
#define PUBLIC_FLAG_VER_FST_BYTE 0x51
|
|
||||||
#define PUBLIC_FLAG_VER 0x01
|
|
||||||
#define PUBLIC_FLAG_RST 0x02
|
|
||||||
#define PUBLIC_FLAG_NONCE 0x04
|
|
||||||
#define BYTE_CNTID_8 0x08
|
|
||||||
#define BYTE_CNTID_0 0x00
|
|
||||||
enum gquic_connid_len {
|
|
||||||
PACKET_0BYTE_CONNECTION_ID = 0,
|
|
||||||
PACKET_8BYTE_CONNECTION_ID = 8
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PKT_NUM_6 0x30
|
struct _gquic_reset_public_header
|
||||||
#define PKT_NUM_4 0x20
|
{
|
||||||
#define PKT_NUM_2 0x10
|
unsigned char public_flags;
|
||||||
#define PKT_NUM_1 0x00
|
unsigned long long connection_id;
|
||||||
|
unsigned int tag;
|
||||||
//enum gquic_pkt_num_len {
|
|
||||||
// PACKET_1BYTE_PACKET_NUMBER = 1,
|
|
||||||
// PACKET_2BYTE_PACKET_NUMBER = 2,
|
|
||||||
// PACKET_4BYTE_PACKET_NUMBER = 4,
|
|
||||||
// PACKET_6BYTE_PACKET_NUMBER = 6
|
|
||||||
//};
|
|
||||||
|
|
||||||
// Used to indicate a QuicSequenceNumberLength using two flag bits.
|
|
||||||
enum gquic_pkt_num_len_flags {
|
|
||||||
PACKET_FLAGS_1BYTE_PACKET = 0, // 00
|
|
||||||
PACKET_FLAGS_2BYTE_PACKET = 1, // 01
|
|
||||||
PACKET_FLAGS_4BYTE_PACKET = 1 << 1, // 10
|
|
||||||
PACKET_FLAGS_6BYTE_PACKET = 1 << 1 | 1, // 11
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//#define PUBLIC_FLAG_MULTIPATH 0x40
|
//GQIIC Frame type
|
||||||
#define UNUSE 0x80
|
#define GQUIC_SPECIAL_FRAME_FLAG 0xE0 // Special Frame Types
|
||||||
#define MSG_AUTH_HASH_LEN 12
|
#define GQUIC_SPECIAL_FRAME_STREAM 0x80
|
||||||
#define PUB_HEAD_SEQ_SFT 4
|
#define GQUIC_SPECIAL_FRAME_ACK 0x40
|
||||||
|
#define GQUIC_SPECIAL_FRAME_CONGEST_FB 0x20
|
||||||
|
|
||||||
/**************************************************************************/
|
#define GQUIC_SPECIAL_FRAME_STREAM_FIN 0x40 // FIN
|
||||||
/* Frame type */
|
#define GQUIC_SPECIAL_FRAME_STREAM_DLEN 0x20 //stream length
|
||||||
/**************************************************************************/
|
#define GQUIC_SPECIAL_FRAME_STREAM_OFFSET 0x1C //offset header field
|
||||||
#define FRAM_SPECIAL 0xE0
|
#define GQUIC_SPECIAL_FRAME_STREAM_ID 0x03 //offset header field
|
||||||
#define STREAM 0x80
|
|
||||||
#define STREAM_F 0x40 //fin
|
|
||||||
#define STREAM_D 0x20 //data length
|
|
||||||
#define STREAM_OOO 0x1C //offset length
|
|
||||||
#define STREAM_SS 0x03 //stream length
|
|
||||||
#define ACK 0x40
|
|
||||||
#define ACK_LL 0x0c
|
|
||||||
#define ACK_MM 0x03
|
|
||||||
#define ACK_N 0x20
|
|
||||||
#define CONGESTION_FEEDBACK 0x20
|
|
||||||
#define PADDING 0x00
|
|
||||||
#define RST_STREAM 0x01
|
|
||||||
#define CONNECTION_CLOSE 0x02
|
|
||||||
#define GOAWAY 0x03
|
|
||||||
#define WINDOW_UPDATE 0x04
|
|
||||||
#define BLOCKED 0x05
|
|
||||||
#define STOP_WAITING 0x06
|
|
||||||
#define PING 0x07
|
|
||||||
|
|
||||||
|
#define GQUIC_REGULAR_FRAME_PADDING 0x00
|
||||||
|
#define GQUIC_REGULAR_FRAME_RST_STREAM 0x01
|
||||||
|
#define GQUIC_REGULAR_FRAME_CONNECTION_CLOSE 0x02
|
||||||
|
#define GQUIC_REGULAR_FRAME_GOAWAY 0x03
|
||||||
|
#define GQUIC_REGULAR_FRAME_WINDOW_UPDATE 0x04
|
||||||
|
#define GQUIC_REGULAR_FRAME_BLOCKED 0x05
|
||||||
|
#define GQUIC_REGULAR_FRAME_STOP_WAITING 0x06
|
||||||
|
#define GQUIC_REGULAR_FRAME_PING 0x07
|
||||||
|
|
||||||
#define STREAM_ID_1BYTE 0x00
|
#define GQUIC_SPECIAL_FRAME_FLAG 0xE0 // Special Frame Types
|
||||||
#define STREAM_ID_2BYTE 0x01
|
#define GQUIC_SPECIAL_FRAME_STREAM 0x80
|
||||||
#define STREAM_ID_3BYTE 0x02
|
#define GQUIC_SPECIAL_FRAME_ACK 0x40
|
||||||
#define STREAM_ID_4BYTE 0x03
|
#define GQUIC_SPECIAL_FRAME_CONGEST_FB 0x20
|
||||||
|
|
||||||
|
#define GQUIC_SPECIAL_FRAME_STREAM_FIN 0x40 // FIN
|
||||||
|
#define GQUIC_SPECIAL_FRAME_STREAM_DLEN 0x20 //stream length
|
||||||
|
#define GQUIC_SPECIAL_FRAME_STREAM_OFFSET 0x1C //offset header field
|
||||||
|
#define GQUIC_SPECIAL_FRAME_STREAM_ID 0x03 //offset header field
|
||||||
|
|
||||||
|
#define GQUIC_REGULAR_FRAME_PADDING 0x00
|
||||||
|
#define GQUIC_REGULAR_FRAME_RST_STREAM 0x01
|
||||||
|
#define GQUIC_REGULAR_FRAME_CONNECTION_CLOSE 0x02
|
||||||
|
#define GQUIC_REGULAR_FRAME_GOAWAY 0x03
|
||||||
|
#define GQUIC_REGULAR_FRAME_WINDOW_UPDATE 0x04
|
||||||
|
#define GQUIC_REGULAR_FRAME_BLOCKED 0x05
|
||||||
|
#define GQUIC_REGULAR_FRAME_STOP_WAITING 0x06
|
||||||
|
#define GQUIC_REGULAR_FRAME_PING 0x07
|
||||||
|
|
||||||
|
//IQIIC Frame type (GQUIC_Q046 is iQUIC 17)
|
||||||
|
#define IQUIC_FRAME_PADDING 0x00
|
||||||
|
#define IQUIC_FRAME_PING 0x10
|
||||||
|
#define IQUIC_FRAME_ACK_HEX02 0x20
|
||||||
|
#define IQUIC_FRAME_ACK_HEX03 0x30
|
||||||
|
#define IQUIC_FRAME_RESET_STREAM 0x40
|
||||||
|
#define IQUIC_FRAME_STOP_SENDING 0x50
|
||||||
|
#define IQUIC_FRAME_CRYPTO 0x60
|
||||||
|
#define IQUIC_FRAME_NEW_TOKEN 0x70
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX08 0x80
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX09 0x90
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0A 0xA0
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0B 0xB0
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0C 0xC0
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0D 0xD0
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0E 0xE0
|
||||||
|
#define IQUIC_FRAME_STREAM_HEX0F 0xF0
|
||||||
|
#define IQUIC_FRAME_MAX_DATA 0x01
|
||||||
|
#define IQUIC_FRAME_MAX_STREAM_DATA 0x11
|
||||||
|
#define IQUIC_FRAME_MAX_STREAMS_HEX12 0x21
|
||||||
|
#define IQUIC_FRAME_MAX_STREAMS_HEX13 0x31
|
||||||
|
#define IQUIC_FRAME_DATA_BLOCKED 0x41
|
||||||
|
#define IQUIC_FRAME_STREAM_DATA_BLOCKED 0x51
|
||||||
|
#define IQUIC_FRAME_STREAMS_BLOCKED_HEX16 0x61
|
||||||
|
#define IQUIC_FRAME_STREAMS_BLOCKED_HEX17 0x71
|
||||||
|
#define IQUIC_FRAME_NEW_CONNECTION_ID 0x81
|
||||||
|
#define IQUIC_FRAME_RETIRE_CONNECTION_ID 0x91
|
||||||
|
#define IQUIC_FRAME_PATH_CHALLENGE 0xA1
|
||||||
|
#define IQUIC_FRAME_PATH_RESPONSE 0xB1
|
||||||
|
#define IQUIC_FRAME_CONNECTION_CLOSE_HEX1C 0xC1
|
||||||
|
#define IQUIC_FRAME_CONNECTION_CLOSE_HEX1D 0xD1
|
||||||
|
|
||||||
enum frame_type_t{
|
|
||||||
FRAME_UNKNOWN = 0,
|
|
||||||
FRAME_STREAM,
|
|
||||||
FRAME_ACK,
|
|
||||||
FRAME_CONGESTION_FEEDBACK,
|
|
||||||
FRAME_PADDING,
|
|
||||||
FRAME_RST_STREAM,
|
|
||||||
FRAME_CONNECTION_CLOSE,
|
|
||||||
FRAME_GOAWAY,
|
|
||||||
FRAME_WINDOW_UPDATE,
|
|
||||||
FRAME_BLOCKED,
|
|
||||||
FRAME_STOP_WAITING,
|
|
||||||
FRAME_PING
|
|
||||||
};
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* Message tag */
|
/* Message tag */
|
||||||
@@ -111,40 +194,6 @@ enum frame_type_t{
|
|||||||
#define REJ 0x52454A00
|
#define REJ 0x52454A00
|
||||||
#define PRST 0x50525354
|
#define PRST 0x50525354
|
||||||
|
|
||||||
enum message_tag_t{
|
|
||||||
MTAG_UNKNOWN = 0,
|
|
||||||
MTAG_CHLO,
|
|
||||||
MTAG_SHLO,
|
|
||||||
MTAG_REJ,
|
|
||||||
MTAG_PRST
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gquic_frame_hdr{
|
|
||||||
enum frame_type_t frame_type;
|
|
||||||
UCHAR is_fin;
|
|
||||||
UCHAR data_len_byte;
|
|
||||||
UCHAR offset_len;
|
|
||||||
UCHAR stream_id_len;
|
|
||||||
UINT8 stream_id;
|
|
||||||
UINT16 data_len;
|
|
||||||
UCHAR padding_len;
|
|
||||||
enum message_tag_t tag;
|
|
||||||
UINT32 tag_num;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gquic_pkt_hdr{
|
|
||||||
UINT64 connection_id;
|
|
||||||
int connection_id_len;
|
|
||||||
UINT8 nonce_flag;
|
|
||||||
UINT8 reset_flag;
|
|
||||||
UINT8 version_flag;
|
|
||||||
UINT32 packet_number_len;
|
|
||||||
UINT32 version;
|
|
||||||
UINT8 version_int8;
|
|
||||||
UINT32 packet_number;
|
|
||||||
UCHAR auth_hash[MSG_AUTH_HASH_LEN];
|
|
||||||
// struct gquic_frame_hdr* frame_hdr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* Tag */
|
/* Tag */
|
||||||
@@ -196,15 +245,7 @@ struct gquic_pkt_hdr{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
UINT8 gquic_process(struct streaminfo *pstream, struct quic_stream* a_quic_stream, int thread_seq, void* a_packet);
|
int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int thread_seq, void* a_packet);
|
||||||
UINT32 read_offset_len(UINT8 frame_type);
|
|
||||||
UINT32 read_stream_len(UINT8 frame_type);
|
|
||||||
UINT32 read_largest_observed_len(UINT8 frame_type);
|
|
||||||
UINT32 read_missing_packet_len(UINT8 frame_type);
|
|
||||||
|
|
||||||
UINT32 get_stream_id(char* g_data_t, UINT8 frame_type, UINT32 *skip_len);
|
|
||||||
UINT32 read_seq_num_len(UINT8 flags);
|
|
||||||
int read_conn_id_len(UINT8 flags);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <MESA/MESA_handle_logger.h>
|
#include <MESA/MESA_handle_logger.h>
|
||||||
#include <MESA/MESA_prof_load.h>
|
#include <MESA/MESA_prof_load.h>
|
||||||
|
|
||||||
struct quic_param_t g_quic_param;
|
struct _quic_param_t g_quic_param;
|
||||||
const char *g_quic_proto_conffile="./conf/quic/main.conf";
|
const char *g_quic_proto_conffile="./conf/quic/main.conf";
|
||||||
const char *g_quic_regionname_conffile="./conf/quic/quic.conf";
|
const char *g_quic_regionname_conffile="./conf/quic/quic.conf";
|
||||||
|
|
||||||
@@ -39,47 +39,19 @@ static __attribute__((__used__)) const char * GIT_VERSION_UNKNOWN = NULL;
|
|||||||
|
|
||||||
const char QUIC_VERSION_20200522=0;
|
const char QUIC_VERSION_20200522=0;
|
||||||
|
|
||||||
|
|
||||||
int quic_init_stream(void **pme, int thread_seq)
|
int quic_init_stream(void **pme, int thread_seq)
|
||||||
{
|
{
|
||||||
struct quic_stream *a_quic_stream=(struct quic_stream *)*pme;
|
struct _quic_context *_context=(struct _quic_context *)*pme;
|
||||||
|
|
||||||
a_quic_stream=(struct quic_stream *)dictator_malloc(thread_seq, sizeof(struct quic_stream));
|
_context=(struct _quic_context *)dictator_malloc(thread_seq, sizeof(struct _quic_context));
|
||||||
memset(a_quic_stream,0,sizeof(struct quic_stream));
|
memset(_context, 0, sizeof(struct _quic_context));
|
||||||
|
|
||||||
a_quic_stream->output_region_flag = g_quic_param.quic_interested_region_flag;
|
*pme=(void*)_context;
|
||||||
a_quic_stream->output_region_mask = QUIC_INTEREST_KEY_MASK;
|
|
||||||
|
|
||||||
a_quic_stream->is_quic_stream = QUIC_FALSE;
|
|
||||||
a_quic_stream->version_cfm = QUIC_FALSE;
|
|
||||||
a_quic_stream->version = 0;
|
|
||||||
a_quic_stream->link_state = QUIC_FALSE;
|
|
||||||
a_quic_stream->fin_flag = QUIC_FALSE;
|
|
||||||
a_quic_stream->business = (struct quic_business_info *)dictator_malloc(thread_seq,sizeof(struct quic_business_info));
|
|
||||||
a_quic_stream->business->param = NULL;
|
|
||||||
a_quic_stream->business->return_value = PROT_STATE_GIVEME;
|
|
||||||
|
|
||||||
*pme = (void*)a_quic_stream;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void quic_release_clientHello(int thread_seq, struct quic_client_hello* st_client_hello)
|
void quic_release_exts(int thread_seq, quic_tlv_t *ext_tags, int ext_tag_num)
|
||||||
{
|
|
||||||
if(st_client_hello!=NULL)
|
|
||||||
{
|
|
||||||
if(st_client_hello->ext_tags!=NULL)
|
|
||||||
{
|
|
||||||
quic_release_exts(thread_seq, st_client_hello->ext_tags, st_client_hello->ext_tag_num);
|
|
||||||
dictator_free(thread_seq, st_client_hello->ext_tags);
|
|
||||||
st_client_hello->ext_tags = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num)
|
|
||||||
{
|
{
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
@@ -87,62 +59,48 @@ void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num
|
|||||||
{
|
{
|
||||||
for(i=0; i<ext_tag_num; i++)
|
for(i=0; i<ext_tag_num; i++)
|
||||||
{
|
{
|
||||||
if(ext_tags[i] != NULL)
|
if(ext_tags[i].value!=NULL)
|
||||||
{
|
{
|
||||||
if(ext_tags[i]->ptr_value != NULL)
|
dictator_free(thread_seq, ext_tags[i].value);
|
||||||
{
|
ext_tags[i].value=NULL;
|
||||||
dictator_free(thread_seq, ext_tags[i]->ptr_value);
|
|
||||||
ext_tags[i]->ptr_value = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dictator_free(thread_seq, ext_tags[i]);
|
|
||||||
ext_tags[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dictator_free(thread_seq, ext_tags);
|
dictator_free(thread_seq, ext_tags);
|
||||||
ext_tags=NULL;
|
ext_tags=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void quic_release_stream(struct streaminfo *a_tcp, void** pme, int thread_seq)
|
void quic_release_stream(struct streaminfo *a_tcp, void** pme, int thread_seq)
|
||||||
{
|
{
|
||||||
struct quic_stream *a_quic_stream = (struct quic_stream *)*pme;
|
struct _quic_context *_context = (struct _quic_context *)*pme;
|
||||||
if(NULL!=a_quic_stream)
|
if(NULL!=_context)
|
||||||
{
|
{
|
||||||
a_quic_stream->fin_flag = QUIC_TRUE;
|
if(_context->quic_info.client_hello!=NULL)
|
||||||
|
|
||||||
if(NULL!=a_quic_stream->business)
|
|
||||||
{
|
{
|
||||||
if(a_quic_stream->business->param!=NULL)
|
quic_release_exts(thread_seq, _context->quic_info.client_hello->ext_tags, _context->quic_info.client_hello->ext_tag_num);
|
||||||
{
|
dictator_free(thread_seq, _context->quic_info.client_hello);
|
||||||
dictator_free(thread_seq,a_quic_stream->business->param);
|
_context->quic_info.client_hello=NULL;
|
||||||
a_quic_stream->business->param = NULL;
|
|
||||||
}
|
|
||||||
dictator_free(thread_seq,a_quic_stream->business);
|
|
||||||
a_quic_stream->business = NULL;
|
|
||||||
}
|
|
||||||
if(NULL!=a_quic_stream->cert_chain.ptr_value)
|
|
||||||
{
|
|
||||||
dictator_free(thread_seq,a_quic_stream->cert_chain.ptr_value);
|
|
||||||
a_quic_stream->cert_chain.ptr_value = NULL;
|
|
||||||
}
|
|
||||||
if(NULL!=a_quic_stream->common_cert.ptr_value)
|
|
||||||
{
|
|
||||||
dictator_free(thread_seq,a_quic_stream->common_cert.ptr_value);
|
|
||||||
a_quic_stream->common_cert.ptr_value = NULL;
|
|
||||||
}
|
|
||||||
if(NULL!=a_quic_stream->cached_cert.ptr_value)
|
|
||||||
{
|
|
||||||
dictator_free(thread_seq,a_quic_stream->cached_cert.ptr_value);
|
|
||||||
a_quic_stream->cached_cert.ptr_value = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quic_release_exts(thread_seq, a_quic_stream->st_client_hello.ext_tags, a_quic_stream->st_client_hello.ext_tag_num);
|
if(_context->quic_info.server_hello!=NULL)
|
||||||
quic_release_exts(thread_seq, a_quic_stream->st_server_hello.ext_tags, a_quic_stream->st_server_hello.ext_tag_num);
|
{
|
||||||
|
quic_release_exts(thread_seq, _context->quic_info.server_hello->ext_tags, _context->quic_info.server_hello->ext_tag_num);
|
||||||
|
dictator_free(thread_seq, _context->quic_info.server_hello);
|
||||||
|
_context->quic_info.server_hello=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
dictator_free(thread_seq,a_quic_stream);
|
if(_context->quic_info.rej!=NULL)
|
||||||
a_quic_stream = NULL;
|
{
|
||||||
|
quic_release_exts(thread_seq, _context->quic_info.rej->ext_tags, _context->quic_info.rej->ext_tag_num);
|
||||||
|
dictator_free(thread_seq, _context->quic_info.rej);
|
||||||
|
_context->quic_info.rej=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dictator_free(thread_seq, _context);
|
||||||
|
_context=NULL;
|
||||||
|
*pme=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -157,7 +115,7 @@ extern "C" int QUIC_INIT(void)
|
|||||||
int region_id=0;
|
int region_id=0;
|
||||||
char region_name[REGION_NAME_LEN]={0};
|
char region_name[REGION_NAME_LEN]={0};
|
||||||
|
|
||||||
memset(&g_quic_param,0,sizeof(struct quic_param_t));
|
memset(&g_quic_param,0,sizeof(struct _quic_param_t));
|
||||||
|
|
||||||
MESA_load_profile_int_def(g_quic_proto_conffile, "QUIC", "LOG_LEVEL", &level, RLOG_LV_FATAL);
|
MESA_load_profile_int_def(g_quic_proto_conffile, "QUIC", "LOG_LEVEL", &level, RLOG_LV_FATAL);
|
||||||
MESA_load_profile_string_def(g_quic_proto_conffile, "QUIC", "LOG_PATH", log_path, sizeof(log_path), "./log/quic/quic");
|
MESA_load_profile_string_def(g_quic_proto_conffile, "QUIC", "LOG_PATH", log_path, sizeof(log_path), "./log/quic/quic");
|
||||||
@@ -278,8 +236,8 @@ extern "C" long long QUIC_FLAG_CHANGE(char* flag_str)
|
|||||||
|
|
||||||
extern "C" char QUIC_ENTRY(struct streaminfo *pstream, void**pme, int thread_seq, void *a_packet)
|
extern "C" char QUIC_ENTRY(struct streaminfo *pstream, void**pme, int thread_seq, void *a_packet)
|
||||||
{
|
{
|
||||||
uint8_t return_val=0;
|
int ret=0;
|
||||||
struct quic_stream *a_quic_stream=(struct quic_stream *)*pme;
|
struct _quic_context *_context=(struct _quic_context *)*pme;
|
||||||
|
|
||||||
if(g_quic_param.quic_interested_region_flag<QUIC_KEY)
|
if(g_quic_param.quic_interested_region_flag<QUIC_KEY)
|
||||||
{
|
{
|
||||||
@@ -296,28 +254,27 @@ extern "C" char QUIC_ENTRY(struct streaminfo *pstream, void**pme, int thread_seq
|
|||||||
if(*pme==NULL)
|
if(*pme==NULL)
|
||||||
{
|
{
|
||||||
quic_init_stream(pme, thread_seq);
|
quic_init_stream(pme, thread_seq);
|
||||||
a_quic_stream=(struct quic_stream *)*pme;
|
_context=(struct _quic_context *)*pme;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(pstream->opstate)
|
switch(pstream->opstate)
|
||||||
{
|
{
|
||||||
case OP_STATE_PENDING:
|
case OP_STATE_PENDING:
|
||||||
case OP_STATE_DATA:
|
case OP_STATE_DATA:
|
||||||
return_val=gquic_process(pstream, a_quic_stream, thread_seq, a_packet);
|
ret=quic_process(pstream, _context, thread_seq, a_packet);
|
||||||
break;
|
break;
|
||||||
case OP_STATE_CLOSE:
|
case OP_STATE_CLOSE:
|
||||||
a_quic_stream->fin_flag=QUIC_TRUE;
|
ret=quic_process(pstream, _context, thread_seq, a_packet);
|
||||||
return_val=gquic_process(pstream, a_quic_stream, thread_seq, a_packet);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(return_val==QUIC_RETURN_DROPME || pstream->opstate==OP_STATE_CLOSE)
|
if(ret&APP_STATE_DROPME|| pstream->opstate==OP_STATE_CLOSE)
|
||||||
{
|
{
|
||||||
quic_release_stream(pstream, pme, thread_seq);
|
quic_release_stream(pstream, pme, thread_seq);
|
||||||
*pme=NULL;
|
*pme=NULL;
|
||||||
return APP_STATE_DROPME;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return APP_STATE_GIVEME;
|
return APP_STATE_GIVEME;
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
/*
|
#ifndef _QUIC_ANALYSIS_H_
|
||||||
* quic_analysis.h
|
#define _QUIC_ANALYSIS_H_
|
||||||
*
|
|
||||||
* Created on: 2019<31><39>4<EFBFBD><34>2<EFBFBD><32>
|
|
||||||
* Author: root
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_QUIC_ANALYSIS_H_
|
#include "gquic.h"
|
||||||
#define SRC_QUIC_ANALYSIS_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "quic_util.h"
|
|
||||||
|
|
||||||
#define QUIC_TRUE 0x01
|
#define QUIC_TRUE 0x01
|
||||||
#define QUIC_FALSE 0x00
|
#define QUIC_FALSE 0x00
|
||||||
@@ -17,24 +9,14 @@
|
|||||||
#define QUIC_WHOLE_CLOSE 0x02
|
#define QUIC_WHOLE_CLOSE 0x02
|
||||||
#define QUIC_DATA 0x03
|
#define QUIC_DATA 0x03
|
||||||
#define QUIC_KEY 1
|
#define QUIC_KEY 1
|
||||||
#define CT_GNUC_SO_EXPORT __attribute__ ((visibility("default"))) //<2F><><EFBFBD>ŵ<EFBFBD><C5B5><EFBFBD><EFBFBD><EFBFBD>so<73>ļ<EFBFBD>
|
|
||||||
#define CT_GNUC_SO_LOCAL __attribute__ ((visibility("hidden"))) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD>so<73>ļ<EFBFBD><C4BC><EFBFBD>
|
|
||||||
#define QUIC_RETURN_NORM 0x60
|
#define QUIC_RETURN_NORM 0x60
|
||||||
#define QUIC_RETURN_UNNORM 0x61
|
#define QUIC_RETURN_UNNORM 0x61
|
||||||
#define QUIC_RETURN_RESET_BUFFER 0x62
|
#define QUIC_RETURN_RESET_BUFFER 0x62
|
||||||
#define QUIC_RETURN_DROPME 0x63
|
#define QUIC_RETURN_DROPME 0x63
|
||||||
#define MAX_REGION_NUM 15
|
#define MAX_REGION_NUM 15
|
||||||
#define REGION_NAME_LEN 32
|
#define REGION_NAME_LEN 32
|
||||||
#define GQUIC_HEADER_LEN 1+8+1
|
|
||||||
#define IQUIC_HEADER_LEN 1+8+1
|
|
||||||
#define ENC_BIG_ENDIAN 0x00000000
|
|
||||||
#define ENC_LITTLE_ENDIAN 0x80000000
|
|
||||||
|
|
||||||
#define DIR_C2S 0x01
|
struct _quic_param_t
|
||||||
#define DIR_S2C 0x02
|
|
||||||
#define DIR_DOUBLE 0x03
|
|
||||||
|
|
||||||
struct quic_param_t
|
|
||||||
{
|
{
|
||||||
unsigned long long quic_interested_region_flag;
|
unsigned long long quic_interested_region_flag;
|
||||||
unsigned long long quic_region_cnt;
|
unsigned long long quic_region_cnt;
|
||||||
@@ -54,7 +36,18 @@ enum quic_mes_type{
|
|||||||
MSG_UNKNOWN = 255
|
MSG_UNKNOWN = 255
|
||||||
};
|
};
|
||||||
|
|
||||||
void quic_release_exts(int thread_seq, quic_tlv_t** ext_tags, UINT16 ext_tag_num);
|
struct _quic_context
|
||||||
|
{
|
||||||
|
int is_quic;
|
||||||
|
int link_state;
|
||||||
|
void *business_pme;
|
||||||
|
struct _quic_info quic_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern struct _quic_param_t g_quic_param;
|
||||||
|
|
||||||
|
void quic_release_exts(int thread_seq, quic_tlv_t *ext_tags, int ext_tag_num);
|
||||||
|
|
||||||
#endif /* SRC_QUIC_ANALYSIS_H_ */
|
#endif /* SRC_QUIC_ANALYSIS_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +1,3 @@
|
|||||||
/*
|
|
||||||
* quic_callback.c
|
|
||||||
*
|
|
||||||
* Created on: 2019<31><39>4<EFBFBD><34>13<31><33>
|
|
||||||
* Author: root
|
|
||||||
*/
|
|
||||||
#include "gquic.h"
|
|
||||||
#include "quic_analysis.h"
|
|
||||||
extern struct quic_param_t g_quic_param;
|
|
||||||
|
|
||||||
int quic_getLinkState(struct quic_stream *a_quic_stream)
|
|
||||||
{
|
|
||||||
UCHAR state = 0;
|
|
||||||
|
|
||||||
if(QUIC_FALSE==a_quic_stream->link_state)
|
|
||||||
{
|
|
||||||
if(QUIC_TRUE==a_quic_stream->fin_flag)
|
|
||||||
{
|
|
||||||
state=SESSION_STATE_CLOSE|SESSION_STATE_PENDING;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state=SESSION_STATE_PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(QUIC_TRUE==(a_quic_stream)->fin_flag)
|
|
||||||
{
|
|
||||||
state=SESSION_STATE_CLOSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state=SESSION_STATE_DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a_quic_stream->link_state=QUIC_TRUE;
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
UCHAR quic_callPlugins(struct quic_stream *a_quic_stream, struct streaminfo *pstream, enum quic_interested_region region_mask, int thread_seq, void *a_packet)
|
|
||||||
{
|
|
||||||
stSessionInfo session_info;
|
|
||||||
unsigned long long region_flag=a_quic_stream->output_region_flag;
|
|
||||||
|
|
||||||
region_flag = (region_flag >> region_mask) % 2;
|
|
||||||
|
|
||||||
if(QUIC_TRUE==region_flag || a_quic_stream->fin_flag==QUIC_TRUE)
|
|
||||||
{
|
|
||||||
if (PROT_STATE_DROPME != a_quic_stream->business->return_value)
|
|
||||||
{
|
|
||||||
session_info.plugid = g_quic_param.quic_plugid;
|
|
||||||
session_info.prot_flag = (((unsigned long long)1)<<region_mask);
|
|
||||||
session_info.session_state = quic_getLinkState(a_quic_stream) ;
|
|
||||||
session_info.app_info = (void*)a_quic_stream;
|
|
||||||
a_quic_stream->business->return_value = PROT_PROCESS(&session_info, &(a_quic_stream->business->param),thread_seq,pstream, a_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUIC_RETURN_NORM;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,5 @@
|
|||||||
|
|
||||||
#ifndef SRC_QUIC_CALLBACK_H_
|
#ifndef SRC_QUIC_CALLBACK_H_
|
||||||
#define SRC_QUIC_CALLBACK_H_
|
#define SRC_QUIC_CALLBACK_H_
|
||||||
#include "gquic.h"
|
|
||||||
UCHAR quic_callPlugins(struct quic_stream *a_quic_stream, struct streaminfo *pstream, enum quic_interested_region region_mask, int thread_seq, void *a_packet);
|
|
||||||
|
|
||||||
//UCHAR quic_doWithVersion(struct quic_stream** a_quic_stream, struct streaminfo *pstream,
|
|
||||||
// unsigned long long region_flag, int thread_seq, void *a_packet);
|
|
||||||
//UCHAR quic_doWithApplicationData(char *pc_quic_data, int data_len, struct quic_stream **a_quic_stream, struct streaminfo *pstream,
|
|
||||||
// unsigned long long region_flag, int thread_seq, void *a_packet);
|
|
||||||
|
|
||||||
#endif /* SRC_QUIC_CALLBACK_H_ */
|
#endif /* SRC_QUIC_CALLBACK_H_ */
|
||||||
|
|||||||
17
src/quic_version.cpp
Normal file
17
src/quic_version.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gquic.h"
|
||||||
|
#include "gquic_process.h"
|
||||||
|
|
||||||
|
int quic_version_int2string(unsigned int version, char *buff, int buff_len)
|
||||||
|
{
|
||||||
|
if(version>0 && version<=GQUIC_VERSION_Q099)
|
||||||
|
{
|
||||||
|
snprintf(buff, buff_len, "Google QUIC %02d", (((version>>8)&0x0000000F)*10) + (version&0x0000000F));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user