This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhangyang-libzt/src/Central.cpp

312 lines
8.4 KiB
C++
Raw Normal View History

2021-01-29 01:26:46 -08:00
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_CENTRAL_H
#define ZT_CENTRAL_H
#ifdef ZTS_ENABLE_CENTRAL_API
2021-01-29 01:26:46 -08:00
#include "Debug.hpp"
#include "Mutex.hpp"
#include "ZeroTierSockets.h"
2021-01-29 01:26:46 -08:00
#include <curl/curl.h>
#include <iomanip>
#include <iostream>
#include <stdio.h>
#include <string.h>
2021-01-29 01:26:46 -08:00
2021-03-14 01:01:04 -08:00
char api_url[ZTS_CENRTAL_MAX_URL_LEN];
char api_token[ZTS_CENTRAL_TOKEN_LEN + 1];
2021-01-29 01:26:46 -08:00
char* _resp_buf;
2021-03-14 01:01:04 -08:00
int _resp_buf_len;
int _resp_buf_offset;
2021-01-29 01:26:46 -08:00
2021-03-14 01:01:04 -08:00
static int8_t _access_modes;
2021-01-29 01:26:46 -08:00
static int8_t _bIsVerbose;
static int8_t _bInit;
using namespace ZeroTier;
Mutex _responseBuffer_m;
#ifdef __cplusplus
2021-01-29 01:26:46 -08:00
extern "C" {
#endif
2021-01-29 01:26:46 -08:00
size_t on_data(void* buffer, size_t size, size_t nmemb, void* userp)
2021-01-29 01:26:46 -08:00
{
2021-03-14 01:01:04 -08:00
DEBUG_INFO("buf=%p,size=%zu,nmemb=%zu,userp=%p", buffer, size, nmemb, userp);
2021-01-29 01:26:46 -08:00
int byte_count = (size * nmemb);
2021-03-14 01:01:04 -08:00
if (_resp_buf_offset + byte_count >= _resp_buf_len) {
2021-01-29 01:26:46 -08:00
DEBUG_ERROR("Out of buffer space. Cannot store response from server");
return 0; // Signal to libcurl that our buffer is full (triggers a write error.)
2021-01-29 01:26:46 -08:00
}
memcpy(_resp_buf + _resp_buf_offset, buffer, byte_count);
2021-03-14 01:01:04 -08:00
_resp_buf_offset += byte_count;
2021-01-29 01:26:46 -08:00
return byte_count;
}
2021-03-14 01:01:04 -08:00
void zts_central_set_access_mode(int8_t modes)
2021-01-29 01:26:46 -08:00
{
2021-03-14 01:01:04 -08:00
_access_modes = modes;
2021-01-29 01:26:46 -08:00
}
2021-03-14 01:01:04 -08:00
void zts_central_set_verbose(int8_t is_verbose)
2021-01-29 01:26:46 -08:00
{
_bIsVerbose = is_verbose;
}
2021-03-14 01:01:04 -08:00
void zts_central_clear_resp_buf()
2021-01-29 01:26:46 -08:00
{
Mutex::Lock _l(_responseBuffer_m);
2021-03-14 01:01:04 -08:00
memset(_resp_buf, 0, _resp_buf_len);
_resp_buf_offset = 0;
2021-01-29 01:26:46 -08:00
}
2021-03-14 01:01:04 -08:00
int zts_central_init(
const char* url_str,
const char* token_str,
char* resp_buf,
uint32_t resp_buf_len)
2021-01-29 01:26:46 -08:00
{
_access_modes = ZTS_CENTRAL_READ; // Defauly read-only
_bIsVerbose = 0; // Default disable libcurl verbose output
2021-01-29 01:26:46 -08:00
Mutex::Lock _l(_responseBuffer_m);
2021-03-14 01:01:04 -08:00
if (resp_buf_len == 0) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
2021-03-14 01:01:04 -08:00
_resp_buf = resp_buf;
_resp_buf_len = resp_buf_len;
_resp_buf_offset = 0;
2021-01-29 01:26:46 -08:00
// Initialize all curl internal submodules
curl_global_init(CURL_GLOBAL_ALL);
int url_len = strlen(url_str);
2021-03-14 01:01:04 -08:00
if (url_len < 3 || url_len > ZTS_CENRTAL_MAX_URL_LEN) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
else {
2021-03-14 01:01:04 -08:00
memset(api_url, 0, ZTS_CENRTAL_MAX_URL_LEN);
memcpy(api_url, url_str, url_len);
2021-01-29 01:26:46 -08:00
}
int token_len = strlen(token_str);
2021-03-14 01:01:04 -08:00
if (token_len != ZTS_CENTRAL_TOKEN_LEN) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
else {
2021-03-14 01:01:04 -08:00
memset(api_token, 0, ZTS_CENTRAL_TOKEN_LEN);
memcpy(api_token, token_str, token_len);
2021-01-29 01:26:46 -08:00
}
_bInit = true;
return ZTS_ERR_OK;
}
2021-03-14 01:01:04 -08:00
void zts_central_cleanup()
2021-01-29 01:26:46 -08:00
{
curl_global_cleanup();
}
int _central_req(
int request_type,
char* central_str,
char* api_route_str,
char* token_str,
int* response_code,
char* post_data)
2021-01-29 01:26:46 -08:00
{
int err = ZTS_ERR_OK;
if (! _bInit) {
2021-03-14 01:01:04 -08:00
DEBUG_ERROR("Error: Central API must be initialized first. Call zts_central_init()");
2021-01-29 01:26:46 -08:00
return ZTS_ERR_SERVICE;
}
if (request_type == ZTS_HTTP_GET && ! (_access_modes & ZTS_CENTRAL_READ)) {
2021-01-29 01:26:46 -08:00
DEBUG_ERROR("Error: Incorrect access mode. Need (ZTS_CENTRAL_READ) permission");
return ZTS_ERR_SERVICE;
}
if (request_type == ZTS_HTTP_POST && ! (_access_modes & ZTS_CENTRAL_WRITE)) {
2021-01-29 01:26:46 -08:00
DEBUG_ERROR("Error: Incorrect access mode. Need (ZTS_CENTRAL_WRITE) permission");
return ZTS_ERR_SERVICE;
}
2021-03-14 01:01:04 -08:00
zts_central_clear_resp_buf();
int central_strlen = strlen(central_str);
2021-01-29 01:26:46 -08:00
int api_route_strlen = strlen(api_route_str);
int token_strlen = strlen(token_str);
2021-03-14 01:01:04 -08:00
int url_len = central_strlen + api_route_strlen;
if (token_strlen > ZTS_CENTRAL_TOKEN_LEN) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
2021-03-14 01:01:04 -08:00
if (url_len > ZTS_CENRTAL_MAX_URL_LEN) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
2021-03-14 01:01:04 -08:00
char req_url[ZTS_CENRTAL_MAX_URL_LEN];
strcpy(req_url, central_str);
2021-01-29 01:26:46 -08:00
strcat(req_url, api_route_str);
CURL* curl;
2021-01-29 01:26:46 -08:00
CURLcode res;
curl = curl_easy_init();
if (! curl) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_GENERAL;
}
struct curl_slist* hs = NULL;
2021-03-14 01:01:04 -08:00
char auth_str[ZTS_CENTRAL_TOKEN_LEN + 32];
if (token_strlen == ZTS_CENTRAL_TOKEN_LEN) {
memset(auth_str, 0, ZTS_CENTRAL_TOKEN_LEN + 32);
2021-01-29 01:26:46 -08:00
sprintf(auth_str, "Authorization: Bearer %s", token_str);
}
hs = curl_slist_append(hs, auth_str);
hs = curl_slist_append(hs, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
curl_easy_setopt(curl, CURLOPT_URL, req_url);
2021-03-14 01:01:04 -08:00
// example.com is redirected, so we tell libcurl to follow redirection
2021-01-29 01:26:46 -08:00
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
if (_bIsVerbose) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
}
// Tell curl to use our write function
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_data);
2021-03-14 01:01:04 -08:00
if (request_type == ZTS_HTTP_GET) {
2021-01-29 01:26:46 -08:00
// Nothing
DEBUG_INFO("Request (GET) = %s", api_route_str);
}
2021-03-14 01:01:04 -08:00
if (request_type == ZTS_HTTP_POST) {
2021-01-29 01:26:46 -08:00
DEBUG_INFO("Request (POST) = %s", api_route_str);
if (post_data) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
}
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
}
2021-03-14 01:01:04 -08:00
if (request_type == ZTS_HTTP_DELETE) {
2021-01-29 01:26:46 -08:00
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
}
// curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); // Consider 400-500 series code as failures
2021-01-29 01:26:46 -08:00
// Perform request
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
// char* url;
2021-01-29 01:26:46 -08:00
double elapsed_time = 0.0;
long hrc = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &hrc);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &elapsed_time);
2021-03-14 01:01:04 -08:00
DEBUG_INFO("Req. took %f second(s). HTTP code (%ld)", elapsed_time, hrc);
2021-01-29 01:26:46 -08:00
*response_code = hrc;
// curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
}
else {
2021-01-29 01:26:46 -08:00
DEBUG_ERROR("%s", curl_easy_strerror(res));
err = ZTS_ERR_SERVICE;
}
curl_easy_cleanup(curl);
return err;
}
int zts_get_last_resp_buf(char* dest_buffer, int dest_buf_len)
2021-01-29 01:26:46 -08:00
{
2021-03-14 01:01:04 -08:00
if (dest_buf_len <= _resp_buf_offset) {
2021-01-29 01:26:46 -08:00
return ZTS_ERR_ARG;
}
2021-03-14 01:01:04 -08:00
int sz = dest_buf_len < _resp_buf_len ? dest_buf_len : _resp_buf_len;
memcpy(dest_buffer, _resp_buf, sz);
2021-01-29 01:26:46 -08:00
return ZTS_ERR_OK;
}
int zts_central_get_status(int* resp_code)
2021-01-29 01:26:46 -08:00
{
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/status", api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_get_self(int* resp_code)
2021-01-29 01:26:46 -08:00
{
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/self", api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_get_network(int* resp_code, uint64_t nwid)
2021-01-29 01:26:46 -08:00
{
char req[64];
sprintf(req, "/api/network/%llx", nwid);
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_update_network(int* resp_code, uint64_t nwid)
2021-01-29 01:26:46 -08:00
{
char req[64];
sprintf(req, "/api/network/%llx", nwid);
return _central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_delete_network(int* resp_code, uint64_t nwid)
2021-01-29 01:26:46 -08:00
{
char req[64];
sprintf(req, "/api/network/%llx", nwid);
return _central_req(ZTS_HTTP_DELETE, api_url, req, api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_get_networks(int* resp_code)
2021-01-29 01:26:46 -08:00
{
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/network", api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_get_member(int* resp_code, uint64_t nwid, uint64_t nodeid)
2021-01-29 01:26:46 -08:00
{
if (nwid == 0 || nodeid == 0) {
return ZTS_ERR_ARG;
}
char req[64];
sprintf(req, "/api/network/%llx/member/%llx", nwid, nodeid);
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
int zts_central_update_member(int* resp_code, uint64_t nwid, uint64_t nodeid, char* post_data)
2021-01-29 01:26:46 -08:00
{
if (nwid == 0 || nodeid == 0 || post_data == NULL) {
return ZTS_ERR_ARG;
}
char req[64];
sprintf(req, "/api/network/%llx/member/%llx", nwid, nodeid);
return _central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, post_data);
2021-01-29 01:26:46 -08:00
}
int zts_central_set_node_auth(int* resp_code, uint64_t nwid, uint64_t nodeid, uint8_t is_authed)
2021-01-29 01:26:46 -08:00
{
if (is_authed != 0 && is_authed != 1) {
return ZTS_ERR_ARG;
}
char config_data[64];
if (is_authed == ZTS_CENTRAL_NODE_AUTH_TRUE) {
sprintf(config_data, "{\"config\": {\"authorized\": true} }");
}
if (is_authed == ZTS_CENTRAL_NODE_AUTH_FALSE) {
sprintf(config_data, "{\"config\": {\"authorized\": false} }");
}
2021-03-14 01:01:04 -08:00
return zts_central_update_member(resp_code, nwid, nodeid, config_data);
2021-01-29 01:26:46 -08:00
}
int zts_central_get_members_of_network(int* resp_code, uint64_t nwid)
2021-01-29 01:26:46 -08:00
{
char req[64];
sprintf(req, "/api/network/%llx/member", nwid);
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
2021-01-29 01:26:46 -08:00
}
#ifdef __cplusplus
} // extern "C"
#endif
2021-01-29 01:26:46 -08:00
#endif // ZTS_ENABLE_CENTRAL_API
#endif // _H