#include "tcp_client.h" #include "bolt/datagram.h" #include "tcp_client_map.h" #include "utils.h" #include "spdlog/spdlog.h" #include #include void TcpClientBolt::onConnection(const hv::SocketChannelPtr &channel) { char buff[2]; buff[0] = BOLT_CHANNEL_CMD_TCP_HANDSHAKE_RESPONSE; buff[1] = BOLT_TCP_HANDSHAKE_SUCESS; int len = sizeof(buff); PACK_TUNNEL_DATA(boltdata, boltdata_len, BOLT_VERSION, BOLT_RESERVE, BOLT_PAYLOAD_TYPE_CMD, t_addr.sin_addr.s_addr, t_addr.sin_port, u_addr.sin_addr.s_addr, u_addr.sin_port, session_id, 0, 0, buff, len); hio_write(io, boltdata, boltdata_len); spdlog::info("BOLT_CHANNEL_CMD_TCP_HANDSHAKE_REQUEST: t_addr={}:{}, u_addr={}:{} ==> connect succ", inet_ntoa(t_addr.sin_addr), htons(t_addr.sin_port), inet_ntoa(u_addr.sin_addr), htons(u_addr.sin_port)); } void TcpClientBolt::onRecv(const hv::SocketChannelPtr &channel, hv::Buffer *buf) { auto config = TcpClientMap::getInstance().get(session_id); if (config) { if (config->encrypt) { switch (config->ept_type) { case CRYPT_TYPE::XOR: xor_::crypt((char *)buf->data(), buf->size(), config->ept_key); break; default: break; } } hio_write(io, buf->data(), buf->size()); } spdlog::info("t_addr={}:{}, u_addr={}:{} onRecv==> {}={}", inet_ntoa(t_addr.sin_addr), htons(t_addr.sin_port), inet_ntoa(u_addr.sin_addr), htons(u_addr.sin_port), buf->len, (const char*)buf->data()); } void TcpClientBolt::onWrited(const hv::SocketChannelPtr &channel, hv::Buffer *buf) { if (channel.get()->isWriteComplete()) { spdlog::info("t_addr={}:{}, u_addr={}:{} isWriteComplete==> {}={}", inet_ntoa(t_addr.sin_addr), htons(t_addr.sin_port), inet_ntoa(u_addr.sin_addr), htons(u_addr.sin_port), buf->len, (const char*)buf->data()); } } void TcpClientBolt::onDisConnection(const hv::SocketChannelPtr &channel) { if (is_bolt_server) { TcpClientMap::getInstance().remove(session_id); } hio_close(io); } bool TcpClientBolt::handShake(void *buf, int readbytes) { if (readbytes > 0) { UNPACK_TUNNEL_DATA(dest, dest_len, ver, res, type, t_ip, t_port, u_ip, u_port, session_id, extend, extend_len, buf, readbytes) if (ver == BOLT_VERSION && res == BOLT_RESERVE) { if (type == BOLT_PAYLOAD_TYPE_CMD) { if (dest_len == 1 && dest[0] == BOLT_CHANNEL_CMD_TCP_HANDSHAKE_REQUEST) { this->t_addr.sin_family = AF_INET; this->t_addr.sin_addr.s_addr = t_ip; this->t_addr.sin_port = t_port; this->u_addr.sin_family = AF_INET; this->u_addr.sin_addr.s_addr = u_ip; this->u_addr.sin_port = u_port; this->session_id = session_id; this->config = TcpClientMap::getInstance().get(session_id); if (!this->config) { char buff[1] = {BOLT_CHANNEL_CMD_INVALID_RESPONSE}; int len = sizeof(buff); PACK_TUNNEL_DATA(boltdata, boltdata_len, BOLT_VERSION, BOLT_RESERVE, BOLT_PAYLOAD_TYPE_CMD, t_addr.sin_addr.s_addr, t_addr.sin_port, u_addr.sin_addr.s_addr, u_addr.sin_port, session_id, 0, 0, buff, len); hio_write(io, buff, len); hio_close_async(io); return false; } if (!this->connect((struct sockaddr *)&t_addr)) { spdlog::info("[TCP]BOLT_CHANNEL_CMD_TCP_HANDSHAKE_REQUEST: t_addr={}:{}, u_addr={}:{} ==> connect fail", inet_ntoa(t_addr.sin_addr), htons(t_addr.sin_port), inet_ntoa(u_addr.sin_addr), htons(u_addr.sin_port)); char buff[2]; buff[0] = BOLT_CHANNEL_CMD_TCP_HANDSHAKE_RESPONSE; buff[1] = BOLT_TCP_HANDSHAKE_FAIL_TIMEOUT; int len = sizeof(buff); PACK_TUNNEL_DATA(boltdata, boltdata_len, BOLT_VERSION, BOLT_RESERVE, BOLT_PAYLOAD_TYPE_CMD, t_addr.sin_addr.s_addr, t_addr.sin_port, u_addr.sin_addr.s_addr, u_addr.sin_port, session_id, 0, 0, buff, len); hio_write(io, buff, len); hio_close_async(io); return false; } return true; } else if (dest_len == 73 && dest[0] == BOLT_CHANNEL_CMD_BIND_REQUEST) { UNPACK_BIND_DATA(command, request_id, signal_id, session_id, data_st, dest, dest_len) this->session_id = session_id; tcpBoltConfig config; config.request_id = request_id; config.session_id = session_id; config.data_st = data_st; config.signal_id = signal_id; if (extend_len >= 5) { if (strcmp(extend, "ept=1") == 0) { config.encrypt = true; } } config.ept_type = config.encrypt ? CRYPT_TYPE::XOR : CRYPT_TYPE::NONE; config.ept_key = config.encrypt ? generateRandomKey() : 0; spdlog::info("[TCP]BOLT_CHANNEL_CMD_BIND_REQUEST: requestId:{}, session_id:{}, encrypt:{}", request_id, session_id, config.encrypt); GENERATE_DECRYPT_KEY(extend_response, extend_response_len, config.ept_type, config.ept_key) uint32_t result = BOLT_BIND_RESPONSE_CODE_SUCESS; PACK_BIND_RESPONSE_DATA(bind_response, bind_response_len, BOLT_CHANNEL_CMD_BIND_RESPONSE, request_id, session_id, result) PACK_TUNNEL_DATA(response, response_len, BOLT_VERSION, BOLT_RESERVE, BOLT_PAYLOAD_TYPE_CMD, 0, 0, 0, 0, session_id, extend_response, extend_response_len, bind_response, bind_response_len) hio_write(io, response, response_len); TcpClientMap::getInstance().add(session_id, config); is_bolt_server = true; } else if (dest_len == 9 && dest[0] == BOLT_CHANNEL_CMD_UNBIND_REQUEST) { UNPACK_UNBIND_DATA(command, session_id, code, dest, dest_len) TcpClientMap::getInstance().remove(session_id); this->close(); hio_close_async(io); spdlog::info("[TCP]BOLT_CHANNEL_CMD_UNBIND_REQUEST: requestId:{}, session_id:{} t_addr={}:{}, u_addr={}:{}", config->request_id, config->session_id, inet_ntoa(t_addr.sin_addr), htons(t_addr.sin_port), inet_ntoa(u_addr.sin_addr), htons(u_addr.sin_port)); } } } } return false; } bool TcpClientBolt::connect(struct sockaddr *addr) { int connfd = cli.createsocket(addr); if (connfd < 0) { return false; } cli.onConnection = [this](const hv::SocketChannelPtr &channel) { std::string peeraddr = channel->peeraddr(); if (channel->isConnected()) { spdlog::info("connected to {}! connfd={}\n", peeraddr.c_str(), channel->fd()); onConnection(channel); } else { spdlog::info("disconnected to {}! connfd={}\n", peeraddr.c_str(), channel->fd()); onDisConnection(channel); } }; cli.onMessage = [this](const hv::SocketChannelPtr &channel, hv::Buffer *buf) { spdlog::info("<<< len:{} : {}", (int)buf->size(), (char *)buf->data()); onRecv(channel, buf); }; cli.onWriteComplete = [this](const hv::SocketChannelPtr &channel, hv::Buffer *buf) { spdlog::info(">>> len:{} : {}", (int)buf->size(), (char *)buf->data()); onWrited(channel, buf); }; cli.start(); return true; } int TcpClientBolt::send(char *data, int size) { if (cli.isConnected()) { auto config = TcpClientMap::getInstance().get(session_id); if (config) { if (config->encrypt) { switch (config->ept_type) { case CRYPT_TYPE::XOR: xor_::crypt(data, size, config->ept_key); break; default: break; } } } return cli.send(data, size); } else { return -1; } } void TcpClientBolt::close() { spdlog::info("TcpClientBolt::close()\n"); cli.stop(); }