From dd25cb57e4ad8025fbc11ace36f921abd2758ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=98=95?= Date: Fri, 20 Oct 2023 14:47:24 +0800 Subject: [PATCH] =?UTF-8?q?OCT=201.=20=E6=9B=B4=E6=8D=A2HTTP=20Client?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- app/src/main/cpp/CMakeLists.txt | 6 +- app/src/main/cpp/http/http-client.cpp | 267 ----- app/src/main/cpp/http/http-client.h | 5 - app/src/main/cpp/include/sion.h | 1036 +++++++++++++++++ app/src/main/cpp/native-lib.cpp | 1 - app/src/main/cpp/srcs/scc-service.cpp | 162 ++- .../com/example/sccproxy/MainActivity.java | 112 +- 8 files changed, 1206 insertions(+), 385 deletions(-) delete mode 100644 app/src/main/cpp/http/http-client.cpp delete mode 100644 app/src/main/cpp/http/http-client.h create mode 100644 app/src/main/cpp/include/sion.h diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1c304db..a92e16f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,7 +16,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" ndk { - //abiFilters.add("armeabi-v7a") + abiFilters.add("armeabi-v7a") } } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 1dec23e..176aa3f 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -5,8 +5,6 @@ # Sets the minimum CMake version required for this project. cmake_minimum_required(VERSION 3.22.1) -OPTION(SCG_ENABLE "Enable SCG Proxy Service" OFF) - # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, # Since this is the top level CMakeLists.txt, the project name is also accessible # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level @@ -32,14 +30,14 @@ ADD_DEFINITIONS(-D_LINUX) # used in the AndroidManifest.xml file. ADD_LIBRARY(${CMAKE_PROJECT_NAME} SHARED # List C/C++ source files with relative paths to this CMakeLists.txt. - native-lib.cpp http/http-client.cpp srcs/ipcalc.cpp srcs/scc-service.cpp srcs/tunnel-proxy.cpp cJSON/cJSON.c ${C_HEADS}) + native-lib.cpp srcs/ipcalc.cpp srcs/scc-service.cpp srcs/tunnel-proxy.cpp cJSON/cJSON.c ${C_HEADS}) MESSAGE(STATUS "SRC DIRECTORY: ${CMAKE_SOURCE_DIR}") # Specifies libraries CMake should link to your target library. You # can link libraries from various origins, such as libraries defined in this # build script, prebuilt third-party libraries, or Android system libraries. -IF (SCG_ENABLE) +IF (TRUE) ADD_DEFINITIONS(-DSCG_ON) TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} # List libraries link to the target library diff --git a/app/src/main/cpp/http/http-client.cpp b/app/src/main/cpp/http/http-client.cpp deleted file mode 100644 index 6ca1629..0000000 --- a/app/src/main/cpp/http/http-client.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "http-client.h" -#include "sccproxy.h" -#include "scg-service.h" - -#define MY_HTTP_DEFAULT_PORT 80 - -#define BUFFER_SIZE 1024 -#define HTTP_POST "POST /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n"\ - "Content-Type:application/json\r\nContent-Length: %d\r\n\r\n%s" -#define HTTP_GET "GET /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n" - -static void send_scg_head(int sock, int vmId) { - int ret; - unsigned char vmid[4]; - unsigned char *p; - const unsigned int id = htonl(vmId); - const auto svrId = static_cast(WG_CTRL_SCG_ID); - unsigned char scgProxy[] = {0x01, // VERSION - 0x09, // Length - 0xF0, // ++++++ INFO[0] TYPE - 0x04, // INFO[0] LENGTH - 0, // INFO[0] VMID[0] - 0, // INFO[0] VMID[1] - 0, // INFO[0] VMID[2] - 0, // INFO[0] VMID[3] - 0xF1, // INFO[1] TYPE - 0x01, // INFO[1] LENGTH - svrId}; // ------ INFO[1] SCG Service ID - - p = scgProxy; - memcpy(vmid, &id, 4); - scgProxy[4] = vmid[0]; - scgProxy[5] = vmid[1]; - scgProxy[6] = vmid[2]; - scgProxy[7] = vmid[3]; - - ret = send(sock, reinterpret_cast(p), sizeof(scgProxy), 0); - - if (ret != sizeof(scgProxy)) { - ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Service Connected To SCG Server(vmid = %d, SCGAppId = %d) error: %d\n", - vmId, WG_CTRL_SCG_ID, ret); - } - - ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "Service Connected To SCG Server:vmid = %d, SCGAppId = %d: %d\n", - vmId, WG_CTRL_SCG_ID, sock); -} - -static int http_tcpclient_create(const char *host, int port) { - struct hostent *he; - struct sockaddr_in server_addr {}; - int socket_fd; - - if ((he = gethostbyname(host)) == nullptr) { - return -1; - } - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(port); - server_addr.sin_addr = *((struct in_addr *) he->h_addr); - - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - return -1; - } - - if (connect(socket_fd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) == -1) { - return -1; - } - - //if(get_scg_cur_vmid() > 0) { - send_scg_head(socket_fd, get_scg_cur_vmid()); - //} - - return socket_fd; -} - -static void http_tcpclient_close(int socket) { - close(socket); -} - -static int http_parse_url(const char *url, char *host, char *file, int *port) { - char *ptr1, *ptr2; - int len = 0; - if (!url || !host || !file || !port) { - return -1; - } - - ptr1 = (char *) url; - - if (!strncmp(ptr1, "http://", strlen("http://"))) { - ptr1 += strlen("http://"); - } else { - return -1; - } - - ptr2 = strchr(ptr1, '/'); - if (ptr2) { - len = strlen(ptr1) - strlen(ptr2); - memcpy(host, ptr1, len); - host[len] = '\0'; - if (*(ptr2 + 1)) { - memcpy(file, ptr2 + 1, strlen(ptr2) - 1); - file[strlen(ptr2) - 1] = '\0'; - } - } else { - memcpy(host, ptr1, strlen(ptr1)); - host[strlen(ptr1)] = '\0'; - } - //get host and ip - ptr1 = strchr(host, ':'); - if (ptr1) { - *ptr1++ = '\0'; - *port = atoi(ptr1); - } else { - *port = MY_HTTP_DEFAULT_PORT; - } - - return 0; -} - - -static int http_tcpclient_recv(int socket, char *lpbuff) { - int recvnum = 0; - - recvnum = recv(socket, lpbuff, BUFFER_SIZE * 4, 0); - - return recvnum; -} - -static int http_tcpclient_send(int socket, char *buff, int size) { - int sent = 0, tmpres = 0; - - while (sent < size) { - tmpres = send(socket, buff + sent, size - sent, 0); - if (tmpres == -1) { - return -1; - } - sent += tmpres; - } - return sent; -} - -static char *http_parse_result(const char *lpbuf) { - char *ptmp = nullptr; - char *response = nullptr; - ptmp = (char *) strstr(lpbuf, "HTTP/1.1"); - if (!ptmp) { - printf("http/1.1 not faind\n"); - return nullptr; - } - if (atoi(ptmp + 9) != 200) { - printf("result:\n%s\n", lpbuf); - return nullptr; - } - - ptmp = (char *) strstr(lpbuf, "\r\n\r\n"); - if (!ptmp) { - printf("ptmp is nullptr\n"); - return nullptr; - } - response = (char *) malloc(strlen(ptmp) + 1); - if (!response) { - printf("malloc failed \n"); - return nullptr; - } - strcpy(response, ptmp + 4); - return response; -} - -char *http_post(const char *url, const char *post_str) { - - char post[BUFFER_SIZE] = {'\0'}; - int socket_fd = -1; - char lpbuf[BUFFER_SIZE * 4] = {'\0'}; - char *ptmp; - char host_addr[BUFFER_SIZE] = {'\0'}; - char file[BUFFER_SIZE] = {'\0'}; - int port = 0; - int len = 0; - char *response = nullptr; - - if (!url || !post_str) { - printf(" failed!\n"); - return nullptr; - } - - if (http_parse_url(url, host_addr, file, &port)) { - printf("http_parse_url failed!\n"); - return nullptr; - } - //printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port); - - socket_fd = http_tcpclient_create(host_addr, port); - if (socket_fd < 0) { - printf("http_tcpclient_create failed\n"); - return nullptr; - } - - sprintf(lpbuf, HTTP_POST, file, host_addr, port, static_cast(strlen(post_str)), post_str); - - if (http_tcpclient_send(socket_fd, lpbuf, static_cast(strlen(lpbuf))) < 0) { - printf("http_tcpclient_send failed..\n"); - return nullptr; - } - //printf("发送请求:\n%s\n",lpbuf); - - /*it's time to recv from server*/ - if (http_tcpclient_recv(socket_fd, lpbuf) <= 0) { - printf("http_tcpclient_recv failed\n"); - return nullptr; - } - - http_tcpclient_close(socket_fd); - - return http_parse_result(lpbuf); -} - -char *http_get(const char *url) { - - char post[BUFFER_SIZE] = {'\0'}; - int socket_fd = -1; - char lpbuf[BUFFER_SIZE * 4] = {'\0'}; - char *ptmp; - char host_addr[BUFFER_SIZE] = {'\0'}; - char file[BUFFER_SIZE] = {'\0'}; - int port = 0; - int len = 0; - - if (!url) { - printf(" failed!\n"); - return nullptr; - } - - if (http_parse_url(url, host_addr, file, &port)) { - printf("http_parse_url failed!\n"); - return nullptr; - } - //printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port); - - socket_fd = http_tcpclient_create(host_addr, port); - if (socket_fd < 0) { - printf("http_tcpclient_create failed\n"); - return nullptr; - } - - sprintf(lpbuf, HTTP_GET, file, host_addr, port); - - if (http_tcpclient_send(socket_fd, lpbuf, static_cast(strlen(lpbuf))) < 0) { - printf("http_tcpclient_send failed..\n"); - return nullptr; - } -// printf("发送请求:\n%s\n",lpbuf); - - if (http_tcpclient_recv(socket_fd, lpbuf) <= 0) { - printf("http_tcpclient_recv failed\n"); - return nullptr; - } - http_tcpclient_close(socket_fd); - - return http_parse_result(lpbuf); -} \ No newline at end of file diff --git a/app/src/main/cpp/http/http-client.h b/app/src/main/cpp/http/http-client.h deleted file mode 100644 index 244a7af..0000000 --- a/app/src/main/cpp/http/http-client.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - - -char * http_get(const char *url); -char * http_post(const char *url,const char * post_str); \ No newline at end of file diff --git a/app/src/main/cpp/include/sion.h b/app/src/main/cpp/include/sion.h new file mode 100644 index 0000000..b310797 --- /dev/null +++ b/app/src/main/cpp/include/sion.h @@ -0,0 +1,1036 @@ +#pragma once + +#define SION_DISABLE_SSL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#pragma comment(lib, "ws2_32.lib") +#else + +#include +#include +#include +#include +#include + +#endif +#ifndef SION_DISABLE_SSL + +#include +#include +#include + +#endif // !SION_DISABLE_SSL +namespace sion { + class Request; + + class Response; + + class Error : public std::exception { + std::string msg; + + public: + Error() {} + + Error(std::string msg) : msg(msg) {} + + ~Error() {} + + const char *what() const + + noexcept { return msg.c_str(); } + }; + + class AsyncAwaitTimeout : public Error { + public: + AsyncAwaitTimeout(std::string msg = "await timeout") : Error(msg) {} + }; + + class PeerConnectionClose : public Error { + public: + PeerConnectionClose(std::string msg = "对方关闭了连接") : Error(msg) {} + }; + + class String : public std::string { + public: + String() {}; + + ~String() {}; + + template + String(T &&arg) : std::string(std::forward(arg)) {} + + String(int arg) : std::string(std::to_string(arg)) {} + + String(unsigned long arg) : std::string(std::to_string(arg)) {} + + String(double arg) : std::string(std::to_string(arg)) {} + + String(bool arg) { (*this) = arg ? "true" : "false"; } + + String(char arg) { + (*this) = " "; + (*this)[0] = arg; + } + + // 使用字符串分割 + // flag 分割标志,返回的字符串向量会剔除,flag不要用char,会重载不明确 + // num 分割次数,默认-1即分割到结束,例num=1,返回开头到flag,flag到结束size=2的字符串向量 + // skip_empty 跳过空字符串,即不压入length==0的字符串 + std::vector Split(String flag, int num = -1, bool skip_empty = true) const { + std::vector data_set; + auto push_data = [&](String line) { + if (line.length() != 0 || !skip_empty) { + data_set.push_back(line); + } + }; + auto pos = FindAll(flag, num); + if (pos.size() == 0) { + return std::vector({*this}); + } + for (auto i = 0; i < static_cast(pos.size()) + 1; i++) { + if (data_set.size() == num && static_cast(pos.size()) > num && num != -1) { // 满足数量直接截到结束 + push_data(substr(pos[data_set.size()] + flag.size())); + break; + } + if (i == 0) { // 第一个数的位置不是0的话补上 + push_data(substr(0, pos[0])); + } else if (i != pos.size()) { + int left = pos[i - 1] + static_cast(flag.length()); + int right = pos[i] - left; + push_data(substr(left, right)); + } else { // 最后一个标志到结束 + push_data(substr(*(--pos.end()) + flag.size())); + } + } + return data_set; + } + + // 清除前后的字符 + // target 需要清除的字符默认空格 + String Trim(String empty_set = " \n\r") const { + int len = static_cast(length()); + int left = 0; + while (left < len && IncludeSym(empty_set, (*this)[left])) { + left++; + } + if (left >= len) { + return *this; + } + int right = len - 1; + while (right > 0 && IncludeSym(empty_set, (*this)[right])) { + right--; + } + return substr(left, right - left + 1); + } + + String ToLowerCase() { + String s = *this; + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); + return s; + } + + String ToUpperCase() { + String s = *this; + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); }); + return s; + } + + static bool IncludeSym(String syms, char sym) { + for (auto i: syms) { + if (i == sym) { + return true; + } + } + return false; + } + + // 包含字母 + bool HasLetter() { + for (auto &x: *this) { + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')) { + return true; + } + } + return false; + } + + // 返回搜索到的所有位置 + // flag 定位标志 + // num 搜索数量,默认直到结束 + std::vector FindAll(String flag, int num = -1) const { + std::vector result; + auto pos = find(flag); + auto flag_offset = flag.length() == 0 ? 1 : flag.length(); + while (pos != -1 && result.size() != num) { + result.push_back(static_cast(pos)); + pos = find(flag, *(--result.end()) + flag_offset); + } + return result; + } + + // 字符串替换 + // oldStr 被替换的字符串 + // newStr 新换上的字符串 + // count 替换次数,默认1,大于0时替换到足够次数或找不到旧字符串为止,小于0时替换到结束 + String &Replace(String old_str, String new_str, int count = 1) { + if (count == 0) { + return *this; + } + auto pos = find(old_str); + if (pos == std::string::npos) { + return *this; + } + replace(pos, old_str.length(), new_str); + return Replace(old_str, new_str, count < 0 ? -1 : count - 1); + } + }; + + template + void Throw(String msg = "") { throw ExceptionType(msg); } + + template + void check( + bool condition, String msg = "", std::function recycle = [] {}) { + if (!condition) { + recycle(); + Throw(msg); + } + } + + using Socket = int; + + static String GetIpByHost(String hostname) { + addrinfo hints, *res; + in_addr addr; + int err; + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET; // ipv4 + if ((err = getaddrinfo(hostname.c_str(), NULL, &hints, &res)) != 0) { +#if _WIN32 + auto str_err = gai_strerrorA(err); +#else + auto str_err = gai_strerror(err); +#endif // _WIN32 + + Throw("错误" + std::to_string(err) + String(str_err)); + } + addr.s_addr = ((sockaddr_in *) (res->ai_addr))->sin_addr.s_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &addr, str, sizeof(str)); + freeaddrinfo(res); + return str; + } + + static Socket GetSocket() { +#ifdef _WIN32 + // 初始化。,WSA windows异步套接字 + WSADATA inet_WsaData; // + const auto result = WSAStartup(MAKEWORD(2, 0), &inet_WsaData); // socket2.0版本 + switch (result) + { + case WSASYSNOTREADY: + WSACleanup(); + Throw("底层网络子系统尚未准备好进行网络通信"); + break; + case WSAVERNOTSUPPORTED: + WSACleanup(); + Throw("此特定 Windows 套接字实现不提供请求的 Windows 套接字支持版本"); + break; + case WSAEINPROGRESS: + WSACleanup(); + Throw("正在进行阻塞的 Windows Sockets 1.1 操作"); + break; + case WSAEPROCLIM: + WSACleanup(); + Throw("已达到 Windows 套接字实现支持的任务数限制"); + break; + } + + if (LOBYTE(inet_WsaData.wVersion) != 2 || HIBYTE(inet_WsaData.wVersion) != 0) + { // 高位字节指明副版本、低位字节指明主版本 + WSACleanup(); + Throw("wsa初始化错误"); + } +#endif + auto tcp_socket = socket(AF_INET, SOCK_STREAM, 0); // ipv4,tcp,tcp或udp该参数可为0 + return tcp_socket; + } + + const String crlf = "\r\n"; + const String crlf_crlf = "\r\n\r\n"; + + static void PushStr2Vec(const String &str, std::vector &vec) { vec.insert(vec.end(), str.begin(), str.end()); } + + namespace Payload { + struct Binary { + std::vector data; + String file_name; + String type; + }; + + class FormData { + std::vector>> + data_; + String boundary_; + + public: + FormData() { boundary_ = "----SionBoundary" + std::to_string(std::uintptr_t(this)); } + + ~FormData() {} + + void Append(String name, Binary value) { + std::vector res; + String filename = value.file_name.size() ? "; filename=\"" + value.file_name + "\"" : ""; + String str = "--" + boundary_ + crlf; + str += "Content-Disposition: form-data; name=\"" + name + "\""; + str += filename; + str += crlf; + if (value.type != "") { + str += "Content-type: " + value.type; + str += crlf; + } + str += crlf; + PushStr2Vec(str, res); + res.insert(res.end(), value.data.begin(), value.data.end()); + PushStr2Vec(crlf, res); + data_.push_back({name, res}); + } + + void Append(String name, String value) { + std::vector res; + String str = "--" + boundary_ + crlf; + str += "Content-Disposition: form-data; name=\"" + name + "\"" + crlf; + str += crlf; + str += value; + str += crlf; + PushStr2Vec(str, res); + data_.push_back({name, res}); + } + + bool Remove(String key) { + for (size_t i = 0; i < data_.size(); i++) { + if (data_[i].first == key) { + data_.erase(data_.begin() + i); + return true; + } + } + return false; + } + + const std::vector>> & + + Data() const { return data_; } + + String GetContentType() { return "multipart/form-data; boundary=" + boundary_; } + + std::vector Serialize() { + std::vector res; + for (auto &i: data_) { + res.insert(res.end(), i.second.begin(), i.second.end()); + } + res.push_back('-'); + res.push_back('-'); + PushStr2Vec(boundary_, res); + res.push_back('-'); + res.push_back('-'); + return res; + } + }; + } // namespace Payload + + class Header { + public: + using RawT = typename std::vector>; + + Header() {}; + + ~Header() {}; + + const RawT &Data() const { return data; } + + bool Remove(String key) { + for (size_t i = 0; i < data.size(); i++) { + if (data[i].first == key) { + data.erase(data.begin() + i); + return true; + } + } + return false; + } + + void RemoveAll(String key) { + while (Remove(key)) { + } + } + + Header(const RawT &other) { data = other; } + + // 添加一个键值对到头中 + void Add(String k, String v) { data.push_back({k, v}); } + + // 获取头的键所对应的所有值 + std::vector GetAll(String key) const { + key = key.ToLowerCase(); + std::vector res; + for (auto &i: data) { + if (i.first == key) { + res.push_back(i.second); + } + } + return res; + } + + // 获取头的键所对应的值,以最后一个为准 + String Get(String key) const { + key = key.ToLowerCase(); + for (int i = static_cast(data.size()) - 1; i >= 0; i--) { + if (data[i].first == key) { + return data[i].second; + } + } + return ""; + } + + private: + RawT data; + }; + + enum class Method { + Get, + Post, + Put, + Delete + }; + + class Response { + friend Request; + bool is_chunked_ = false; // 是否分块编码 + int content_length_ = 0; // 正文长度 + std::vector source_; // 源响应报文 + String protocol_version_; + String code_; + String status_; + std::vector body_; // 响应体 + Header response_header_; // 响应头 + public: + Response() {}; + + ~Response() {}; + + Response(std::vector source) { + source_ = source; + ParseHeader(); + ParseBody(); + } + + const std::vector &Body() const { return body_; } + + const String Code() const { return code_; }; + + const String Status() const { return status_; }; + + const int ContentLength() const { return content_length_; }; + + String StrBody() { return body_.size() == 0 ? "" : std::string(body_.data(), 0, body_.size()); } + + const Header &GetHeader() const { return response_header_; }; + + private: + size_t resp_body_start_pos_ = -1; + + String Sourse2Str() { return source_.size() == 0 ? "" : std::string(source_.data(), 0, source_.size()); } + + bool CanParseHeader() { + auto buf_str = Sourse2Str(); + if (resp_body_start_pos_ == -1 && buf_str.find(crlf_crlf) != -1) { + resp_body_start_pos_ = buf_str.find(crlf_crlf) + 4; + } + return resp_body_start_pos_ != std::string::npos; + } + + void ParseHeader() { + String buf_str = Sourse2Str(); + auto header_str = buf_str.substr(0, resp_body_start_pos_); + auto data = String(header_str).Split(crlf); + if (data.size() == 0) { + return; + } + // 第一行 + auto first_line = data[0].Split(" ", 2); + check(first_line.size() == 3, "解析错误\n" + buf_str); + protocol_version_ = first_line[0].Trim(); + code_ = first_line[1].Trim(); + status_ = first_line[2].Trim(); + data.erase(data.begin()); + // 头 + for (auto &x: data) { + auto pair = x.Split(":", 1); + if (pair.size() == 2) { + response_header_.Add(pair[0].Trim().ToLowerCase(), pair[1].Trim()); + } + } + String content_len = response_header_.Get("content-length"); + content_length_ = content_len != "" ? stoi(content_len) : content_length_; + is_chunked_ = response_header_.Get("Transfer-Encoding") == "chunked"; + body_.insert(body_.end(), source_.begin() + resp_body_start_pos_, source_.end()); + } + + void ParseBody() { + const auto &sc = body_; + if (sc.size() == 0 || !is_chunked_) { + return; + } + std::vector pure_source_char; + // 获取下一个\r\n的位置 + int crlf_pos = 0; + auto get_next_crlf = [&](int leap) { + for (int i = crlf_pos + leap; i < static_cast(sc.size() - 1); i++) { + if (sc[i] == '\r' && sc[i + 1] == '\n') { + crlf_pos = i; + return i; + } + } + return -1; + }; + int left = -2; // 这里-2是因为第一个数量是400\r\n这样的,而其它的是\r\n400\r\n。所以要对第一次进行补偿 + int right = get_next_crlf(0); + while (left != -1 && right != -1) { + auto count = std::string(sc.begin() + 2 + left, sc.begin() + right); // 每个分块开头写的数量 + auto count_num = stoi(count, nullptr, 16); // 那数量是16进制 + if (count_num == 0) // 最后一个 0\r\n\r\n,退出 + { + break; + } + auto chunked_start = sc.begin() + right + 2; // 每个分块正文的开始位置 + pure_source_char.insert(pure_source_char.end(), chunked_start, chunked_start + count_num); + left = get_next_crlf(count_num + 2); // 更新位置lpv + right = get_next_crlf(1); + } + body_ = pure_source_char; + content_length_ = static_cast(pure_source_char.size()); + } + }; + + struct HttpProxy { + int port{}; + String host; + }; + + class Request { + typedef void (*POSTSOCKETCONNECTCB)(Socket sock); + + std::vector source_; + String method_; + String path_; + String protocol_; + String ip_; + String url_; + String host_; + std::vector request_body_; + String protocol_version_ = "HTTP/1.1"; + Header request_header_; + HttpProxy proxy_; + bool enable_proxy_ = false; + int port_ = 80; + + POSTSOCKETCONNECTCB _postConnCb = nullptr; + + public: + Request() {}; + + ~Request() {}; + + Request &SetHttpMethod(sion::Method method) { + switch (method) { + case Method::Get: + method_ = "GET"; + break; + case Method::Post: + method_ = "POST"; + break; + case Method::Put: + method_ = "PUT"; + break; + case Method::Delete: + method_ = "DELETE"; + break; + } + return *this; + } + + Request &SetHttpMethod(String other) { + method_ = other; + return *this; + } + + Request &SetUrl(String url) { + url_ = url; + return *this; + } + + Request &SetConnectedCb(POSTSOCKETCONNECTCB cb) { + _postConnCb = cb; + return *this; + } + + Request &SetBody(String body) { + request_body_.clear(); + PushStr2Vec(body, request_body_); + return *this; + } + + Request &SetBody(Payload::Binary body) { + request_body_.clear(); + request_body_.insert(request_body_.begin(), body.data.begin(), body.data.end()); + if (body.type != "") { + request_header_.RemoveAll("Content-Type"); + request_header_.Add("Content-Type", body.type); + } + return *this; + } + + Request &SetBody(Payload::FormData body) { + request_body_ = body.Serialize(); + request_header_.RemoveAll("Content-Type"); + request_header_.Add("Content-Type", body.GetContentType()); + return *this; + } + + Request &SetHeader(Header header) { + request_header_ = header; + return *this; + } + + Request &SetHeader(String k, String v) { + request_header_.Add(k, v); + return *this; + } + + Request &SetProxy(HttpProxy proxy) { + enable_proxy_ = true; + proxy_ = proxy; + return *this; + } + + Response Send(sion::Method method, String url) { + SetHttpMethod(method); + return Send(url); + } + + Response Send() { return Send(url_); } + +#ifndef SION_DISABLE_SSL + private: + Response SendBySSL(Socket socket) { + SSL_library_init(); + auto method = TLS_method(); + auto ssl_ctx = SSL_CTX_new(method); + auto ssl = SSL_new(ssl_ctx); + check(ssl != nullptr && ssl_ctx != nullptr, "openssl初始化异常"); + SSL_set_fd(ssl, socket); + SSL_connect(ssl); + SSL_write(ssl, source_.data(), int(source_.size())); + auto resp = ReadResponse(socket, ssl); + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ssl_ctx); + return resp; + } + +#endif + public: + Response Send(String url) { + check(method_.length(), "请求方法未定义"); + std::smatch m; +#ifdef SION_DISABLE_SSL + bool enable_ssl = false; +#else + bool enable_ssl = true; +#endif + if (enable_ssl || enable_proxy_) { + std::regex url_parse(R"(^(http|https)://([\w.-]*):?(\d*)(/?.*)$)"); + regex_match(url, m, url_parse); + check(m.size() == 5, "url格式不对或者是用了除http(s)外的协议"); + protocol_ = m[1]; + port_ = m[3].length() == 0 ? (protocol_ == "http" ? 80 : 443) : stoi(m[3]); + } else { + std::regex url_parse(R"(^(http)://([\w.-]*):?(\d*)(/?.*)$)"); + regex_match(url, m, url_parse); + check(m.size() == 5, "url格式不对或者是用了除http外的协议"); + protocol_ = m[1]; + port_ = m[3].length() == 0 ? 80 : stoi(m[3]); + } + host_ = m[2]; + path_ = m[4].length() == 0 ? "/" : m[4].str(); + Socket socket = GetSocket(); + try { + Connection(socket, host_); + BuildRequestString(); + if (protocol_ == "http" || enable_proxy_) { + send(socket, source_.data(), static_cast(source_.size()), 0); + return ReadResponse(socket); + } +#ifndef SION_DISABLE_SSL + else // if (protocol_ == "https") + { + return SendBySSL(socket); + } +#endif + } + catch (const std::exception &e) { +#ifdef _WIN32 + WSACleanup(); +#endif + Throw(e.what()); + } + throw Error("unreachable code"); + } + + private: + void BuildRequestString() { + request_header_.Add("Host", host_); + request_header_.Add("Content-Length", std::to_string(request_body_.size())); + auto request_target = enable_proxy_ ? url_ : path_; + String source_str = method_ + " " + request_target + " " + protocol_version_ + crlf; + for (auto &x: request_header_.Data()) { + source_str += x.first + ": " + x.second + crlf; + } + source_str += crlf; + PushStr2Vec(source_str, source_); + source_.insert(source_.end(), request_body_.begin(), request_body_.end()); + } + + void Connection(Socket socket, String host) { + in_addr sa{}; + ip_ = host.HasLetter() ? GetIpByHost(host) : host; + auto target_ip = enable_proxy_ ? (proxy_.host.HasLetter() ? GetIpByHost(proxy_.host) : proxy_.host) : ip_; + check((inet_pton(AF_INET, target_ip.c_str(), &sa) != -1), "地址转换错误"); + sockaddr_in saddr{}; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(enable_proxy_ ? proxy_.port : port_); + saddr.sin_addr = sa; + if (::connect(socket, (sockaddr *) &saddr, sizeof(saddr)) != 0) { + String err = "连接失败:\n"; + err += "Host:" + host_ + "\n"; + err += "Ip:" + ip_ + "\n"; + if (enable_proxy_) { + err += "Proxy IP:" + target_ip + "\n"; + err += "Proxy Host:" + proxy_.host + "\n"; + } +#ifdef _WIN32 + err += "错误码:" + std::to_string(WSAGetLastError()); +#else + err += String("error str:") + strerror(errno); +#endif + Throw(err); + } else if (_postConnCb != nullptr) { + _postConnCb(socket); + } + } + +#ifndef SION_DISABLE_SSL + + Response ReadResponse(Socket socket, SSL *ssl = nullptr) +#else + + Response ReadResponse(Socket socket) +#endif + { + const int buf_size = 2048; + std::array buf{0}; + auto Read = [&]() { + buf.fill(0); + int status = 0; + if (protocol_ == "http" || enable_proxy_) { + status = recv(socket, buf.data(), buf_size - 1, 0); + } +#ifndef SION_DISABLE_SSL + else if (protocol_ == "https") { + status = SSL_read(ssl, buf.data(), buf_size - 1); + } +#endif + check(status != 0); + check(status > 0, "网络异常,Socket错误码:" + std::to_string(status)); + return status; + }; + Response resp; + auto read_count = 0; + // 读取解析头部信息 + while (true) { + read_count = Read(); + if (read_count > 0) { + resp.source_.insert(resp.source_.end(), buf.data(), buf.data() + read_count); + } + if (resp.CanParseHeader()) { + break; + } + } + + resp.ParseHeader(); + // 检查是否接收完 + auto check_end = [&] { + const auto &body = resp.Body(); + if (resp.is_chunked_) { + if (body.size() < 7) { + return false; + } + auto chunked_end_offset = body.size() - 4; + auto chunked_end_iter = body.begin() + chunked_end_offset; + auto chunked_end = std::string(chunked_end_iter, chunked_end_iter + 4); + if (chunked_end != crlf_crlf) { + return false; + } + auto chunked_start_offset = chunked_end_offset - 1; + // 有些不是\r\n0\r\n\r\n 而是\r\n000000\r\n\r\n + for (auto &i = chunked_start_offset; i >= 2; i--) { + auto r = body[i]; + if (r != '0') { + break; + } + if (body[i - 1] == '\n' && body[i - 2] == '\r') { + return true; + } + } + } else { + return body.size() == resp.content_length_; + } + return false; + }; + // 循环读取接收 + while (!check_end()) { + read_count = Read(); + resp.body_.insert(resp.body_.end(), buf.begin(), buf.begin() + read_count); + } +#ifdef _WIN32 + closesocket(socket); + WSACleanup(); +#else + close(socket); +#endif + resp.ParseBody(); + return resp; + } + }; + + static Response Fetch(String url, Method method = Method::Get, Header header = Header(), String body = "") { + return Request().SetUrl(url).SetHttpMethod(method).SetHeader(header).SetBody(body).Send(); + } + + enum AsyncResponseReceiveMode { + callback, + queue, + future + }; + + struct AsyncResponse { + Response resp; + int id{}; + String err_msg; + }; + + struct AsyncPackage { + Request request; + std::function callback; + int id{}; + AsyncResponseReceiveMode received_mode{}; + }; + + class Async { + int thread_num_ = 6; + std::queue queue_; + std::mutex m_; + std::condition_variable cv_; + std::condition_variable waiting_resp_cv_; + std::map threads_; + bool running_ = false; + bool throw_if_has_err_msg = false; + std::atomic_bool stopped_; + std::atomic_int incr_id; + bool is_block_ = false; + std::mutex waiting_resp_queue_mutex_; + std::vector waiting_handle_response_; + + public: + ~Async() { + stopped_ = true; + cv_.notify_all(); + std::unique_lock lk(m_); + auto &ts = threads_; + cv_.wait(lk, [&] { return ts.empty(); }); // 等待所有线程退出 + } + + Async &SetThreadNum(int num) { + thread_num_ = num; + return *this; + } + + Async &SetBlock(bool wait) { + is_block_ = wait; + return *this; + } + + Async &SetThrowIfHasErrMsg(bool op) { + throw_if_has_err_msg = op; + return *this; + } + + AsyncResponse GetTargetResp(int id) { + auto &queue = waiting_handle_response_; + for (size_t i = 0; i < queue.size(); i++) { + auto &target = queue[i]; + if (target.id == id) { + auto r = queue[i]; + if (throw_if_has_err_msg && r.err_msg.size()) { + Throw(r.err_msg); + } + queue.erase(queue.begin() + i); + return r; + } + } + throw Error("unreachable code"); + } + + AsyncResponse Await(int id, int timeout_ms = 0) { + std::unique_lock lk(waiting_resp_queue_mutex_); + auto &queue = waiting_handle_response_; + auto check = [&] { + for (auto &i: queue) { + if (i.id == id) { + return true; + } + } + return false; + }; + if (check()) { + return GetTargetResp(id); + } + if (timeout_ms != 0) { + waiting_resp_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), check); + if (!check()) { + throw AsyncAwaitTimeout(); + } + } else { + waiting_resp_cv_.wait(lk, check); + } + return GetTargetResp(id); + } + + void Start() { + check(!running_, "一个线程池实例只能start一次"); + for (int i = 0; i < thread_num_; i++) { + threads_[i] = std::thread([&, i] { AsyncLoop(i); }); + } + running_ = true; + if (is_block_) { + for (auto &i: threads_) { + i.second.join(); + } + } else { + for (auto &i: threads_) { + i.second.detach(); + } + } + } + + int Run(std::function fn) { + auto id = ++incr_id; + { + std::lock_guard lock(m_); + AsyncPackage pkg; + pkg.request = fn(); + pkg.id = id; + pkg.received_mode = AsyncResponseReceiveMode::queue; + queue_.push(pkg); + } + cv_.notify_one(); + return id; + } + + void Run(std::function fn, std::function cb) { + { + std::lock_guard lock(m_); + AsyncPackage pkg; + pkg.callback = cb; + pkg.request = fn(); + pkg.received_mode = AsyncResponseReceiveMode::callback; + queue_.push(pkg); + } + cv_.notify_one(); + } + + std::vector GetAvailableResponse() { + std::lock_guard m(waiting_resp_queue_mutex_); + auto available_resp_queue = waiting_handle_response_; + waiting_handle_response_ = {}; + return available_resp_queue; + } + + private: + void AsyncLoop(int id) { + AsyncPackage pkg; + while (!stopped_.load()) { + std::unique_lock lk(m_); + cv_.wait(lk, [&] { return !queue_.empty() || stopped_.load(); }); + if (stopped_.load()) { + break; + } + pkg = queue_.front(); + queue_.pop(); + lk.unlock(); // 提前解锁,不等析构再解,防止notify_one拉起后又马上阻塞 + cv_.notify_one(); + Response resp; + String err_msg; + if (stopped_.load()) { + break; + } + try { + resp = pkg.request.Send(); + } + catch (const std::exception &e) { + err_msg = e.what(); + } + if (stopped_.load()) { + break; + } + AsyncResponse resp_pkg; + resp_pkg.id = pkg.id; + resp_pkg.resp = resp; + resp_pkg.err_msg = err_msg; + if (pkg.received_mode == AsyncResponseReceiveMode::queue) { + std::lock_guard m(waiting_resp_queue_mutex_); + waiting_handle_response_.push_back(resp_pkg); + waiting_resp_cv_.notify_all(); + } else if (pkg.received_mode == AsyncResponseReceiveMode::callback) { + try { + pkg.callback(resp_pkg); + } + catch (const std::exception &e) { + std::cerr << e.what() << '\n'; + } + } + } + { + std::lock_guard m(m_); + threads_.erase(id); + cv_.notify_one(); + } + } + }; + +} // namespace sion diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 58897c6..c9117bf 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -8,7 +8,6 @@ #ifdef SCG_ON static void connect_scg_server() { - //1、设置token jwae_set_token("token1234"); diff --git a/app/src/main/cpp/srcs/scc-service.cpp b/app/src/main/cpp/srcs/scc-service.cpp index b3b4814..5a9a1f5 100644 --- a/app/src/main/cpp/srcs/scc-service.cpp +++ b/app/src/main/cpp/srcs/scc-service.cpp @@ -8,7 +8,7 @@ #include "ipcalc.h" #include "scg-service.h" #include "../cJSON/cJSON.h" -#include "../http/http-client.h" +#include "sion.h" #define SET_CLIENTCFG_PATH ("/tunnel/setconfig") #define SET_CLIENTSTART_TUNNEL ("/tunnel/start") @@ -24,6 +24,42 @@ typedef struct { static SCGPROXY_CONFIG g_scgProxyCfg; +static void http_connected_cb(sion::Socket sock) { + int ret; + unsigned char vmid[4]; + unsigned char *p; + const unsigned int id = htonl(g_scgProxyCfg.curConnVmId); + const auto svrId = static_cast(WG_CTRL_SCG_ID); + unsigned char scgProxy[] = {0x01, // VERSION + 0x09, // Length + 0xF0, // ++++++ INFO[0] TYPE + 0x04, // INFO[0] LENGTH + 0, // INFO[0] VMID[0] + 0, // INFO[0] VMID[1] + 0, // INFO[0] VMID[2] + 0, // INFO[0] VMID[3] + 0xF1, // INFO[1] TYPE + 0x01, // INFO[1] LENGTH + svrId}; // ------ INFO[1] SCG Service ID + + p = scgProxy; + memcpy(vmid, &id, 4); + scgProxy[4] = vmid[0]; + scgProxy[5] = vmid[1]; + scgProxy[6] = vmid[2]; + scgProxy[7] = vmid[3]; + + ret = send(sock, reinterpret_cast(p), sizeof(scgProxy), 0); + + if (ret != sizeof(scgProxy)) { + ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Service Connected To SCG Server(vmid = %d, SCGAppId = %d) error: %d\n", + g_scgProxyCfg.curConnVmId, WG_CTRL_SCG_ID, ret); + } + + ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "Service Connected To SCG Server:vmid = %d, SCGAppId = %d: %d\n", + g_scgProxyCfg.curConnVmId, WG_CTRL_SCG_ID, sock); +} + int get_scg_cur_vmid() { return g_scgProxyCfg.curConnVmId; } @@ -131,12 +167,12 @@ int init_scgproxy_service(const char *pSCGIpAddr, int scgPort) { } static int remote_tunnel_service_control(int vmId, bool start) { - char *pJsonString; - cJSON *pRoot; - cJSON *pMsgContent; - cJSON *rspCode; - char url[1024]; - char *pSvrResp; + char *pJsonString; + cJSON *pRoot; + cJSON *pMsgContent; + cJSON *rspCode; + char url[1024]; + sion::Response resp; if (vmId < 0) { ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pSCGIpAddr params error: %d\n", vmId); @@ -176,36 +212,49 @@ static int remote_tunnel_service_control(int vmId, bool start) { memset(url, 0, 1024); snprintf(url, 1024, "%s%s", g_scgProxyCfg.scgProxyUrl, SET_CLIENTSTART_TUNNEL); - pSvrResp = http_post(url, pJsonString); -// res = g_scgProxyCfg.g_tunCtrlCtx->Post(SET_CLIENTSTART_TUNNEL, pJsonString, "application/json"); + resp = sion::Request() + .SetUrl(url) + .SetHttpMethod(sion::Method::Post) + .SetHeader("Content-type", "application/json") + .SetBody(pJsonString) + .SetConnectedCb(http_connected_cb) + .Send(); - if (pSvrResp == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error\n", SET_CLIENTSTART_TUNNEL, pJsonString); + if (resp.Status() != "OK") { + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error: %s\n", SET_CLIENTCFG_PATH, pJsonString, resp.Status().c_str()); free(pJsonString); return -ERR_HTTP_POST_DATA; } - ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, pSvrResp); + if (resp.Code() != "200") { + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s server return HTTP error: %s\n", SET_CLIENTCFG_PATH, + pJsonString, + resp.Code().c_str()); + free(pJsonString); + return -ERR_HTTP_SERVER_RSP; + } + + ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, resp.StrBody().c_str()); free(pJsonString); - if (strlen(pSvrResp) == 0) { + if (strlen(resp.Code().c_str()) == 0) { ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Server response empty message.\n"); return -ERR_READ_FILE; } - pRoot = cJSON_Parse(pSvrResp); + pRoot = cJSON_Parse(resp.StrBody().c_str()); if (pRoot == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", resp.StrBody().c_str()); return -ERR_JSON_DECODE; } pMsgContent = cJSON_GetObjectItem(pRoot, "msgContent"); if (pMsgContent == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", resp.StrBody().c_str()); cJSON_Delete(pRoot); return -ERR_JSON_DECODE; } @@ -213,7 +262,7 @@ static int remote_tunnel_service_control(int vmId, bool start) { rspCode = cJSON_GetObjectItem(pMsgContent, "errCode"); if (rspCode == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.rspCode) JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.rspCode) JSON %s Error.\n", resp.StrBody().c_str()); cJSON_Delete(pRoot); return -ERR_JSON_DECODE; } @@ -257,13 +306,13 @@ void remote_connect_vm_service(int vmId) { * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO */ int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, const char *pCliTunNetwork, char *pSvrNetwork) { - char *pJsonString; - cJSON *pRoot; - cJSON *pMsgContent; - cJSON *pRspCode; - cJSON *pSvrNet; - char url[1024]; - char *pSvrResp; + char *pJsonString; + cJSON *pRoot; + cJSON *pMsgContent; + cJSON *pRspCode; + cJSON *pSvrNet; + char url[1024]; + sion::Response resp; if (pCliPubKey == nullptr || strlen(pCliPubKey) == 0) { ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pCliPubKey params error: %s\n", pCliPubKey ? pCliPubKey : "NULL String"); @@ -323,48 +372,59 @@ int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, co memset(url, 0, 1024); snprintf(url, 1024, "%s%s", g_scgProxyCfg.scgProxyUrl, SET_CLIENTCFG_PATH); - pSvrResp = http_post(url, pJsonString); -#if 0 - memset(url, 0, 1024); - //sprintf(url, "%s", g_scgProxyCfg.) - snprintf(url, 1024, "http://%s:%d%s", g_scgProxyCfg.scgProxyIpAddr, g_scgProxyCfg.scgProxyPort, SET_CLIENTCFG_PATH); - char *resp = http_post(url, pJsonString); + resp = sion::Request() + .SetUrl(url) + .SetHttpMethod(sion::Method::Post) + .SetHeader("Content-type", "application/json") + .SetBody(pJsonString) + .SetConnectedCb(http_connected_cb) + .Send(); - if (resp == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s recv NULL\n", SET_CLIENTCFG_PATH, pJsonString); - return ERR_HTTP_POST_DATA; - } else { - ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "[%s]:Post Data %s recv: %s\n", SET_CLIENTCFG_PATH, pJsonString, resp); - return ERR_HTTP_POST_DATA; - } - res = g_scgProxyCfg.g_tunCtrlCtx->Post(SET_CLIENTCFG_PATH, pJsonString, "application/json"); -#endif - if (pSvrResp == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error", SET_CLIENTCFG_PATH, pJsonString); + if (resp.Status() != "OK") { + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error: %s\n", SET_CLIENTCFG_PATH, pJsonString, resp.Status().c_str()); free(pJsonString); return -ERR_HTTP_POST_DATA; } - ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, pSvrResp); + if (resp.Code() != "200") { + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s server return HTTP error: %s\n", SET_CLIENTCFG_PATH, + pJsonString, + resp.Code().c_str()); + free(pJsonString); + return -ERR_HTTP_SERVER_RSP; + } +#if 0 + memset(url, 0, 1024); + //sprintf(url, "%s", g_scgProxyCfg.) + snprintf(url, 1024, "http://%s:%d%s", g_scgProxyCfg.scgProxyIpAddr, g_scgProxyCfg.scgProxyPort, SET_CLIENTCFG_PATH); + char *resp = http_post(url, pJsonString); + + if (resp == nullptr) { + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s recv NULL\n", SET_CLIENTCFG_PATH, pJsonString); + return ERR_HTTP_POST_DATA; + } else { + ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "[%s]:Post Data %s recv: %s\n", SET_CLIENTCFG_PATH, pJsonString, resp); + return ERR_HTTP_POST_DATA; + } + res = g_scgProxyCfg.g_tunCtrlCtx->Post(SET_CLIENTCFG_PATH, pJsonString, "application/json"); +#endif + + ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, resp.StrBody().c_str()); free(pJsonString); - if (strlen(pSvrResp) == 0) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Server response empty message.\n"); - return -ERR_READ_FILE; - } - pRoot = cJSON_Parse(pSvrResp); + pRoot = cJSON_Parse(resp.StrBody().c_str()); if (pRoot == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", resp.StrBody().c_str()); return -ERR_JSON_DECODE; } pMsgContent = cJSON_GetObjectItem(pRoot, "msgContent"); if (pMsgContent == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", resp.StrBody().c_str()); cJSON_Delete(pRoot); return -ERR_JSON_DECODE; } @@ -372,7 +432,7 @@ int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, co pRspCode = cJSON_GetObjectItem(pMsgContent, "errCode"); if (pRspCode == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pRspCode) JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pRspCode) JSON %s Error.\n", resp.StrBody().c_str()); cJSON_Delete(pRoot); return -ERR_JSON_DECODE; } @@ -385,7 +445,7 @@ int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, co pSvrNet = cJSON_GetObjectItem(pMsgContent, "svrNetwork"); if (pSvrNet == nullptr) { - ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pSvrNet) JSON %s Error.\n", pSvrResp); + ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pSvrNet) JSON %s Error.\n", resp.StrBody().c_str()); cJSON_Delete(pRoot); return -ERR_JSON_DECODE; } diff --git a/app/src/main/java/com/example/sccproxy/MainActivity.java b/app/src/main/java/com/example/sccproxy/MainActivity.java index 0f7b261..e329c1f 100644 --- a/app/src/main/java/com/example/sccproxy/MainActivity.java +++ b/app/src/main/java/com/example/sccproxy/MainActivity.java @@ -35,67 +35,67 @@ public class MainActivity extends AppCompatActivity { binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - requestPermission(); + //requestPermission(); // Example of a call to a native method TextView tv = binding.sampleText; tv.setText(stringFromJNI()); } - - private void requestPermission() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - // 先判断有没有权限 - if (Environment.isExternalStorageManager()) { - writeFile(); - } else { - Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); - intent.setData(Uri.parse("package:" + this.getPackageName())); - startActivityForResult(intent, REQUEST_CODE); - } - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - // 先判断有没有权限 - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - writeFile(); - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); - } - } else { - writeFile(); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == REQUEST_CODE) { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - writeFile(); - } else { - //ToastUtils.show("存储权限获取失败"); - } - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - if (Environment.isExternalStorageManager()) { - writeFile(); - } else { - //ToastUtils.show("存储权限获取失败"); - } - } - } - - /** - * 模拟文件写入 - */ - private void writeFile() { - //ToastUtils.show("写入文件成功"); - } +// +// private void requestPermission() { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { +// // 先判断有没有权限 +// if (Environment.isExternalStorageManager()) { +// writeFile(); +// } else { +// Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); +// intent.setData(Uri.parse("package:" + this.getPackageName())); +// startActivityForResult(intent, REQUEST_CODE); +// } +// } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// // 先判断有没有权限 +// if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && +// ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { +// writeFile(); +// } else { +// ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); +// } +// } else { +// writeFile(); +// } +// } +// +// @Override +// public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { +// super.onRequestPermissionsResult(requestCode, permissions, grantResults); +// if (requestCode == REQUEST_CODE) { +// if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && +// ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { +// writeFile(); +// } else { +// //ToastUtils.show("存储权限获取失败"); +// } +// } +// } +// +// @Override +// protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { +// super.onActivityResult(requestCode, resultCode, data); +// if (requestCode == REQUEST_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { +// if (Environment.isExternalStorageManager()) { +// writeFile(); +// } else { +// //ToastUtils.show("存储权限获取失败"); +// } +// } +// } +// +// /** +// * 模拟文件写入 +// */ +// private void writeFile() { +// //ToastUtils.show("写入文件成功"); +// } /** * A native method that is implemented by the 'sccproxy' native library,