Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_50753323
TDengine
提交
341ab912
T
TDengine
项目概览
qq_50753323
/
TDengine
与 Fork 源项目一致
Fork自
taosdata / TDengine
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
341ab912
编写于
9月 27, 2019
作者:
S
slguan
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix issue #569
上级
3dc152df
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
560 addition
and
81 deletion
+560
-81
src/modules/http/inc/httpHandle.h
src/modules/http/inc/httpHandle.h
+0
-1
src/modules/http/src/httpAuth.c
src/modules/http/src/httpAuth.c
+50
-0
src/modules/http/src/httpHandle.c
src/modules/http/src/httpHandle.c
+32
-37
src/modules/http/src/httpServer.c
src/modules/http/src/httpServer.c
+12
-35
src/modules/http/src/httpSession.c
src/modules/http/src/httpSession.c
+15
-5
src/modules/http/src/httpSql.c
src/modules/http/src/httpSql.c
+7
-3
src/util/src/tdes.c
src/util/src/tdes.c
+444
-0
未找到文件。
src/modules/http/inc/httpHandle.h
浏览文件 @
341ab912
...
...
@@ -188,7 +188,6 @@ typedef struct HttpContext {
HttpSqlCmd
singleCmd
;
HttpSqlCmds
*
multiCmds
;
JsonBuf
*
jsonBuf
;
pthread_mutex_t
mutex
;
HttpParser
parser
;
void
*
readTimer
;
struct
HttpThread
*
pThread
;
...
...
src/modules/http/src/httpAuth.c
浏览文件 @
341ab912
...
...
@@ -23,6 +23,7 @@
#include "http.h"
#include "httpHandle.h"
#include "tkey.h"
#define KEY_DES_4 4971256377704625728L
bool
httpParseBasicAuthToken
(
HttpContext
*
pContext
,
char
*
token
,
int
len
)
{
token
[
len
]
=
'\0'
;
...
...
@@ -65,3 +66,52 @@ bool httpParseBasicAuthToken(HttpContext *pContext, char *token, int len) {
pContext
->
user
);
return
true
;
}
bool
httpParseTaosdAuthToken
(
HttpContext
*
pContext
,
char
*
token
,
int
len
)
{
token
[
len
]
=
'\0'
;
int
outlen
=
0
;
unsigned
char
*
base64
=
base64_decode
(
token
,
len
,
&
outlen
);
if
(
base64
==
NULL
||
outlen
==
0
)
{
httpError
(
"context:%p, fd:%d, ip:%s, taosd token:%s parsed error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
token
);
return
false
;
}
if
(
outlen
!=
(
TSDB_USER_LEN
+
TSDB_PASSWORD_LEN
))
{
httpError
(
"context:%p, fd:%d, ip:%s, taosd token:%s length error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
token
);
free
(
base64
);
return
false
;
}
char
*
descrypt
=
taosDesDecode
(
KEY_DES_4
,
(
char
*
)
base64
,
outlen
);
if
(
descrypt
==
NULL
)
{
httpError
(
"context:%p, fd:%d, ip:%s, taosd token:%s descrypt error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
token
);
free
(
base64
);
return
false
;
}
else
{
strncpy
(
pContext
->
user
,
descrypt
,
TSDB_USER_LEN
);
strncpy
(
pContext
->
pass
,
descrypt
+
TSDB_USER_LEN
,
TSDB_PASSWORD_LEN
);
httpTrace
(
"context:%p, fd:%d, ip:%s, taosd token:%s parsed success, user:%s"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
token
,
pContext
->
user
);
free
(
base64
);
free
(
descrypt
);
return
true
;
}
}
bool
httpGenTaosdAuthToken
(
HttpContext
*
pContext
,
char
*
token
,
int
maxLen
)
{
char
buffer
[
TSDB_USER_LEN
+
TSDB_PASSWORD_LEN
]
=
{
0
};
strncpy
(
buffer
,
pContext
->
user
,
TSDB_USER_LEN
);
strncpy
(
buffer
+
TSDB_USER_LEN
,
pContext
->
pass
,
TSDB_PASSWORD_LEN
);
char
*
encrypt
=
taosDesEncode
(
KEY_DES_4
,
buffer
,
TSDB_USER_LEN
+
TSDB_PASSWORD_LEN
);
char
*
base64
=
base64_encode
((
const
unsigned
char
*
)
encrypt
,
TSDB_USER_LEN
+
TSDB_PASSWORD_LEN
);
strncpy
(
token
,
base64
,
(
size_t
)
strlen
(
base64
));
free
(
encrypt
);
free
(
base64
);
httpTrace
(
"context:%p, fd:%d, ip:%s, gen taosd token:%s"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
token
);
return
true
;
}
src/modules/http/src/httpHandle.c
浏览文件 @
341ab912
...
...
@@ -224,8 +224,13 @@ bool httpParseHead(HttpContext* pContext) {
return
false
;
}
}
else
if
(
strncasecmp
(
pParser
->
pLast
+
15
,
"Taosd "
,
6
)
==
0
)
{
httpSendErrorResp
(
pContext
,
HTTP_INVALID_TAOSD_AUTH_TOKEN
);
return
false
;
pParser
->
token
.
pos
=
pParser
->
pLast
+
21
;
pParser
->
token
.
len
=
(
int16_t
)(
pParser
->
pCur
-
pParser
->
token
.
pos
-
1
);
bool
parsed
=
httpParseTaosdAuthToken
(
pContext
,
pParser
->
token
.
pos
,
pParser
->
token
.
len
);
if
(
!
parsed
)
{
httpSendErrorResp
(
pContext
,
HTTP_INVALID_TAOSD_AUTH_TOKEN
);
return
false
;
}
}
else
{
httpSendErrorResp
(
pContext
,
HTTP_INVALID_AUTH_TOKEN
);
return
false
;
...
...
@@ -269,51 +274,41 @@ bool httpParseChunkedBody(HttpContext* pContext, HttpParser* pParser, bool test)
}
bool
httpReadChunkedBody
(
HttpContext
*
pContext
,
HttpParser
*
pParser
)
{
for
(
int
tryTimes
=
0
;
tryTimes
<
HTTP_READ_RETRY_TIMES
;
++
tryTimes
)
{
bool
parsedOk
=
httpParseChunkedBody
(
pContext
,
pParser
,
true
);
if
(
parsedOk
)
{
httpParseChunkedBody
(
pContext
,
pParser
,
false
);
return
HTTP_CHECK_BODY_SUCCESS
;
bool
parsedOk
=
httpParseChunkedBody
(
pContext
,
pParser
,
true
);
if
(
parsedOk
)
{
httpParseChunkedBody
(
pContext
,
pParser
,
false
);
return
HTTP_CHECK_BODY_SUCCESS
;
}
else
{
httpTrace
(
"context:%p, fd:%d, ip:%s, chunked body not finished, continue read"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
if
(
!
httpReadDataImp
(
pContext
))
{
httpError
(
"context:%p, fd:%d, ip:%s, read chunked request error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_ERROR
;
}
else
{
httpTrace
(
"context:%p, fd:%d, ip:%s, chunked body not finished, continue read"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
if
(
!
httpReadDataImp
(
pContext
))
{
httpError
(
"context:%p, fd:%d, ip:%s, read chunked request error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_ERROR
;
}
else
{
taosMsleep
(
HTTP_READ_WAIT_TIME_MS
);
}
return
HTTP_CHECK_BODY_CONTINUE
;
}
}
httpTrace
(
"context:%p, fd:%d, ip:%s, chunked body not finished, wait epoll"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_CONTINUE
;
}
int
httpReadUnChunkedBody
(
HttpContext
*
pContext
,
HttpParser
*
pParser
)
{
for
(
int
tryTimes
=
0
;
tryTimes
<
HTTP_READ_RETRY_TIMES
;
++
tryTimes
)
{
int
dataReadLen
=
pParser
->
bufsize
-
(
int
)(
pParser
->
data
.
pos
-
pParser
->
buffer
);
if
(
dataReadLen
>
pParser
->
data
.
len
)
{
httpError
(
"context:%p, fd:%d, ip:%s, un-chunked body length invalid, dataReadLen:%d > pContext->data.len:%d"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
dataReadLen
,
pParser
->
data
.
len
);
httpSendErrorResp
(
pContext
,
HTTP_PARSE_BODY_ERROR
);
int
dataReadLen
=
pParser
->
bufsize
-
(
int
)(
pParser
->
data
.
pos
-
pParser
->
buffer
);
if
(
dataReadLen
>
pParser
->
data
.
len
)
{
httpError
(
"context:%p, fd:%d, ip:%s, un-chunked body length invalid, dataReadLen:%d > pContext->data.len:%d"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
dataReadLen
,
pParser
->
data
.
len
);
httpSendErrorResp
(
pContext
,
HTTP_PARSE_BODY_ERROR
);
return
HTTP_CHECK_BODY_ERROR
;
}
else
if
(
dataReadLen
<
pParser
->
data
.
len
)
{
httpTrace
(
"context:%p, fd:%d, ip:%s, un-chunked body not finished, dataReadLen:%d < pContext->data.len:%d, continue read"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
dataReadLen
,
pParser
->
data
.
len
);
if
(
!
httpReadDataImp
(
pContext
))
{
httpError
(
"context:%p, fd:%d, ip:%s, read chunked request error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_ERROR
;
}
else
if
(
dataReadLen
<
pParser
->
data
.
len
)
{
httpTrace
(
"context:%p, fd:%d, ip:%s, un-chunked body not finished, dataReadLen:%d < pContext->data.len:%d, continue read"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
dataReadLen
,
pParser
->
data
.
len
);
if
(
!
httpReadDataImp
(
pContext
))
{
httpError
(
"context:%p, fd:%d, ip:%s, read chunked request error"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_ERROR
;
}
else
{
taosMsleep
(
HTTP_READ_WAIT_TIME_MS
);
}
}
else
{
return
HTTP_CHECK_BODY_
SUCCESS
;
return
HTTP_CHECK_BODY_
CONTINUE
;
}
}
else
{
return
HTTP_CHECK_BODY_SUCCESS
;
}
httpTrace
(
"context:%p, fd:%d, ip:%s, un-chunked body not finished, wait epoll"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
);
return
HTTP_CHECK_BODY_CONTINUE
;
}
bool
httpParseRequest
(
HttpContext
*
pContext
)
{
...
...
src/modules/http/src/httpServer.c
浏览文件 @
341ab912
...
...
@@ -73,18 +73,10 @@ HttpContext *httpCreateContext(HttpServer *pServer) {
pContext
->
signature
=
pContext
;
pContext
->
httpVersion
=
HTTP_VERSION_10
;
pContext
->
lastAccessTime
=
taosGetTimestampSec
();
if
(
pthread_mutex_init
(
&
(
pContext
->
mutex
),
NULL
)
<
0
)
{
httpFreeContext
(
pServer
,
pContext
);
return
NULL
;
}
return
pContext
;
}
void
httpFreeContext
(
HttpServer
*
pServer
,
HttpContext
*
pContext
)
{
pthread_mutex_unlock
(
&
pContext
->
mutex
);
pthread_mutex_destroy
(
&
pContext
->
mutex
);
if
(
pContext
->
fromMemPool
)
{
httpTrace
(
"context:%p, is freed from mempool"
,
pContext
);
taosMemPoolFree
(
pServer
->
pContextPool
,
(
char
*
)
pContext
);
...
...
@@ -103,7 +95,12 @@ void httpCleanUpContextTimer(HttpContext *pContext) {
}
void
httpCleanUpContext
(
HttpThread
*
pThread
,
HttpContext
*
pContext
)
{
// for not keep-alive
void
*
sigature
=
__sync_val_compare_and_swap_64
(
&
pContext
->
signature
,
pContext
->
signature
,
0
);
if
(
sigature
==
NULL
)
{
httpTrace
(
"context:%p is freed by another thread."
,
pContext
);
return
;
}
httpCleanUpContextTimer
(
pContext
);
if
(
pContext
->
fd
>=
0
)
{
...
...
@@ -182,13 +179,7 @@ void httpCloseContextByApp(HttpContext *pContext) {
return
;
}
pthread_mutex_lock
(
&
pContext
->
mutex
);
if
(
pContext
->
signature
!=
pContext
)
{
return
;
}
pContext
->
parsed
=
false
;
httpTrace
(
"context:%p, fd:%d, ip:%s, app use finished, usedByEpoll:%d, usedByApp:%d, httpVersion:1.%d, keepAlive:%d"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
pContext
->
usedByEpoll
,
pContext
->
usedByApp
,
pContext
->
httpVersion
,
pContext
->
httpKeepAlive
);
...
...
@@ -202,7 +193,6 @@ void httpCloseContextByApp(HttpContext *pContext) {
httpCleanUpContext
(
pThread
,
pContext
);
}
else
{
pContext
->
usedByApp
=
0
;
pthread_mutex_unlock
(
&
pContext
->
mutex
);
}
}
}
...
...
@@ -211,14 +201,8 @@ void httpCloseContextByServer(HttpThread *pThread, HttpContext *pContext) {
if
(
pContext
->
signature
!=
pContext
||
pContext
->
pThread
!=
pThread
)
{
return
;
}
pthread_mutex_lock
(
&
pContext
->
mutex
);
if
(
pContext
->
signature
!=
pContext
)
{
return
;
}
pContext
->
usedByEpoll
=
0
;
pContext
->
parsed
=
false
;
httpTrace
(
"context:%p, fd:%d, ip:%s, epoll use finished, usedByEpoll:%d, usedByApp:%d"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
pContext
->
usedByEpoll
,
pContext
->
usedByApp
);
...
...
@@ -231,7 +215,7 @@ void httpCloseContextByServer(HttpThread *pThread, HttpContext *pContext) {
if
(
!
pContext
->
usedByApp
)
{
httpCleanUpContext
(
pThread
,
pContext
);
}
else
{
p
thread_mutex_unlock
(
&
pContext
->
mutex
)
;
p
Context
->
usedByEpoll
=
0
;
}
}
...
...
@@ -281,7 +265,6 @@ void httpReadDirtyData(int fd) {
bool
httpReadDataImp
(
HttpContext
*
pContext
)
{
HttpParser
*
pParser
=
&
pContext
->
parser
;
int
blocktimes
=
0
;
while
(
pParser
->
bufsize
<=
(
HTTP_BUFFER_SIZE
-
HTTP_STEP_SIZE
))
{
int
nread
=
(
int
)
taosReadSocket
(
pContext
->
fd
,
pParser
->
buffer
+
pParser
->
bufsize
,
HTTP_STEP_SIZE
);
if
(
nread
>=
0
&&
nread
<
HTTP_STEP_SIZE
)
{
...
...
@@ -289,13 +272,9 @@ bool httpReadDataImp(HttpContext *pContext) {
break
;
}
else
if
(
nread
<
0
)
{
if
(
errno
==
EINTR
||
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
if
(
blocktimes
++
>
HTTP_READ_RETRY_TIMES
)
{
taosMsleep
(
HTTP_READ_WAIT_TIME_MS
);
httpTrace
(
"context:%p, fd:%d, ip:%s, read from socket error:%d, error times:%d"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
errno
,
blocktimes
);
break
;
}
continue
;
httpTrace
(
"context:%p, fd:%d, ip:%s, read from socket error:%d, wait another event"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
errno
);
break
;
}
else
{
httpError
(
"context:%p, fd:%d, ip:%s, read from socket error:%d, close connect"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
errno
);
...
...
@@ -575,6 +554,8 @@ bool httpInitConnect(HttpServer *pServer) {
}
memset
(
pServer
->
pThreads
,
0
,
sizeof
(
HttpThread
)
*
(
size_t
)
pServer
->
numOfThreads
);
pthread_attr_init
(
&
thattr
);
pthread_attr_setdetachstate
(
&
thattr
,
PTHREAD_CREATE_JOINABLE
);
pThread
=
pServer
->
pThreads
;
for
(
i
=
0
;
i
<
pServer
->
numOfThreads
;
++
i
)
{
sprintf
(
pThread
->
label
,
"%s%d"
,
pServer
->
label
,
i
);
...
...
@@ -598,8 +579,6 @@ bool httpInitConnect(HttpServer *pServer) {
return
false
;
}
pthread_attr_init
(
&
thattr
);
pthread_attr_setdetachstate
(
&
thattr
,
PTHREAD_CREATE_JOINABLE
);
if
(
pthread_create
(
&
(
pThread
->
thread
),
&
thattr
,
(
void
*
)
httpProcessHttpData
,
(
void
*
)(
pThread
))
!=
0
)
{
httpError
(
"http thread:%s, failed to create HTTP process data thread, reason:%s"
,
pThread
->
label
,
strerror
(
errno
));
...
...
@@ -610,8 +589,6 @@ bool httpInitConnect(HttpServer *pServer) {
pThread
++
;
}
pthread_attr_init
(
&
thattr
);
pthread_attr_setdetachstate
(
&
thattr
,
PTHREAD_CREATE_JOINABLE
);
if
(
pthread_create
(
&
(
pServer
->
thread
),
&
thattr
,
(
void
*
)
httpAcceptHttpConnection
,
(
void
*
)(
pServer
))
!=
0
)
{
httpError
(
"http server:%s, failed to create Http accept thread, reason:%s"
,
pServer
->
label
,
strerror
(
errno
));
return
false
;
...
...
src/modules/http/src/httpSession.c
浏览文件 @
341ab912
...
...
@@ -28,8 +28,12 @@
#include "ttimer.h"
void
httpAccessSession
(
HttpContext
*
pContext
)
{
if
(
pContext
->
session
==
pContext
->
session
->
signature
)
pContext
->
session
->
expire
=
(
int
)
taosGetTimestampSec
()
+
pContext
->
pThread
->
pServer
->
sessionExpire
;
HttpServer
*
server
=
pContext
->
pThread
->
pServer
;
pthread_mutex_lock
(
&
server
->
serverMutex
);
if
(
pContext
->
session
==
pContext
->
session
->
signature
)
{
pContext
->
session
->
expire
=
(
int
)
taosGetTimestampSec
()
+
pContext
->
pThread
->
pServer
->
sessionExpire
;
}
pthread_mutex_unlock
(
&
server
->
serverMutex
);
}
void
httpCreateSession
(
HttpContext
*
pContext
,
void
*
taos
)
{
...
...
@@ -53,6 +57,8 @@ void httpCreateSession(HttpContext *pContext, void *taos) {
httpError
(
"context:%p, fd:%d, ip:%s, user:%s, error:%s"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
pContext
->
user
,
httpMsg
[
HTTP_SESSION_FULL
]);
taos_close
(
taos
);
pthread_mutex_unlock
(
&
server
->
serverMutex
);
return
;
}
pContext
->
session
->
signature
=
pContext
->
session
;
...
...
@@ -82,10 +88,14 @@ void httpFetchSession(HttpContext *pContext) {
void
httpRestoreSession
(
HttpContext
*
pContext
)
{
HttpServer
*
server
=
pContext
->
pThread
->
pServer
;
HttpSession
*
session
=
pContext
->
session
;
if
(
session
==
NULL
||
session
!=
session
->
signature
)
return
;
// all access to the session is via serverMutex
pthread_mutex_lock
(
&
server
->
serverMutex
);
HttpSession
*
session
=
pContext
->
session
;
if
(
session
==
NULL
||
session
!=
session
->
signature
)
{
pthread_mutex_unlock
(
&
server
->
serverMutex
);
return
;
}
session
->
access
--
;
httpTrace
(
"context:%p, ip:%s, user:%s, restore session:%p:%s:%p, access:%d, expire:%d"
,
pContext
,
pContext
->
ipstr
,
pContext
->
user
,
session
,
session
->
id
,
session
->
taos
,
...
...
@@ -127,7 +137,7 @@ bool httpInitAllSessions(HttpServer *pServer) {
int
httpSessionExpired
(
char
*
session
)
{
HttpSession
*
pSession
=
(
HttpSession
*
)
session
;
time_t
cur
=
t
ime
(
NULL
);
time_t
cur
=
t
aosGetTimestampSec
(
);
if
(
pSession
->
taos
!=
NULL
)
{
if
(
pSession
->
expire
>
cur
)
{
...
...
src/modules/http/src/httpSql.c
浏览文件 @
341ab912
...
...
@@ -300,10 +300,14 @@ void httpProcessSingleSqlCmd(HttpContext *pContext) {
}
void
httpProcessLoginCmd
(
HttpContext
*
pContext
)
{
char
token
[
128
]
=
"current version only supports basic authorization, no token returned"
;
httpTrace
(
"context:%p, fd:%d, ip:%s, user:%s, login via http, return token:%s"
,
char
token
[
128
]
=
{
0
};
if
(
!
httpGenTaosdAuthToken
(
pContext
,
token
,
128
))
{
httpSendErrorResp
(
pContext
,
HTTP_GEN_TAOSD_TOKEN_ERR
);
}
else
{
httpTrace
(
"context:%p, fd:%d, ip:%s, user:%s, login via http, return token:%s"
,
pContext
,
pContext
->
fd
,
pContext
->
ipstr
,
pContext
->
user
,
token
);
httpSendSuccResp
(
pContext
,
token
);
httpSendSuccResp
(
pContext
,
token
);
}
}
void
httpProcessHeartBeatCmd
(
HttpContext
*
pContext
)
{
...
...
src/util/src/tdes.c
0 → 100644
浏览文件 @
341ab912
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tkey.h"
#define ENCRYPTION_MODE 1
#define DECRYPTION_MODE 0
typedef
struct
{
unsigned
char
k
[
8
];
unsigned
char
c
[
4
];
unsigned
char
d
[
4
];
}
key_set
;
void
generate_key
(
unsigned
char
*
key
);
void
generate_sub_keys
(
unsigned
char
*
main_key
,
key_set
*
key_sets
);
void
process_message
(
unsigned
char
*
message_piece
,
unsigned
char
*
processed_piece
,
key_set
*
key_sets
,
int
mode
);
int64_t
taosDesGenKey
()
{
unsigned
int
iseed
=
(
unsigned
int
)
time
(
NULL
);
srand
(
iseed
);
unsigned
char
key
[
8
]
=
{
0
};
generate_key
(
key
);
return
*
((
int64_t
*
)
key
);
}
char
*
taosDesImp
(
unsigned
char
*
key
,
char
*
src
,
unsigned
int
len
,
int
process_mode
)
{
unsigned
int
number_of_blocks
=
len
/
8
;
unsigned
char
data_block
[
9
]
=
{
0
};
unsigned
char
processed_block
[
9
]
=
{
0
};
key_set
key_sets
[
17
]
=
{
0
};
char
*
dest
=
calloc
(
len
+
1
,
1
);
generate_sub_keys
(
key
,
key_sets
);
for
(
unsigned
int
block_count
=
0
;
block_count
<
number_of_blocks
;
block_count
++
)
{
memset
(
processed_block
,
0
,
8
);
memcpy
(
data_block
,
src
+
block_count
*
8
,
8
);
process_message
(
data_block
,
processed_block
,
key_sets
,
process_mode
);
memcpy
(
dest
+
block_count
*
8
,
processed_block
,
8
);
}
return
dest
;
}
char
*
taosDesEncode
(
int64_t
key
,
char
*
src
,
int
len
)
{
if
(
len
%
8
!=
0
)
return
NULL
;
unsigned
char
*
keyStr
=
(
unsigned
char
*
)(
&
key
);
return
taosDesImp
(
keyStr
,
src
,
len
,
ENCRYPTION_MODE
);
}
char
*
taosDesDecode
(
int64_t
key
,
char
*
src
,
int
len
)
{
unsigned
char
*
keyStr
=
(
unsigned
char
*
)(
&
key
);
char
*
temp
=
calloc
(
len
+
8
,
1
);
memcpy
(
temp
,
src
,
len
);
len
+=
8
;
char
*
decode
=
taosDesImp
(
keyStr
,
temp
,
len
,
DECRYPTION_MODE
);
free
(
temp
);
return
decode
;
}
int
initial_key_permutaion
[]
=
{
57
,
49
,
41
,
33
,
25
,
17
,
9
,
1
,
58
,
50
,
42
,
34
,
26
,
18
,
10
,
2
,
59
,
51
,
43
,
35
,
27
,
19
,
11
,
3
,
60
,
52
,
44
,
36
,
63
,
55
,
47
,
39
,
31
,
23
,
15
,
7
,
62
,
54
,
46
,
38
,
30
,
22
,
14
,
6
,
61
,
53
,
45
,
37
,
29
,
21
,
13
,
5
,
28
,
20
,
12
,
4
};
int
initial_message_permutation
[]
=
{
58
,
50
,
42
,
34
,
26
,
18
,
10
,
2
,
60
,
52
,
44
,
36
,
28
,
20
,
12
,
4
,
62
,
54
,
46
,
38
,
30
,
22
,
14
,
6
,
64
,
56
,
48
,
40
,
32
,
24
,
16
,
8
,
57
,
49
,
41
,
33
,
25
,
17
,
9
,
1
,
59
,
51
,
43
,
35
,
27
,
19
,
11
,
3
,
61
,
53
,
45
,
37
,
29
,
21
,
13
,
5
,
63
,
55
,
47
,
39
,
31
,
23
,
15
,
7
};
int
key_shift_sizes
[]
=
{
-
1
,
1
,
1
,
2
,
2
,
2
,
2
,
2
,
2
,
1
,
2
,
2
,
2
,
2
,
2
,
2
,
1
};
int
sub_key_permutation
[]
=
{
14
,
17
,
11
,
24
,
1
,
5
,
3
,
28
,
15
,
6
,
21
,
10
,
23
,
19
,
12
,
4
,
26
,
8
,
16
,
7
,
27
,
20
,
13
,
2
,
41
,
52
,
31
,
37
,
47
,
55
,
30
,
40
,
51
,
45
,
33
,
48
,
44
,
49
,
39
,
56
,
34
,
53
,
46
,
42
,
50
,
36
,
29
,
32
};
int
message_expansion
[]
=
{
32
,
1
,
2
,
3
,
4
,
5
,
4
,
5
,
6
,
7
,
8
,
9
,
8
,
9
,
10
,
11
,
12
,
13
,
12
,
13
,
14
,
15
,
16
,
17
,
16
,
17
,
18
,
19
,
20
,
21
,
20
,
21
,
22
,
23
,
24
,
25
,
24
,
25
,
26
,
27
,
28
,
29
,
28
,
29
,
30
,
31
,
32
,
1
};
int
S1
[]
=
{
14
,
4
,
13
,
1
,
2
,
15
,
11
,
8
,
3
,
10
,
6
,
12
,
5
,
9
,
0
,
7
,
0
,
15
,
7
,
4
,
14
,
2
,
13
,
1
,
10
,
6
,
12
,
11
,
9
,
5
,
3
,
8
,
4
,
1
,
14
,
8
,
13
,
6
,
2
,
11
,
15
,
12
,
9
,
7
,
3
,
10
,
5
,
0
,
15
,
12
,
8
,
2
,
4
,
9
,
1
,
7
,
5
,
11
,
3
,
14
,
10
,
0
,
6
,
13
};
int
S2
[]
=
{
15
,
1
,
8
,
14
,
6
,
11
,
3
,
4
,
9
,
7
,
2
,
13
,
12
,
0
,
5
,
10
,
3
,
13
,
4
,
7
,
15
,
2
,
8
,
14
,
12
,
0
,
1
,
10
,
6
,
9
,
11
,
5
,
0
,
14
,
7
,
11
,
10
,
4
,
13
,
1
,
5
,
8
,
12
,
6
,
9
,
3
,
2
,
15
,
13
,
8
,
10
,
1
,
3
,
15
,
4
,
2
,
11
,
6
,
7
,
12
,
0
,
5
,
14
,
9
};
int
S3
[]
=
{
10
,
0
,
9
,
14
,
6
,
3
,
15
,
5
,
1
,
13
,
12
,
7
,
11
,
4
,
2
,
8
,
13
,
7
,
0
,
9
,
3
,
4
,
6
,
10
,
2
,
8
,
5
,
14
,
12
,
11
,
15
,
1
,
13
,
6
,
4
,
9
,
8
,
15
,
3
,
0
,
11
,
1
,
2
,
12
,
5
,
10
,
14
,
7
,
1
,
10
,
13
,
0
,
6
,
9
,
8
,
7
,
4
,
15
,
14
,
3
,
11
,
5
,
2
,
12
};
int
S4
[]
=
{
7
,
13
,
14
,
3
,
0
,
6
,
9
,
10
,
1
,
2
,
8
,
5
,
11
,
12
,
4
,
15
,
13
,
8
,
11
,
5
,
6
,
15
,
0
,
3
,
4
,
7
,
2
,
12
,
1
,
10
,
14
,
9
,
10
,
6
,
9
,
0
,
12
,
11
,
7
,
13
,
15
,
1
,
3
,
14
,
5
,
2
,
8
,
4
,
3
,
15
,
0
,
6
,
10
,
1
,
13
,
8
,
9
,
4
,
5
,
11
,
12
,
7
,
2
,
14
};
int
S5
[]
=
{
2
,
12
,
4
,
1
,
7
,
10
,
11
,
6
,
8
,
5
,
3
,
15
,
13
,
0
,
14
,
9
,
14
,
11
,
2
,
12
,
4
,
7
,
13
,
1
,
5
,
0
,
15
,
10
,
3
,
9
,
8
,
6
,
4
,
2
,
1
,
11
,
10
,
13
,
7
,
8
,
15
,
9
,
12
,
5
,
6
,
3
,
0
,
14
,
11
,
8
,
12
,
7
,
1
,
14
,
2
,
13
,
6
,
15
,
0
,
9
,
10
,
4
,
5
,
3
};
int
S6
[]
=
{
12
,
1
,
10
,
15
,
9
,
2
,
6
,
8
,
0
,
13
,
3
,
4
,
14
,
7
,
5
,
11
,
10
,
15
,
4
,
2
,
7
,
12
,
9
,
5
,
6
,
1
,
13
,
14
,
0
,
11
,
3
,
8
,
9
,
14
,
15
,
5
,
2
,
8
,
12
,
3
,
7
,
0
,
4
,
10
,
1
,
13
,
11
,
6
,
4
,
3
,
2
,
12
,
9
,
5
,
15
,
10
,
11
,
14
,
1
,
7
,
6
,
0
,
8
,
13
};
int
S7
[]
=
{
4
,
11
,
2
,
14
,
15
,
0
,
8
,
13
,
3
,
12
,
9
,
7
,
5
,
10
,
6
,
1
,
13
,
0
,
11
,
7
,
4
,
9
,
1
,
10
,
14
,
3
,
5
,
12
,
2
,
15
,
8
,
6
,
1
,
4
,
11
,
13
,
12
,
3
,
7
,
14
,
10
,
15
,
6
,
8
,
0
,
5
,
9
,
2
,
6
,
11
,
13
,
8
,
1
,
4
,
10
,
7
,
9
,
5
,
0
,
15
,
14
,
2
,
3
,
12
};
int
S8
[]
=
{
13
,
2
,
8
,
4
,
6
,
15
,
11
,
1
,
10
,
9
,
3
,
14
,
5
,
0
,
12
,
7
,
1
,
15
,
13
,
8
,
10
,
3
,
7
,
4
,
12
,
5
,
6
,
11
,
0
,
14
,
9
,
2
,
7
,
11
,
4
,
1
,
9
,
12
,
14
,
2
,
0
,
6
,
10
,
13
,
15
,
3
,
5
,
8
,
2
,
1
,
14
,
7
,
4
,
10
,
8
,
13
,
15
,
12
,
9
,
0
,
3
,
5
,
6
,
11
};
int
right_sub_message_permutation
[]
=
{
16
,
7
,
20
,
21
,
29
,
12
,
28
,
17
,
1
,
15
,
23
,
26
,
5
,
18
,
31
,
10
,
2
,
8
,
24
,
14
,
32
,
27
,
3
,
9
,
19
,
13
,
30
,
6
,
22
,
11
,
4
,
25
};
int
final_message_permutation
[]
=
{
40
,
8
,
48
,
16
,
56
,
24
,
64
,
32
,
39
,
7
,
47
,
15
,
55
,
23
,
63
,
31
,
38
,
6
,
46
,
14
,
54
,
22
,
62
,
30
,
37
,
5
,
45
,
13
,
53
,
21
,
61
,
29
,
36
,
4
,
44
,
12
,
52
,
20
,
60
,
28
,
35
,
3
,
43
,
11
,
51
,
19
,
59
,
27
,
34
,
2
,
42
,
10
,
50
,
18
,
58
,
26
,
33
,
1
,
41
,
9
,
49
,
17
,
57
,
25
};
void
print_char_as_binary
(
char
input
)
{
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
char
shift_byte
=
0x01
<<
(
7
-
i
);
if
(
shift_byte
&
input
)
{
printf
(
"1"
);
}
else
{
printf
(
"0"
);
}
}
}
void
generate_key
(
unsigned
char
*
key
)
{
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
key
[
i
]
=
rand
()
%
255
;
}
}
void
print_key_set
(
key_set
key_set
)
{
int
i
;
printf
(
"K:
\n
"
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
printf
(
"%02X : "
,
key_set
.
k
[
i
]);
print_char_as_binary
(
key_set
.
k
[
i
]);
printf
(
"
\n
"
);
}
printf
(
"
\n
C:
\n
"
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
printf
(
"%02X : "
,
key_set
.
c
[
i
]);
print_char_as_binary
(
key_set
.
c
[
i
]);
printf
(
"
\n
"
);
}
printf
(
"
\n
D:
\n
"
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
printf
(
"%02X : "
,
key_set
.
d
[
i
]);
print_char_as_binary
(
key_set
.
d
[
i
]);
printf
(
"
\n
"
);
}
printf
(
"
\n
"
);
}
void
generate_sub_keys
(
unsigned
char
*
main_key
,
key_set
*
key_sets
)
{
int
i
,
j
;
int
shift_size
;
unsigned
char
shift_byte
,
first_shift_bits
,
second_shift_bits
,
third_shift_bits
,
fourth_shift_bits
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
key_sets
[
0
].
k
[
i
]
=
0
;
}
for
(
i
=
0
;
i
<
56
;
i
++
)
{
shift_size
=
initial_key_permutaion
[
i
];
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
main_key
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
key_sets
[
0
].
k
[
i
/
8
]
|=
(
shift_byte
>>
i
%
8
);
}
for
(
i
=
0
;
i
<
3
;
i
++
)
{
key_sets
[
0
].
c
[
i
]
=
key_sets
[
0
].
k
[
i
];
}
key_sets
[
0
].
c
[
3
]
=
key_sets
[
0
].
k
[
3
]
&
0xF0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
key_sets
[
0
].
d
[
i
]
=
(
key_sets
[
0
].
k
[
i
+
3
]
&
0x0F
)
<<
4
;
key_sets
[
0
].
d
[
i
]
|=
(
key_sets
[
0
].
k
[
i
+
4
]
&
0xF0
)
>>
4
;
}
key_sets
[
0
].
d
[
3
]
=
(
key_sets
[
0
].
k
[
6
]
&
0x0F
)
<<
4
;
for
(
i
=
1
;
i
<
17
;
i
++
)
{
for
(
j
=
0
;
j
<
4
;
j
++
)
{
key_sets
[
i
].
c
[
j
]
=
key_sets
[
i
-
1
].
c
[
j
];
key_sets
[
i
].
d
[
j
]
=
key_sets
[
i
-
1
].
d
[
j
];
}
shift_size
=
key_shift_sizes
[
i
];
if
(
shift_size
==
1
)
{
shift_byte
=
0x80
;
}
else
{
shift_byte
=
0xC0
;
}
// Process C
first_shift_bits
=
shift_byte
&
key_sets
[
i
].
c
[
0
];
second_shift_bits
=
shift_byte
&
key_sets
[
i
].
c
[
1
];
third_shift_bits
=
shift_byte
&
key_sets
[
i
].
c
[
2
];
fourth_shift_bits
=
shift_byte
&
key_sets
[
i
].
c
[
3
];
key_sets
[
i
].
c
[
0
]
<<=
shift_size
;
key_sets
[
i
].
c
[
0
]
|=
(
second_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
c
[
1
]
<<=
shift_size
;
key_sets
[
i
].
c
[
1
]
|=
(
third_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
c
[
2
]
<<=
shift_size
;
key_sets
[
i
].
c
[
2
]
|=
(
fourth_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
c
[
3
]
<<=
shift_size
;
key_sets
[
i
].
c
[
3
]
|=
(
first_shift_bits
>>
(
4
-
shift_size
));
// Process D
first_shift_bits
=
shift_byte
&
key_sets
[
i
].
d
[
0
];
second_shift_bits
=
shift_byte
&
key_sets
[
i
].
d
[
1
];
third_shift_bits
=
shift_byte
&
key_sets
[
i
].
d
[
2
];
fourth_shift_bits
=
shift_byte
&
key_sets
[
i
].
d
[
3
];
key_sets
[
i
].
d
[
0
]
<<=
shift_size
;
key_sets
[
i
].
d
[
0
]
|=
(
second_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
d
[
1
]
<<=
shift_size
;
key_sets
[
i
].
d
[
1
]
|=
(
third_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
d
[
2
]
<<=
shift_size
;
key_sets
[
i
].
d
[
2
]
|=
(
fourth_shift_bits
>>
(
8
-
shift_size
));
key_sets
[
i
].
d
[
3
]
<<=
shift_size
;
key_sets
[
i
].
d
[
3
]
|=
(
first_shift_bits
>>
(
4
-
shift_size
));
for
(
j
=
0
;
j
<
48
;
j
++
)
{
shift_size
=
sub_key_permutation
[
j
];
if
(
shift_size
<=
28
)
{
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
key_sets
[
i
].
c
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
}
else
{
shift_byte
=
0x80
>>
((
shift_size
-
29
)
%
8
);
shift_byte
&=
key_sets
[
i
].
d
[(
shift_size
-
29
)
/
8
];
shift_byte
<<=
((
shift_size
-
29
)
%
8
);
}
key_sets
[
i
].
k
[
j
/
8
]
|=
(
shift_byte
>>
j
%
8
);
}
}
}
void
process_message
(
unsigned
char
*
message_piece
,
unsigned
char
*
processed_piece
,
key_set
*
key_sets
,
int
mode
)
{
int
i
,
k
;
int
shift_size
;
unsigned
char
shift_byte
;
unsigned
char
initial_permutation
[
8
];
memset
(
initial_permutation
,
0
,
8
);
memset
(
processed_piece
,
0
,
8
);
for
(
i
=
0
;
i
<
64
;
i
++
)
{
shift_size
=
initial_message_permutation
[
i
];
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
message_piece
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
initial_permutation
[
i
/
8
]
|=
(
shift_byte
>>
i
%
8
);
}
unsigned
char
l
[
4
],
r
[
4
];
for
(
i
=
0
;
i
<
4
;
i
++
)
{
l
[
i
]
=
initial_permutation
[
i
];
r
[
i
]
=
initial_permutation
[
i
+
4
];
}
unsigned
char
ln
[
4
],
rn
[
4
],
er
[
6
],
ser
[
4
];
int
key_index
;
for
(
k
=
1
;
k
<=
16
;
k
++
)
{
memcpy
(
ln
,
r
,
4
);
memset
(
er
,
0
,
6
);
for
(
i
=
0
;
i
<
48
;
i
++
)
{
shift_size
=
message_expansion
[
i
];
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
r
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
er
[
i
/
8
]
|=
(
shift_byte
>>
i
%
8
);
}
if
(
mode
==
DECRYPTION_MODE
)
{
key_index
=
17
-
k
;
}
else
{
key_index
=
k
;
}
for
(
i
=
0
;
i
<
6
;
i
++
)
{
er
[
i
]
^=
key_sets
[
key_index
].
k
[
i
];
}
unsigned
char
row
,
column
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
ser
[
i
]
=
0
;
}
// 0000 0000 0000 0000 0000 0000
// rccc crrc cccr rccc crrc cccr
// Byte 1
row
=
0
;
row
|=
((
er
[
0
]
&
0x80
)
>>
6
);
row
|=
((
er
[
0
]
&
0x04
)
>>
2
);
column
=
0
;
column
|=
((
er
[
0
]
&
0x78
)
>>
3
);
ser
[
0
]
|=
((
unsigned
char
)
S1
[
row
*
16
+
column
]
<<
4
);
row
=
0
;
row
|=
(
er
[
0
]
&
0x02
);
row
|=
((
er
[
1
]
&
0x10
)
>>
4
);
column
=
0
;
column
|=
((
er
[
0
]
&
0x01
)
<<
3
);
column
|=
((
er
[
1
]
&
0xE0
)
>>
5
);
ser
[
0
]
|=
(
unsigned
char
)
S2
[
row
*
16
+
column
];
// Byte 2
row
=
0
;
row
|=
((
er
[
1
]
&
0x08
)
>>
2
);
row
|=
((
er
[
2
]
&
0x40
)
>>
6
);
column
=
0
;
column
|=
((
er
[
1
]
&
0x07
)
<<
1
);
column
|=
((
er
[
2
]
&
0x80
)
>>
7
);
ser
[
1
]
|=
((
unsigned
char
)
S3
[
row
*
16
+
column
]
<<
4
);
row
=
0
;
row
|=
((
er
[
2
]
&
0x20
)
>>
4
);
row
|=
(
er
[
2
]
&
0x01
);
column
=
0
;
column
|=
((
er
[
2
]
&
0x1E
)
>>
1
);
ser
[
1
]
|=
(
unsigned
char
)
S4
[
row
*
16
+
column
];
// Byte 3
row
=
0
;
row
|=
((
er
[
3
]
&
0x80
)
>>
6
);
row
|=
((
er
[
3
]
&
0x04
)
>>
2
);
column
=
0
;
column
|=
((
er
[
3
]
&
0x78
)
>>
3
);
ser
[
2
]
|=
((
unsigned
char
)
S5
[
row
*
16
+
column
]
<<
4
);
row
=
0
;
row
|=
(
er
[
3
]
&
0x02
);
row
|=
((
er
[
4
]
&
0x10
)
>>
4
);
column
=
0
;
column
|=
((
er
[
3
]
&
0x01
)
<<
3
);
column
|=
((
er
[
4
]
&
0xE0
)
>>
5
);
ser
[
2
]
|=
(
unsigned
char
)
S6
[
row
*
16
+
column
];
// Byte 4
row
=
0
;
row
|=
((
er
[
4
]
&
0x08
)
>>
2
);
row
|=
((
er
[
5
]
&
0x40
)
>>
6
);
column
=
0
;
column
|=
((
er
[
4
]
&
0x07
)
<<
1
);
column
|=
((
er
[
5
]
&
0x80
)
>>
7
);
ser
[
3
]
|=
((
unsigned
char
)
S7
[
row
*
16
+
column
]
<<
4
);
row
=
0
;
row
|=
((
er
[
5
]
&
0x20
)
>>
4
);
row
|=
(
er
[
5
]
&
0x01
);
column
=
0
;
column
|=
((
er
[
5
]
&
0x1E
)
>>
1
);
ser
[
3
]
|=
(
unsigned
char
)
S8
[
row
*
16
+
column
];
for
(
i
=
0
;
i
<
4
;
i
++
)
{
rn
[
i
]
=
0
;
}
for
(
i
=
0
;
i
<
32
;
i
++
)
{
shift_size
=
right_sub_message_permutation
[
i
];
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
ser
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
rn
[
i
/
8
]
|=
(
shift_byte
>>
i
%
8
);
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
rn
[
i
]
^=
l
[
i
];
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
l
[
i
]
=
ln
[
i
];
r
[
i
]
=
rn
[
i
];
}
}
unsigned
char
pre_end_permutation
[
8
];
for
(
i
=
0
;
i
<
4
;
i
++
)
{
pre_end_permutation
[
i
]
=
r
[
i
];
pre_end_permutation
[
4
+
i
]
=
l
[
i
];
}
for
(
i
=
0
;
i
<
64
;
i
++
)
{
shift_size
=
final_message_permutation
[
i
];
shift_byte
=
0x80
>>
((
shift_size
-
1
)
%
8
);
shift_byte
&=
pre_end_permutation
[(
shift_size
-
1
)
/
8
];
shift_byte
<<=
((
shift_size
-
1
)
%
8
);
processed_piece
[
i
/
8
]
|=
(
shift_byte
>>
i
%
8
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录