mirror of
https://github.com/zhaojh329/rtty.git
synced 2026-02-27 09:53:17 +08:00
Drop the depend of libuwsc
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "src/buffer"]
|
||||||
|
path = src/buffer
|
||||||
|
url = https://github.com/zhaojh329/buffer.git
|
||||||
@@ -5,8 +5,6 @@ os:
|
|||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get install -y libev-dev libssl-dev
|
- sudo apt-get install -y libev-dev libssl-dev
|
||||||
- git clone --recursive https://github.com/zhaojh329/libuwsc.git
|
|
||||||
- cd libuwsc && cmake . && sudo make install && cd -
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- mkdir build && cd build
|
- mkdir build && cd build
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
You first need to send a command to the server through POST, the message format is as follows.
|
You first need to send a command to the server through POST, the message format is as follows.
|
||||||
|
|
||||||
{"devid": "test", "username": "test", "password": "test", "cmd": "echo", "params": ["hello rtty"], "env": {"x": "12"}}
|
{"devid": "test", "username": "test", "password": "test", "cmd": "echo", "params": ["hello rtty"]}
|
||||||
|
|
||||||
The devid, username, cmd in the message must be provided. Password, params, and env are optional. Params is a JSON array and env is a JSON object.
|
The devid, username, cmd in the message must be provided. Password, params are optional. Params is a JSON array.
|
||||||
|
|
||||||
Then the server returns a unique token.
|
Then the server returns a unique token.
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
首先要通过POST方式向服务器发送一条命令,消息格式如下所示:
|
首先要通过POST方式向服务器发送一条命令,消息格式如下所示:
|
||||||
|
|
||||||
{"devid": "test", "username": "test", "password": "test", "cmd": "echo", "params": ["hello rtty"], "env": {"x": "12"}}
|
{"devid": "test", "username": "test", "password": "test", "cmd": "echo", "params": ["hello rtty"]}
|
||||||
|
|
||||||
其中devid、username、cmd必须提供。password、params和env为可选项。params为一个JSON数组,env为一个JSON对象。
|
其中devid、username、cmd必须提供。password、params为可选项。params为一个JSON数组。
|
||||||
|
|
||||||
然后服务器返回一个唯一的token:
|
然后服务器返回一个唯一的token:
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,6 @@
|
|||||||
./configure --host=arm-linux-gnueabi
|
./configure --host=arm-linux-gnueabi
|
||||||
DESTDIR=/tmp/rtty_install make install
|
DESTDIR=/tmp/rtty_install make install
|
||||||
|
|
||||||
# Build libuwsc
|
|
||||||
|
|
||||||
git clone --recursive https://github.com/zhaojh329/libuwsc.git
|
|
||||||
cd libuwsc
|
|
||||||
cmake . -DCMAKE_C_COMPILER=arm-linux-gnueabi-gcc -DCMAKE_FIND_ROOT_PATH=/tmp/rtty_install -DUWSC_SSL_SUPPORT=OFF
|
|
||||||
DESTDIR=/tmp/rtty_install make install
|
|
||||||
|
|
||||||
# Build rtty
|
# Build rtty
|
||||||
|
|
||||||
git clone https://github.com/zhaojh329/rtty.git
|
git clone https://github.com/zhaojh329/rtty.git
|
||||||
@@ -30,5 +23,3 @@
|
|||||||
├── libev.so -> libev.so.4.0.0
|
├── libev.so -> libev.so.4.0.0
|
||||||
├── libev.so.4 -> libev.so.4.0.0
|
├── libev.so.4 -> libev.so.4.0.0
|
||||||
├── libev.so.4.0.0
|
├── libev.so.4.0.0
|
||||||
├── libuwsc.so -> libuwsc.so.3.3.2
|
|
||||||
└── libuwsc.so.3.3.2
|
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -6,7 +6,7 @@
|
|||||||
[4]: https://github.com/zhaojh329/rtty/pulls
|
[4]: https://github.com/zhaojh329/rtty/pulls
|
||||||
[5]: https://img.shields.io/badge/Issues-welcome-brightgreen.svg?style=plastic
|
[5]: https://img.shields.io/badge/Issues-welcome-brightgreen.svg?style=plastic
|
||||||
[6]: https://github.com/zhaojh329/rtty/issues/new
|
[6]: https://github.com/zhaojh329/rtty/issues/new
|
||||||
[7]: https://img.shields.io/badge/release-6.6.1-blue.svg?style=plastic
|
[7]: https://img.shields.io/badge/release-7.0.0-blue.svg?style=plastic
|
||||||
[8]: https://github.com/zhaojh329/rtty/releases
|
[8]: https://github.com/zhaojh329/rtty/releases
|
||||||
[9]: https://travis-ci.org/zhaojh329/rtty.svg?branch=master
|
[9]: https://travis-ci.org/zhaojh329/rtty.svg?branch=master
|
||||||
[10]: https://travis-ci.org/zhaojh329/rtty
|
[10]: https://travis-ci.org/zhaojh329/rtty
|
||||||
@@ -18,9 +18,7 @@
|
|||||||
[![Build Status][9]][10]
|
[![Build Status][9]][10]
|
||||||
|
|
||||||
[Xterm.js]: https://github.com/xtermjs/xterm.js
|
[Xterm.js]: https://github.com/xtermjs/xterm.js
|
||||||
[lrzsz]: https://ohse.de/uwe/software/lrzsz.html
|
|
||||||
[libev]: http://software.schmorp.de/pkg/libev.html
|
[libev]: http://software.schmorp.de/pkg/libev.html
|
||||||
[libuwsc]: https://github.com/zhaojh329/libuwsc
|
|
||||||
[openssl]: https://github.com/openssl/openssl
|
[openssl]: https://github.com/openssl/openssl
|
||||||
[mbedtls(polarssl)]: https://github.com/ARMmbed/mbedtls
|
[mbedtls(polarssl)]: https://github.com/ARMmbed/mbedtls
|
||||||
[CyaSSl(wolfssl)]: https://github.com/wolfSSL/wolfssl
|
[CyaSSl(wolfssl)]: https://github.com/wolfSSL/wolfssl
|
||||||
@@ -49,12 +47,10 @@ the world.
|
|||||||
* SSL support: openssl, mbedtls, CyaSSl(wolfssl)
|
* SSL support: openssl, mbedtls, CyaSSl(wolfssl)
|
||||||
* Support device authorization
|
* Support device authorization
|
||||||
* Support Execute a command remote
|
* Support Execute a command remote
|
||||||
* The client is very small, suitable for embedded Linux: rtty(20.1K) + libev(48.5K) + libuwsc(24.4K) = 93K. If you want
|
* The client is very small, suitable for embedded Linux
|
||||||
to support ssl, +libwolfssl(595.9K) = 688.9K
|
|
||||||
|
|
||||||
# Dependencies of the Client side
|
# Dependencies of the Client side
|
||||||
* [libev] - A full-featured and high-performance event loop
|
* [libev] - A full-featured and high-performance event loop
|
||||||
* [libuwsc] - A Lightweight and fully asynchronous WebSocket client library based on libev
|
|
||||||
* [mbedtls(polarssl)], [CyaSSl(wolfssl)] or [openssl] - If you want to support SSL
|
* [mbedtls(polarssl)], [CyaSSl(wolfssl)] or [openssl] - If you want to support SSL
|
||||||
|
|
||||||
# [Deploying the server side](https://github.com/zhaojh329/rttys)
|
# [Deploying the server side](https://github.com/zhaojh329/rttys)
|
||||||
@@ -68,18 +64,21 @@ Install
|
|||||||
Command-line Options
|
Command-line Options
|
||||||
|
|
||||||
Usage: rtty [option]
|
Usage: rtty [option]
|
||||||
-I id # Set an ID for the device(Maximum 63 bytes, valid character:letter,
|
-I, --id=string Set an ID for the device(Maximum 63 bytes, valid
|
||||||
number, underline and short line)
|
character:letter, number, underline and short line)
|
||||||
-h host # Server's host or ipaddr
|
-h, --host=string Server's host or ipaddr(Default is localhost)
|
||||||
-p port # Server port(Default is 5912)
|
-p, --port=number Server port(Default is 5912)
|
||||||
-a # Auto reconnect to the server
|
-d, --description=string Adding a description to the device(Maximum 126 bytes)
|
||||||
-v # verbose
|
-a Auto reconnect to the server
|
||||||
-d # Adding a description to the device(Maximum 126 bytes)
|
-s SSL on
|
||||||
-s # SSL on
|
-D Run in the background
|
||||||
-k keepalive # keep alive in seconds for this client. Defaults to 5
|
-t, --token=string Authorization token
|
||||||
-V # Show version
|
-f username Skip a second login authentication. See man login(1) about the details
|
||||||
-D # Run in the background
|
-R Receive file
|
||||||
-t token # Authorization token
|
-S file Send file
|
||||||
|
-v, --verbose verbose
|
||||||
|
-V, --version Show version
|
||||||
|
--help Show usage
|
||||||
|
|
||||||
Run RTTY(Replace the following parameters with your own parameters)
|
Run RTTY(Replace the following parameters with your own parameters)
|
||||||
|
|
||||||
@@ -94,11 +93,11 @@ If your rttys is configured with a token, add the following parameter(Replace th
|
|||||||
## [For Other Embedded Linux Platform](/CROSS_COMPILE.md)
|
## [For Other Embedded Linux Platform](/CROSS_COMPILE.md)
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Use your web browser to access your server: `https://your-server-host:5912`, then click the connection button
|
Use your web browser to access your server: `https://your-server-host:5913`, then click the connection button
|
||||||
|
|
||||||
You can easily embed RTTY into your existing platform: `https://your-server-host:5912/#/?id=your-id`
|
You can easily embed RTTY into your existing platform: `https://your-server-host:5913/#/?id=your-id`
|
||||||
|
|
||||||
Automatic login: `https://your-server:5912/#/?id=device-id&username=device-username&password=device-password`
|
Automatic login: `https://your-server:5913/#/?id=device-id&username=device-username&password=device-password`
|
||||||
|
|
||||||
## Transfer file
|
## Transfer file
|
||||||
Transfer file from local to remote device
|
Transfer file from local to remote device
|
||||||
|
|||||||
40
README_ZH.md
40
README_ZH.md
@@ -6,7 +6,7 @@
|
|||||||
[4]: https://github.com/zhaojh329/rtty/pulls
|
[4]: https://github.com/zhaojh329/rtty/pulls
|
||||||
[5]: https://img.shields.io/badge/Issues-welcome-brightgreen.svg?style=plastic
|
[5]: https://img.shields.io/badge/Issues-welcome-brightgreen.svg?style=plastic
|
||||||
[6]: https://github.com/zhaojh329/rtty/issues/new
|
[6]: https://github.com/zhaojh329/rtty/issues/new
|
||||||
[7]: https://img.shields.io/badge/release-6.6.1-blue.svg?style=plastic
|
[7]: https://img.shields.io/badge/release-7.0.0-blue.svg?style=plastic
|
||||||
[8]: https://github.com/zhaojh329/rtty/releases
|
[8]: https://github.com/zhaojh329/rtty/releases
|
||||||
[9]: https://travis-ci.org/zhaojh329/rtty.svg?branch=master
|
[9]: https://travis-ci.org/zhaojh329/rtty.svg?branch=master
|
||||||
[10]: https://travis-ci.org/zhaojh329/rtty
|
[10]: https://travis-ci.org/zhaojh329/rtty
|
||||||
@@ -18,9 +18,7 @@
|
|||||||
[![Build Status][9]][10]
|
[![Build Status][9]][10]
|
||||||
|
|
||||||
[Xterm.js]: https://github.com/xtermjs/xterm.js
|
[Xterm.js]: https://github.com/xtermjs/xterm.js
|
||||||
[lrzsz]: https://ohse.de/uwe/software/lrzsz.html
|
|
||||||
[libev]: http://software.schmorp.de/pkg/libev.html
|
[libev]: http://software.schmorp.de/pkg/libev.html
|
||||||
[libuwsc]: https://github.com/zhaojh329/libuwsc
|
|
||||||
[openssl]: https://github.com/openssl/openssl
|
[openssl]: https://github.com/openssl/openssl
|
||||||
[mbedtls(polarssl)]: https://github.com/ARMmbed/mbedtls
|
[mbedtls(polarssl)]: https://github.com/ARMmbed/mbedtls
|
||||||
[CyaSSl(wolfssl)]: https://github.com/wolfSSL/wolfssl
|
[CyaSSl(wolfssl)]: https://github.com/wolfSSL/wolfssl
|
||||||
@@ -47,11 +45,10 @@ rtty非常适合远程维护你的或者你公司的部署在全球各地的成
|
|||||||
* 支持SSL: openssl, mbedtls, CyaSSl(wolfssl)
|
* 支持SSL: openssl, mbedtls, CyaSSl(wolfssl)
|
||||||
* 支持设备认证
|
* 支持设备认证
|
||||||
* 支持远程执行命令
|
* 支持远程执行命令
|
||||||
* 客户端非常小,适合嵌入式Linux: rtty(20.1K) + libev(48.5K) + libuwsc(24.4K) = 93K. 如果你希望支持SSL,+libwolfssl(595.9K) = 688.9K
|
* 客户端非常小,适合嵌入式Linux
|
||||||
|
|
||||||
# 客户端依赖
|
# 客户端依赖
|
||||||
* [libev] - 高性能的事件循环库
|
* [libev] - 高性能的事件循环库
|
||||||
* [libuwsc] - 一个轻量的针对嵌入式Linux的基于libev的WebSocket客户端C库。
|
|
||||||
* [mbedtls(polarssl)]、[CyaSSl(wolfssl)]或者[openssl] - 如果你需要支持SSL
|
* [mbedtls(polarssl)]、[CyaSSl(wolfssl)]或者[openssl] - 如果你需要支持SSL
|
||||||
|
|
||||||
# [部署服务端](https://github.com/zhaojh329/rttys/blob/master/README_ZH.md)
|
# [部署服务端](https://github.com/zhaojh329/rttys/blob/master/README_ZH.md)
|
||||||
@@ -65,18 +62,21 @@ rtty非常适合远程维护你的或者你公司的部署在全球各地的成
|
|||||||
查看命令行选项
|
查看命令行选项
|
||||||
|
|
||||||
Usage: rtty [option]
|
Usage: rtty [option]
|
||||||
-I id # Set an ID for the device(Maximum 63 bytes, valid character:letter,
|
-I, --id=string Set an ID for the device(Maximum 63 bytes, valid
|
||||||
number, underline and short line)
|
character:letter, number, underline and short line)
|
||||||
-h host # Server's host or ipaddr
|
-h, --host=string Server's host or ipaddr(Default is localhost)
|
||||||
-p port # Server port(Default is 5912)
|
-p, --port=number Server port(Default is 5912)
|
||||||
-a # Auto reconnect to the server
|
-d, --description=string Adding a description to the device(Maximum 126 bytes)
|
||||||
-v # verbose
|
-a Auto reconnect to the server
|
||||||
-d # Adding a description to the device(Maximum 126 bytes)
|
-s SSL on
|
||||||
-s # SSL on
|
-D Run in the background
|
||||||
-k keepalive # keep alive in seconds for this client. Defaults to 5
|
-t, --token=string Authorization token
|
||||||
-V # Show version
|
-f username Skip a second login authentication. See man login(1) about the details
|
||||||
-D # Run in the background
|
-R Receive file
|
||||||
-t token # Authorization token
|
-S file Send file
|
||||||
|
-v, --verbose verbose
|
||||||
|
-V, --version Show version
|
||||||
|
--help Show usage
|
||||||
|
|
||||||
运行RTTY(将下面的参数替换为你自己的参数)
|
运行RTTY(将下面的参数替换为你自己的参数)
|
||||||
|
|
||||||
@@ -91,11 +91,11 @@ rtty非常适合远程维护你的或者你公司的部署在全球各地的成
|
|||||||
## [其它嵌入式Linux平台](/CROSS_COMPILE.md)
|
## [其它嵌入式Linux平台](/CROSS_COMPILE.md)
|
||||||
|
|
||||||
# 如何使用
|
# 如何使用
|
||||||
使用你的Web浏览器访问你的服务器: `https://your-server-host:5912`,然后点击连接按钮。
|
使用你的Web浏览器访问你的服务器: `https://your-server-host:5913`,然后点击连接按钮。
|
||||||
|
|
||||||
你可以非常方便的将RTTY嵌入到你现有的平台: `https://your-server-host:5912/#/?id=your-id`
|
你可以非常方便的将RTTY嵌入到你现有的平台: `https://your-server-host:5913/#/?id=your-id`
|
||||||
|
|
||||||
自动登录: `https://your-server:5912/#/?id=device-id&username=device-username&password=device-password`
|
自动登录: `https://your-server:5913/#/?id=device-id&username=device-username&password=device-password`
|
||||||
|
|
||||||
## 传输文件
|
## 传输文件
|
||||||
从本地传输文件到远程设备
|
从本地传输文件到远程设备
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# - Try to find libuwsc
|
|
||||||
# Once done this will define
|
|
||||||
# LIBUWSC_FOUND - System has libuwsc
|
|
||||||
# LIBUWSC_INCLUDE_DIR - The libuwsc include directories
|
|
||||||
# LIBUWSC_LIBRARY - The libraries needed to use libuwsc
|
|
||||||
|
|
||||||
find_path(LIBUWSC_INCLUDE_DIR uwsc)
|
|
||||||
find_library(LIBUWSC_LIBRARY uwsc PATH_SUFFIXES lib64)
|
|
||||||
|
|
||||||
if(LIBUWSC_INCLUDE_DIR)
|
|
||||||
file(STRINGS "${LIBUWSC_INCLUDE_DIR}/uwsc/config.h"
|
|
||||||
LIBUWSC_VERSION_MAJOR REGEX "^#define[ \t]+UWSC_VERSION_MAJOR[ \t]+[0-9]+")
|
|
||||||
file(STRINGS "${LIBUWSC_INCLUDE_DIR}/uwsc/config.h"
|
|
||||||
LIBUWSC_VERSION_MINOR REGEX "^#define[ \t]+UWSC_VERSION_MINOR[ \t]+[0-9]+")
|
|
||||||
string(REGEX REPLACE "[^0-9]+" "" LIBUWSC_VERSION_MAJOR "${LIBUWSC_VERSION_MAJOR}")
|
|
||||||
string(REGEX REPLACE "[^0-9]+" "" LIBUWSC_VERSION_MINOR "${LIBUWSC_VERSION_MINOR}")
|
|
||||||
set(LIBUWSC_VERSION "${LIBUWSC_VERSION_MAJOR}.${LIBUWSC_VERSION_MINOR}")
|
|
||||||
unset(LIBUWSC_VERSION_MINOR)
|
|
||||||
unset(LIBUWSC_VERSION_MAJOR)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and set LIBUWSC_FOUND to TRUE
|
|
||||||
# if all listed variables are TRUE and the requested version matches.
|
|
||||||
find_package_handle_standard_args(Libuwsc REQUIRED_VARS
|
|
||||||
LIBUWSC_LIBRARY LIBUWSC_INCLUDE_DIR
|
|
||||||
VERSION_VAR LIBUWSC_VERSION)
|
|
||||||
|
|
||||||
mark_as_advanced(LIBUWSC_INCLUDE_DIR LIBUWSC_LIBRARY)
|
|
||||||
37
cmake/Modules/FindMbedTLS.cmake
Normal file
37
cmake/Modules/FindMbedTLS.cmake
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
find_path(MBEDTLS_INCLUDE_DIR mbedtls/ssl.h)
|
||||||
|
|
||||||
|
find_library(MBEDTLS_LIBRARY mbedtls)
|
||||||
|
find_library(MBEDX509_LIBRARY mbedx509)
|
||||||
|
find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
|
||||||
|
|
||||||
|
if(MBEDTLS_INCLUDE_DIR)
|
||||||
|
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h"
|
||||||
|
MBEDTLS_VERSION_MAJOR REGEX "^#define[ \t]+MBEDTLS_VERSION_MAJOR[ \t]+[0-9]+")
|
||||||
|
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h"
|
||||||
|
MBEDTLS_VERSION_MINOR REGEX "^#define[ \t]+MBEDTLS_VERSION_MINOR[ \t]+[0-9]+")
|
||||||
|
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h"
|
||||||
|
MBEDTLS_VERSION_PATCH REGEX "^#define[ \t]+MBEDTLS_VERSION_PATCH[ \t]+[0-9]+")
|
||||||
|
string(REGEX REPLACE "[^0-9]+" "" MBEDTLS_VERSION_MAJOR "${MBEDTLS_VERSION_MAJOR}")
|
||||||
|
string(REGEX REPLACE "[^0-9]+" "" MBEDTLS_VERSION_MINOR "${MBEDTLS_VERSION_MINOR}")
|
||||||
|
string(REGEX REPLACE "[^0-9]+" "" MBEDTLS_VERSION_PATCH "${MBEDTLS_VERSION_PATCH}")
|
||||||
|
set(MBEDTLS_VERSION "${MBEDTLS_VERSION_MAJOR}.${MBEDTLS_VERSION_MINOR}.${MBEDTLS_VERSION_PATCH}")
|
||||||
|
unset(MBEDTLS_VERSION_MINOR)
|
||||||
|
unset(MBEDTLS_VERSION_MAJOR)
|
||||||
|
unset(MBEDTLS_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(MbedTLS
|
||||||
|
REQUIRED_VARS
|
||||||
|
MBEDTLS_LIBRARY
|
||||||
|
MBEDX509_LIBRARY
|
||||||
|
MBEDCRYPTO_LIBRARY
|
||||||
|
MBEDTLS_INCLUDE_DIR
|
||||||
|
VERSION_VAR
|
||||||
|
MBEDTLS_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
|
||||||
62
cmake/Modules/FindWolfSSL.cmake
Normal file
62
cmake/Modules/FindWolfSSL.cmake
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
if(WOLFSSL_PREFER_STATIC_LIB)
|
||||||
|
set(WOLFSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
if(WIN32)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
else()
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(_WOLFSSL QUIET wolfssl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_path(WOLFSSL_INCLUDE_DIR NAMES wolfssl/version.h HINTS ${_WOLFSSL_INCLUDEDIR})
|
||||||
|
find_library(WOLFSSL_LIBRARY NAMES wolfssl HINTS ${_WOLFSSL_LIBDIR})
|
||||||
|
if(WOLFSSL_INCLUDE_DIR AND WOLFSSL_LIBRARY)
|
||||||
|
set(WOLFSSL_INCLUDE_DIR ${WOLFSSL_INCLUDE_DIR})
|
||||||
|
set(WOLFSSL_LIBRARY ${WOLFSSL_LIBRARY})
|
||||||
|
set(WOLFSSL_VERSION ${_WOLFSSL_VERSION})
|
||||||
|
set(WOLFSSL_IS_WOLFSSL ON)
|
||||||
|
else()
|
||||||
|
if(UNIX)
|
||||||
|
pkg_check_modules(_WOLFSSL QUIET WOLFSSL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_path(WOLFSSL_INCLUDE_DIR NAMES WOLFSSL/version.h HINTS ${_WOLFSSL_INCLUDEDIR})
|
||||||
|
find_library(WOLFSSL_LIBRARY NAMES WOLFSSL HINTS ${_WOLFSSL_LIBDIR})
|
||||||
|
set(WOLFSSL_VERSION ${_WOLFSSL_VERSION})
|
||||||
|
set(WOLFSSL_IS_WOLFSSL OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT WOLFSSL_VERSION AND WOLFSSL_INCLUDE_DIR)
|
||||||
|
if(WOLFSSL_IS_WOLFSSL)
|
||||||
|
file(STRINGS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h" WOLFSSL_VERSION_STR REGEX "^#define[\t ]+LIBWOLFSSL_VERSION_STRING[\t ]+\"[^\"]+\"")
|
||||||
|
else()
|
||||||
|
file(STRINGS "${WOLFSSL_INCLUDE_DIR}/WOLFSSL/version.h" WOLFSSL_VERSION_STR REGEX "^#define[\t ]+LIBWOLFSSL_VERSION_STRING[\t ]+\"[^\"]+\"")
|
||||||
|
endif()
|
||||||
|
if(WOLFSSL_VERSION_STR MATCHES "\"([^\"]+)\"")
|
||||||
|
set(WOLFSSL_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
|
||||||
|
set(WOLFSSL_LIBRARIES ${WOLFSSL_LIBRARY})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(WOLFSSL
|
||||||
|
REQUIRED_VARS
|
||||||
|
WOLFSSL_LIBRARY
|
||||||
|
WOLFSSL_INCLUDE_DIR
|
||||||
|
VERSION_VAR
|
||||||
|
WOLFSSL_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)
|
||||||
|
|
||||||
|
if(WOLFSSL_PREFER_STATIC_LIB)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${WOLFSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
unset(WOLFSSL_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||||
|
endif()
|
||||||
@@ -1,18 +1,93 @@
|
|||||||
add_definitions(-O -Wall -Werror --std=gnu99 -D_GNU_SOURCE)
|
add_definitions(-O -Wall -Werror --std=gnu99 -D_GNU_SOURCE)
|
||||||
|
|
||||||
# The version number.
|
# The version number.
|
||||||
set(RTTY_VERSION_MAJOR 6)
|
set(RTTY_VERSION_MAJOR 7)
|
||||||
set(RTTY_VERSION_MINOR 6)
|
set(RTTY_VERSION_MINOR 0)
|
||||||
set(RTTY_VERSION_PATCH 1)
|
set(RTTY_VERSION_PATCH 0)
|
||||||
|
|
||||||
# Check the third party Libraries
|
# Check the third party Libraries
|
||||||
find_package(Libev REQUIRED)
|
find_package(Libev REQUIRED)
|
||||||
find_package(Libuwsc 3.2 REQUIRED)
|
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUWSC_INCLUDE_DIR} ${LIBEV_INCLUDE_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/buffer ${LIBEV_INCLUDE_DIR})
|
||||||
set(EXTRA_LIBS ${LIBUWSC_LIBRARY} ${LIBEV_LIBRARY} util crypt m)
|
set(EXTRA_LIBS ${LIBEV_LIBRARY} util crypt m)
|
||||||
|
|
||||||
add_executable(rtty main.c utils.c json.c command.c file.c)
|
set(RTTY_FILE_UNIX_SOCKET "/var/run/rttyfile.sock")
|
||||||
|
add_definitions(-DRTTY_FILE_UNIX_SOCKET="${RTTY_FILE_UNIX_SOCKET}")
|
||||||
|
|
||||||
|
set(RTTY_SSL_SUPPORT_CONFIG 1)
|
||||||
|
option(RTTY_SSL_SUPPORT "SSL support" ON)
|
||||||
|
|
||||||
|
option(RTTY_USE_OPENSSL "Force select OpenSSL" OFF)
|
||||||
|
option(RTTY_USE_WOLFSSL "Force select WolfSSL(CyaSSL)" OFF)
|
||||||
|
option(RTTY_USE_MBEDTLS "Force select MbedTLS(PolarSSL)" OFF)
|
||||||
|
|
||||||
|
set(SSL_NAME OFF)
|
||||||
|
set(RTTY_HAVE_OPENSSL_CONFIG 0)
|
||||||
|
set(RTTY_HAVE_WOLFSSL_CONFIG 0)
|
||||||
|
set(RTTY_HAVE_MBEDTLS_CONFIG 0)
|
||||||
|
|
||||||
|
if(NOT RTTY_SSL_SUPPORT)
|
||||||
|
set(RTTY_SSL_SUPPORT_CONFIG 0)
|
||||||
|
else()
|
||||||
|
find_package(OpenSSL)
|
||||||
|
find_package(WolfSSL)
|
||||||
|
find_package(MbedTLS)
|
||||||
|
|
||||||
|
if(RTTY_USE_OPENSSL)
|
||||||
|
if (NOT OPENSSL_FOUND)
|
||||||
|
set(RTTY_SSL_SUPPORT OFF)
|
||||||
|
message(WARNING "Force select OpenSSL, but not found it")
|
||||||
|
endif()
|
||||||
|
elseif(RTTY_USE_WOLFSSL)
|
||||||
|
if (NOT WOLFSSL_FOUND)
|
||||||
|
set(RTTY_SSL_SUPPORT OFF)
|
||||||
|
message(WARNING "Force select WolfSSL(CyaSSL), but not found it")
|
||||||
|
endif()
|
||||||
|
elseif(RTTY_USE_MBEDTLS)
|
||||||
|
if (NOT MBEDTLS_FOUND)
|
||||||
|
set(RTTY_SSL_SUPPORT OFF)
|
||||||
|
message(WARNING "Force select MbedTLS(PolarSSL), but not found it")
|
||||||
|
endif()
|
||||||
|
elseif(OPENSSL_FOUND)
|
||||||
|
set(RTTY_USE_OPENSSL ON)
|
||||||
|
elseif(WOLFSSL_FOUND)
|
||||||
|
set(RTTY_USE_WOLFSSL ON)
|
||||||
|
elseif(MBEDTLS_FOUND)
|
||||||
|
set(RTTY_USE_MBEDTLS ON)
|
||||||
|
else()
|
||||||
|
set(RTTY_SSL_SUPPORT OFF)
|
||||||
|
message(WARNING "No available SSL libraries found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(RTTY_USE_OPENSSL)
|
||||||
|
set(SSL_NAME "OpenSSL")
|
||||||
|
set(SSL_INC ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(SSL_LIB ${OPENSSL_LIBRARIES})
|
||||||
|
set(RTTY_HAVE_OPENSSL_CONFIG 1)
|
||||||
|
elseif(RTTY_USE_WOLFSSL)
|
||||||
|
set(SSL_NAME "WolfSSL(CyaSSL)")
|
||||||
|
set(SSL_INC ${WOLFSSL_INCLUDE_DIR})
|
||||||
|
set(SSL_LIB ${WOLFSSL_LIBRARIES})
|
||||||
|
set(RTTY_HAVE_WOLFSSL_CONFIG 1)
|
||||||
|
elseif(RTTY_USE_MBEDTLS)
|
||||||
|
set(SSL_NAME "MbedTLS(PolarSSL)")
|
||||||
|
set(SSL_INC ${MBEDTLS_INCLUDE_DIR})
|
||||||
|
set(SSL_LIB ${MBEDTLS_LIBRARIES})
|
||||||
|
set(RTTY_HAVE_MBEDTLS_CONFIG 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(RTTY_SSL_SUPPORT)
|
||||||
|
include_directories(${SSL_INC})
|
||||||
|
list(APPEND EXTRA_LIBS ${SSL_LIB})
|
||||||
|
message(STATUS "Select ${SSL_NAME} as the SSL backend")
|
||||||
|
else()
|
||||||
|
set(SSL_NAME OFF)
|
||||||
|
set(RTTY_SSL_SUPPORT_CONFIG 0)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(rtty main.c utils.c buffer/buffer.c log.c net.c net.h rtty.c rtty.h command.c
|
||||||
|
file.c upfile.c upfile.h downfile.c downfile.h ssl.c ssl.h)
|
||||||
target_link_libraries(rtty ${EXTRA_LIBS})
|
target_link_libraries(rtty ${EXTRA_LIBS})
|
||||||
|
|
||||||
# configure a header file to pass some of the CMake settings to the source code
|
# configure a header file to pass some of the CMake settings to the source code
|
||||||
|
|||||||
1
src/buffer
Submodule
1
src/buffer
Submodule
Submodule src/buffer added at 74d566b6c4
117
src/command.c
117
src/command.c
@@ -31,11 +31,9 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <shadow.h>
|
#include <shadow.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <uwsc/log.h>
|
|
||||||
#include <uwsc/utils.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
@@ -121,55 +119,61 @@ static const char *cmderr2str(int err)
|
|||||||
|
|
||||||
static void task_free(struct task *t)
|
static void task_free(struct task *t)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
/* stdout watcher */
|
/* stdout watcher */
|
||||||
if (t->ioo.fd > 0) {
|
if (t->ioo.fd > 0) {
|
||||||
close(t->ioo.fd);
|
close(t->ioo.fd);
|
||||||
ev_io_stop(t->ws->loop, &t->ioo);
|
ev_io_stop(t->rtty->loop, &t->ioo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stderr watcher */
|
/* stderr watcher */
|
||||||
if (t->ioe.fd > 0) {
|
if (t->ioe.fd > 0) {
|
||||||
close(t->ioe.fd);
|
close(t->ioe.fd);
|
||||||
ev_io_stop(t->ws->loop, &t->ioe);
|
ev_io_stop(t->rtty->loop, &t->ioe);
|
||||||
}
|
}
|
||||||
|
|
||||||
ev_child_stop(t->ws->loop, &t->cw);
|
ev_child_stop(t->rtty->loop, &t->cw);
|
||||||
ev_timer_stop(t->ws->loop, &t->timer);
|
ev_timer_stop(t->rtty->loop, &t->timer);
|
||||||
|
|
||||||
buffer_free(&t->ob);
|
buffer_free(&t->ob);
|
||||||
buffer_free(&t->eb);
|
buffer_free(&t->eb);
|
||||||
|
|
||||||
json_value_free((json_value *)t->msg);
|
for (i = 0; i < t->nparams; i++)
|
||||||
|
free(t->params[i]);
|
||||||
|
free(t->params);
|
||||||
|
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_err_reply(struct uwsc_client *ws, const char *token, int err)
|
static void cmd_err_reply(struct rtty *rtty, const char *token, int err)
|
||||||
{
|
{
|
||||||
char str[256] = "";
|
char str[256] = "";
|
||||||
|
|
||||||
snprintf(str, sizeof(str) - 1, "{\"type\":\"cmd\",\"token\":\"%s\","
|
snprintf(str, sizeof(str) - 1, "{\"token\":\"%s\","
|
||||||
"\"attrs\":{\"err\":%d,\"msg\":\"%s\"}}", token, err, cmderr2str(err));
|
"\"attrs\":{\"err\":%d,\"msg\":\"%s\"}}", token, err, cmderr2str(err));
|
||||||
ws->send(ws, str, strlen(str), UWSC_OP_TEXT);
|
|
||||||
|
rtty_send_msg(rtty, MSG_TYPE_CMD, str, strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_reply(struct task *t, int code)
|
static void cmd_reply(struct task *t, int code)
|
||||||
{
|
{
|
||||||
size_t len = buffer_length(&t->ob) + buffer_length(&t->eb);
|
size_t len = buffer_length(&t->ob) + buffer_length(&t->eb);
|
||||||
int ret;
|
struct rtty *rtty = t->rtty;
|
||||||
char *str, *pos;
|
char *str, *pos;
|
||||||
|
int ret;
|
||||||
|
|
||||||
len = ceil(len * 4.0 / 3) + 200;
|
len = ceil(len * 4.0 / 3) + 200;
|
||||||
|
|
||||||
str = calloc(1, len);
|
str = calloc(1, len);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
cmd_err_reply(t->ws, t->token, RTTY_CMD_ERR_NOMEM);
|
cmd_err_reply(t->rtty, t->token, RTTY_CMD_ERR_NOMEM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = str;
|
pos = str;
|
||||||
|
|
||||||
ret = snprintf(pos, len, "{\"type\":\"cmd\",\"token\":\"%s\","
|
ret = snprintf(pos, len, "{\"token\":\"%s\","
|
||||||
"\"attrs\":{\"code\":%d,\"stdout\":\"", t->token, code);
|
"\"attrs\":{\"code\":%d,\"stdout\":\"", t->token, code);
|
||||||
|
|
||||||
len -= ret;
|
len -= ret;
|
||||||
@@ -188,10 +192,10 @@ static void cmd_reply(struct task *t, int code)
|
|||||||
pos += ret;
|
pos += ret;
|
||||||
|
|
||||||
ret = snprintf(pos, len, "\"}}");
|
ret = snprintf(pos, len, "\"}}");
|
||||||
len -= ret;
|
|
||||||
pos += ret;
|
pos += ret;
|
||||||
|
|
||||||
t->ws->send(t->ws, str, pos - str, UWSC_OP_TEXT);
|
rtty_send_msg(rtty, MSG_TYPE_CMD, str, pos - str);
|
||||||
|
|
||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +225,7 @@ static void ev_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
|
|||||||
task_free(t);
|
task_free(t);
|
||||||
nrunning--;
|
nrunning--;
|
||||||
|
|
||||||
uwsc_log_err("exec '%s' timeout\n", t->cmd);
|
log_err("exec '%s' timeout\n", t->cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ev_io_stdout_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
static void ev_io_stdout_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
@@ -249,7 +253,7 @@ static void run_task(struct task *t)
|
|||||||
|
|
||||||
if (pipe2(opipe, O_CLOEXEC | O_NONBLOCK) < 0 ||
|
if (pipe2(opipe, O_CLOEXEC | O_NONBLOCK) < 0 ||
|
||||||
pipe2(epipe, O_CLOEXEC | O_NONBLOCK) < 0) {
|
pipe2(epipe, O_CLOEXEC | O_NONBLOCK) < 0) {
|
||||||
uwsc_log_err("pipe2 failed: %s\n", strerror(errno));
|
log_err("pipe2 failed: %s\n", strerror(errno));
|
||||||
err = RTTY_CMD_ERR_SYSERR;
|
err = RTTY_CMD_ERR_SYSERR;
|
||||||
goto ERR;
|
goto ERR;
|
||||||
}
|
}
|
||||||
@@ -257,15 +261,14 @@ static void run_task(struct task *t)
|
|||||||
pid = fork();
|
pid = fork();
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
uwsc_log_err("fork: %s\n", strerror(errno));
|
log_err("fork: %s\n", strerror(errno));
|
||||||
err = RTTY_CMD_ERR_SYSERR;
|
err = RTTY_CMD_ERR_SYSERR;
|
||||||
goto ERR;
|
goto ERR;
|
||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
const json_value *params = json_get_value(t->attrs, "params");
|
int arglen = 2 + t->nparams;
|
||||||
const json_value *env = json_get_value(t->attrs, "env");
|
|
||||||
int i, arglen;
|
|
||||||
char **args;
|
char **args;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Close unused read end */
|
/* Close unused read end */
|
||||||
close(opipe[0]);
|
close(opipe[0]);
|
||||||
@@ -277,30 +280,14 @@ static void run_task(struct task *t)
|
|||||||
close(opipe[1]);
|
close(opipe[1]);
|
||||||
close(epipe[1]);
|
close(epipe[1]);
|
||||||
|
|
||||||
arglen = 2;
|
|
||||||
if (params)
|
|
||||||
arglen += params->u.array.length;
|
|
||||||
|
|
||||||
args = calloc(1, sizeof(char *) * arglen);
|
args = calloc(1, sizeof(char *) * arglen);
|
||||||
if (!args)
|
if (!args)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
args[0] = t->cmd;
|
args[0] = t->cmd;
|
||||||
|
|
||||||
if (params) {
|
for (i = 0; i < t->nparams; i++)
|
||||||
for (i = 0; i < params->u.array.length; i++)
|
args[i + 1] = t->params[i];
|
||||||
args[i + 1] = (char *)json_get_array_string(params, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env) {
|
|
||||||
if (env->type == json_object) {
|
|
||||||
for (i = 0; i < env->u.object.length; i++) {
|
|
||||||
json_value *v = env->u.object.values[i].value;
|
|
||||||
if (v->type == json_string)
|
|
||||||
setenv(env->u.object.values[i].name, v->u.string.ptr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
execv(t->cmd, args);
|
execv(t->cmd, args);
|
||||||
}
|
}
|
||||||
@@ -311,40 +298,46 @@ static void run_task(struct task *t)
|
|||||||
|
|
||||||
/* Watch child's status */
|
/* Watch child's status */
|
||||||
ev_child_init(&t->cw, ev_child_exit, pid, 0);
|
ev_child_init(&t->cw, ev_child_exit, pid, 0);
|
||||||
ev_child_start(t->ws->loop, &t->cw);
|
ev_child_start(t->rtty->loop, &t->cw);
|
||||||
|
|
||||||
ev_io_init(&t->ioo, ev_io_stdout_cb, opipe[0], EV_READ);
|
ev_io_init(&t->ioo, ev_io_stdout_cb, opipe[0], EV_READ);
|
||||||
ev_io_start(t->ws->loop, &t->ioo);
|
ev_io_start(t->rtty->loop, &t->ioo);
|
||||||
|
|
||||||
ev_io_init(&t->ioe, ev_io_stderr_cb, epipe[0], EV_READ);
|
ev_io_init(&t->ioe, ev_io_stderr_cb, epipe[0], EV_READ);
|
||||||
ev_io_start(t->ws->loop, &t->ioe);
|
ev_io_start(t->rtty->loop, &t->ioe);
|
||||||
|
|
||||||
ev_timer_init(&t->timer, ev_timer_cb, RTTY_CMD_EXEC_TIMEOUT, 0);
|
ev_timer_init(&t->timer, ev_timer_cb, RTTY_CMD_EXEC_TIMEOUT, 0);
|
||||||
ev_timer_start(t->ws->loop, &t->timer);
|
ev_timer_start(t->rtty->loop, &t->timer);
|
||||||
|
|
||||||
nrunning++;
|
nrunning++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR:
|
ERR:
|
||||||
cmd_err_reply(t->ws, t->token, err);
|
cmd_err_reply(t->rtty, t->token, err);
|
||||||
task_free(t);
|
task_free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_task(struct uwsc_client *ws, const char *token, const char *cmd,
|
static void add_task(struct rtty *rtty, const char *token, const char *cmd, const char *data)
|
||||||
const json_value *msg, const json_value *attrs)
|
|
||||||
{
|
{
|
||||||
struct task *t;
|
struct task *t;
|
||||||
|
int i;
|
||||||
|
|
||||||
t = calloc(1, sizeof(struct task) + strlen(cmd) + 1);
|
t = calloc(1, sizeof(struct task) + strlen(cmd) + 1);
|
||||||
if (!t) {
|
if (!t) {
|
||||||
cmd_err_reply(ws, token, RTTY_CMD_ERR_NOMEM);
|
cmd_err_reply(rtty, token, RTTY_CMD_ERR_NOMEM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->ws = ws;
|
t->rtty = rtty;
|
||||||
t->msg = msg;
|
|
||||||
t->attrs = attrs;
|
t->nparams = *data++;
|
||||||
|
t->params = calloc(t->nparams, sizeof(char *));
|
||||||
|
|
||||||
|
for (i = 0; i < t->nparams; i++) {
|
||||||
|
t->params[i] = strdup(data);
|
||||||
|
data += strlen(t->params[i]) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(t->cmd, cmd);
|
strcpy(t->cmd, cmd);
|
||||||
strcpy(t->token, token);
|
strcpy(t->token, token);
|
||||||
@@ -355,30 +348,30 @@ static void add_task(struct uwsc_client *ws, const char *token, const char *cmd,
|
|||||||
list_add_tail(&t->list, &task_pending);
|
list_add_tail(&t->list, &task_pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_command(struct uwsc_client *ws, const json_value *msg)
|
void run_command(struct rtty *rtty, const char *data)
|
||||||
{
|
{
|
||||||
const json_value *attrs = json_get_value(msg, "attrs");
|
const char *username = data;
|
||||||
const char *username = json_get_string(attrs, "username");
|
const char *password = username + strlen(username) + 1;
|
||||||
const char *password = json_get_string(attrs, "password");
|
const char *cmd = password + strlen(password) + 1;
|
||||||
const char *token = json_get_string(msg, "token");
|
const char *token = cmd + strlen(cmd) + 1;
|
||||||
const char *cmd;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!username || !username[0] || !login_test(username, password)) {
|
data = token + strlen(token) + 1;
|
||||||
|
|
||||||
|
if (!username[0] || !login_test(username, password)) {
|
||||||
err = RTTY_CMD_ERR_PERMIT;
|
err = RTTY_CMD_ERR_PERMIT;
|
||||||
goto ERR;
|
goto ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = cmd_lookup(json_get_string(attrs, "cmd"));
|
cmd = cmd_lookup(cmd);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
err = RTTY_CMD_ERR_NOT_FOUND;
|
err = RTTY_CMD_ERR_NOT_FOUND;
|
||||||
goto ERR;
|
goto ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_task(ws, token, cmd, msg, attrs);
|
add_task(rtty, token, cmd, data);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ERR:
|
ERR:
|
||||||
cmd_err_reply(ws, token, err);
|
cmd_err_reply(rtty, token, err);
|
||||||
json_value_free((json_value *)msg);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@
|
|||||||
#ifndef _COMMAND_H
|
#ifndef _COMMAND_H
|
||||||
#define _COMMAND_H
|
#define _COMMAND_H
|
||||||
|
|
||||||
#include <uwsc/uwsc.h>
|
#include "rtty.h"
|
||||||
|
|
||||||
#include "json.h"
|
|
||||||
|
|
||||||
#define RTTY_CMD_MAX_RUNNING 5
|
#define RTTY_CMD_MAX_RUNNING 5
|
||||||
#define RTTY_CMD_EXEC_TIMEOUT 30
|
#define RTTY_CMD_EXEC_TIMEOUT 30
|
||||||
@@ -42,19 +40,19 @@ enum {
|
|||||||
|
|
||||||
struct task {
|
struct task {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct uwsc_client *ws;
|
struct rtty *rtty;
|
||||||
struct ev_child cw;
|
struct ev_child cw;
|
||||||
struct ev_timer timer;
|
struct ev_timer timer;
|
||||||
struct ev_io ioo; /* Watch stdout of child */
|
struct ev_io ioo; /* Watch stdout of child */
|
||||||
struct ev_io ioe; /* Watch stderr of child */
|
struct ev_io ioe; /* Watch stderr of child */
|
||||||
struct buffer ob; /* buffer for stdout */
|
struct buffer ob; /* buffer for stdout */
|
||||||
struct buffer eb; /* buffer for stderr */
|
struct buffer eb; /* buffer for stderr */
|
||||||
const json_value *msg; /* message from server */
|
int nparams;
|
||||||
const json_value *attrs;
|
char **params;
|
||||||
char token[33];
|
char token[33];
|
||||||
char cmd[0];
|
char cmd[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
void run_command(struct uwsc_client *ws, const json_value *msg);
|
void run_command(struct rtty *rtty, const char *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,4 +30,10 @@
|
|||||||
#define RTTY_VERSION_PATCH @RTTY_VERSION_PATCH@
|
#define RTTY_VERSION_PATCH @RTTY_VERSION_PATCH@
|
||||||
#define RTTY_VERSION_STRING "@RTTY_VERSION_MAJOR@.@RTTY_VERSION_MINOR@.@RTTY_VERSION_PATCH@"
|
#define RTTY_VERSION_STRING "@RTTY_VERSION_MAJOR@.@RTTY_VERSION_MINOR@.@RTTY_VERSION_PATCH@"
|
||||||
|
|
||||||
|
#define RTTY_SSL_SUPPORT @RTTY_SSL_SUPPORT_CONFIG@
|
||||||
|
|
||||||
|
#define RTTY_HAVE_OPENSSL @RTTY_HAVE_OPENSSL_CONFIG@
|
||||||
|
#define RTTY_HAVE_WOLFSSL @RTTY_HAVE_WOLFSSL_CONFIG@
|
||||||
|
#define RTTY_HAVE_MBEDTLS @RTTY_HAVE_MBEDTLS_CONFIG@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
198
src/downfile.c
Normal file
198
src/downfile.c
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static struct buffer rb;
|
||||||
|
static struct buffer wb;
|
||||||
|
static uint32_t remain;
|
||||||
|
static uint32_t file_size;
|
||||||
|
static ev_tstamp start_time;
|
||||||
|
static struct ev_io iow;
|
||||||
|
static struct ev_io ior;
|
||||||
|
static struct ev_signal sw;
|
||||||
|
static char *file_name;
|
||||||
|
static bool canceled;
|
||||||
|
|
||||||
|
static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
||||||
|
{
|
||||||
|
canceled = true;
|
||||||
|
ev_signal_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_file_write(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
int ret = buffer_pull_to_fd (&wb, w->fd, -1, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr,"socket write error: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remain -= ret;
|
||||||
|
|
||||||
|
fprintf (stdout, "%100c\r", ' ');
|
||||||
|
fprintf(stdout," %lu%% %s %.3lfs\r",
|
||||||
|
(file_size - remain) * 100UL / file_size,
|
||||||
|
format_size(file_size - remain), ev_now(loop) - start_time);
|
||||||
|
fflush (stdout);
|
||||||
|
|
||||||
|
if (buffer_length (&wb) < 1)
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_write_file(struct ev_loop *loop, int msglen)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
remain = file_size = ntohl(buffer_pull_u32 (&rb));
|
||||||
|
file_name = strndup (buffer_data (&rb), msglen - 4);
|
||||||
|
buffer_pull (&rb, NULL, msglen - 4);
|
||||||
|
|
||||||
|
printf ("Transferring '%s'...\n", file_name);
|
||||||
|
|
||||||
|
fd = open (file_name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
printf ("%s\n", strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_io_init(&iow, on_file_write, fd, EV_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_msg(struct ev_loop *loop)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (buffer_length (&rb) < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
len = buffer_get_u16 (&rb, 1);
|
||||||
|
if (buffer_length (&rb) < len + 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
type = buffer_pull_u8 (&rb);
|
||||||
|
buffer_pull (&rb, NULL, 2);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RTTY_FILE_MSG_INFO:
|
||||||
|
start_write_file(loop, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTTY_FILE_MSG_DATA:
|
||||||
|
if (len == 0) {
|
||||||
|
ev_io_stop (loop, &ior);
|
||||||
|
ev_signal_stop (loop, &sw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer_put_data (&wb, buffer_data (&rb), len);
|
||||||
|
buffer_pull (&rb, NULL, len);
|
||||||
|
ev_io_start (loop, &iow);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTTY_FILE_MSG_CANCELED:
|
||||||
|
canceled = true;
|
||||||
|
ev_break (loop, EVBREAK_ALL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_read(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
bool eof;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (canceled) {
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = buffer_put_fd(&rb, w->fd, -1, &eof, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf (stderr, "socket read error: %s\n", strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_msg(loop);
|
||||||
|
|
||||||
|
if (eof) {
|
||||||
|
printf("busy\n");
|
||||||
|
ev_break (loop, EVBREAK_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void download_file()
|
||||||
|
{
|
||||||
|
struct ev_loop *loop = EV_DEFAULT;
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
sock = connect_rtty_file_service();
|
||||||
|
if (sock < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
detect_sid('d');
|
||||||
|
|
||||||
|
ev_signal_init(&sw, signal_cb, SIGINT);
|
||||||
|
ev_signal_start(loop, &sw);
|
||||||
|
|
||||||
|
ev_io_init(&ior, on_net_read, sock, EV_READ);
|
||||||
|
ev_io_start (loop, &ior);
|
||||||
|
|
||||||
|
start_time = ev_now (loop);
|
||||||
|
|
||||||
|
printf("Waiting to receive. Press Ctrl+C to cancel\n");
|
||||||
|
|
||||||
|
ev_run(loop, 0);
|
||||||
|
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
if (iow.fd > 0) {
|
||||||
|
close (iow.fd);
|
||||||
|
|
||||||
|
if (canceled) {
|
||||||
|
unlink (file_name);
|
||||||
|
buffer_free(&wb);
|
||||||
|
buffer_put_u8 (&wb, RTTY_FILE_MSG_CANCELED);
|
||||||
|
buffer_put_u16 (&wb, 0);
|
||||||
|
buffer_pull_to_fd (&wb, sock, -1, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (sock > -1)
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
30
src/downfile.h
Normal file
30
src/downfile.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTTY_DOWNFILE_H_
|
||||||
|
#define RTTY_DOWNFILE_H_
|
||||||
|
|
||||||
|
void download_file();
|
||||||
|
|
||||||
|
#endif
|
||||||
423
src/file.c
423
src/file.c
@@ -22,278 +22,227 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <sys/un.h>
|
||||||
#include <termios.h>
|
#include <sys/socket.h>
|
||||||
#include <stdbool.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <uwsc/log.h>
|
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
static void set_stdin(bool raw)
|
static uint8_t RTTY_FILE_MAGIC[] = {0xb6, 0xbc, 0xbd};
|
||||||
|
struct rtty_file_context file_context;
|
||||||
|
|
||||||
|
static void clear_file_context()
|
||||||
{
|
{
|
||||||
static struct termios ots;
|
file_context.running = false;
|
||||||
static bool current_raw;
|
close(file_context.sock);
|
||||||
struct termios nts;
|
|
||||||
|
|
||||||
if (raw) {
|
buffer_free (&file_context.rb);
|
||||||
if (current_raw)
|
buffer_free (&file_context.wb);
|
||||||
return;
|
|
||||||
|
|
||||||
current_raw = true;
|
ev_io_stop(file_context.rtty->loop, &file_context.ior);
|
||||||
|
ev_io_stop(file_context.rtty->loop, &file_context.iow);
|
||||||
tcgetattr(STDIN_FILENO, &ots);
|
|
||||||
|
|
||||||
nts = ots;
|
|
||||||
|
|
||||||
nts.c_iflag = IGNBRK;
|
|
||||||
/* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */
|
|
||||||
nts.c_lflag &= ~(ECHO | ICANON | ISIG);
|
|
||||||
nts.c_oflag = 0;
|
|
||||||
nts.c_cc[VMIN] = 1;
|
|
||||||
nts.c_cc[VTIME] = 1;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &nts);
|
|
||||||
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
|
|
||||||
} else {
|
|
||||||
if (!current_raw)
|
|
||||||
return;
|
|
||||||
current_raw = false;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &ots);
|
|
||||||
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rf_write(int fd, void *buf, int len)
|
static void on_file_msg_read(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
{
|
{
|
||||||
if (write(fd, buf, len) < 0) {
|
struct buffer *rb = &file_context.rb;
|
||||||
uwsc_log_err("Write failed: %s\n", strerror(errno));
|
struct rtty *rtty = file_context.rtty;
|
||||||
exit(0);
|
struct buffer *wb = &rtty->wb;
|
||||||
|
int msglen;
|
||||||
|
bool eof;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = buffer_put_fd(rb, w->fd, -1, &eof, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err("socket read error: %s\n", strerror (errno));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (buffer_length (rb) < 3)
|
||||||
|
break;
|
||||||
|
|
||||||
|
msglen = buffer_get_u16 (rb, 1);
|
||||||
|
if (buffer_length (rb) < msglen + 3)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer_put_u8 (wb, MSG_TYPE_FILE);
|
||||||
|
buffer_put_u16 (wb, htons(2 + msglen));
|
||||||
|
buffer_put_u8 (wb, file_context.sid);
|
||||||
|
buffer_put_u8 (wb, buffer_pull_u8 (rb));
|
||||||
|
|
||||||
|
buffer_pull (rb, NULL, 2);
|
||||||
|
|
||||||
|
buffer_put_data (wb, buffer_data (rb), msglen);
|
||||||
|
buffer_pull (rb, NULL, msglen);
|
||||||
|
|
||||||
|
ev_io_start(loop, &rtty->iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eof)
|
||||||
|
clear_file_context ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_file_info(struct transfer_context *tc)
|
static void on_file_msg_write(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
{
|
{
|
||||||
struct buffer *b = &tc->b;
|
struct buffer *wb = &file_context.wb;
|
||||||
int len;
|
int ret = buffer_pull_to_fd (wb, w->fd, -1, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err ("socket write error: %s\n", strerror(errno));
|
||||||
|
clear_file_context ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_length(b) < 3)
|
if (buffer_length (wb) < 1)
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_accept(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
int sock = accept(w->fd, NULL, NULL);
|
||||||
|
if (sock < 0) {
|
||||||
|
log_err("accept fail: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_context.running) {
|
||||||
|
log_err("up/down file busy\n");
|
||||||
|
close(sock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
|
||||||
|
|
||||||
|
file_context.sock = sock;
|
||||||
|
file_context.running = true;
|
||||||
|
|
||||||
|
ev_io_init(&file_context.ior, on_file_msg_read, sock, EV_READ);
|
||||||
|
ev_io_start (loop, &file_context.ior);
|
||||||
|
|
||||||
|
ev_io_init(&file_context.iow, on_file_msg_write, sock, EV_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int start_file_service(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun = {
|
||||||
|
.sun_family = AF_UNIX
|
||||||
|
};
|
||||||
|
const int on = 1;
|
||||||
|
int sock;
|
||||||
|
|
||||||
|
if (strlen(RTTY_FILE_UNIX_SOCKET) >= sizeof(sun.sun_path)) {
|
||||||
|
log_err("unix socket path too long\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
log_err("create socket fail: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(sun.sun_path, RTTY_FILE_UNIX_SOCKET);
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||||
|
|
||||||
|
unlink(RTTY_FILE_UNIX_SOCKET);
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
|
||||||
|
log_err("bind socket fail: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, SOMAXCONN) < 0) {
|
||||||
|
log_err("listen socket fail: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_io_init(&rtty->iof, on_net_accept, sock, EV_READ);
|
||||||
|
ev_io_start (rtty->loop, &rtty->iof);
|
||||||
|
|
||||||
|
file_context.rtty = rtty;
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (sock > -1)
|
||||||
|
close (sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool detect_file_msg(uint8_t *buf, int len, int sid, int *type)
|
||||||
|
{
|
||||||
|
if (len != 4)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
len = buffer_get_u8(b, 1);
|
if (memcmp (buf, RTTY_FILE_MAGIC, sizeof (RTTY_FILE_MAGIC)))
|
||||||
|
|
||||||
if (buffer_length(b) < len + 2)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
buffer_pull(b, NULL, 2);
|
if (buf[3] != 'u' && buf[3] != 'd')
|
||||||
buffer_pull(b, tc->name, len);
|
return false;
|
||||||
|
|
||||||
tc->size = ntohl(buffer_pull_u32(b));
|
file_context.sid = sid;
|
||||||
|
*type = -1;
|
||||||
|
|
||||||
|
if (buf[3] == 'd')
|
||||||
|
*type = RTTY_FILE_MSG_START_DOWNLOAD;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_file_data(struct transfer_context *tc)
|
void recv_file(struct buffer *b, int len)
|
||||||
{
|
{
|
||||||
struct buffer *b = &tc->b;
|
struct buffer *wb = &file_context.wb;
|
||||||
ev_tstamp n = ev_time();
|
|
||||||
char unit = 'K';
|
|
||||||
float offset;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (buffer_length(b) < 3)
|
buffer_put_u8 (wb, buffer_pull_u8 (b));
|
||||||
return false;
|
buffer_put_u16 (wb, len - 1);
|
||||||
|
buffer_put_data (wb, buffer_data (b), len - 1);
|
||||||
|
buffer_pull (b, NULL, len - 1);
|
||||||
|
|
||||||
len = ntohs(buffer_get_u16(b, 1));
|
ev_io_start (file_context.rtty->loop, &file_context.iow);
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_length(b) < len + 3)
|
int connect_rtty_file_service()
|
||||||
return false;
|
{
|
||||||
|
struct sockaddr_un sun = {
|
||||||
|
.sun_family = AF_UNIX
|
||||||
|
};
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
buffer_pull(b, NULL, 3);
|
sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
|
if (sock < 0) {
|
||||||
if (tc->fd > 0) {
|
fprintf(stderr, "create socket fail: %s\n", strerror(errno));
|
||||||
buffer_pull_to_fd(b, tc->fd, len, NULL, NULL);
|
return -1;
|
||||||
} else {
|
|
||||||
/* skip */
|
|
||||||
buffer_pull(b, NULL, len);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tc->offset += len;
|
strcpy(sun.sun_path, RTTY_FILE_UNIX_SOCKET);
|
||||||
offset = tc->offset / 1024.0;
|
|
||||||
|
|
||||||
if ((int)offset / 1024 > 0) {
|
if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
|
||||||
offset = offset / 1024;
|
fprintf(stderr,"connect to rtty fail: %s\n", strerror(errno));
|
||||||
unit = 'M';
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" %d%% %.3f %cB %.3fs\r",
|
return sock;
|
||||||
(int)(tc->offset * 1.0 / tc->size * 100), offset, unit, n - tc->ts);
|
|
||||||
|
err:
|
||||||
|
if (sock > -1)
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detect_sid(char type)
|
||||||
|
{
|
||||||
|
uint8_t buf[4];
|
||||||
|
|
||||||
|
memcpy(buf, RTTY_FILE_MAGIC, 3);
|
||||||
|
buf[3] = type;
|
||||||
|
|
||||||
|
fwrite(buf, 4, 1, stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
usleep (10000);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_file(struct transfer_context *tc)
|
|
||||||
{
|
|
||||||
struct buffer *b = &tc->b;
|
|
||||||
int type;
|
|
||||||
|
|
||||||
while (buffer_length(b) > 0) {
|
|
||||||
type = buffer_get_u8(b, 0);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 0x01: /* file info */
|
|
||||||
if (!parse_file_info(tc))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
tc->ts = ev_time();
|
|
||||||
|
|
||||||
printf("Transferring '%s'...\r\n", tc->name);
|
|
||||||
|
|
||||||
tc->fd = open(tc->name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
|
||||||
if (tc->fd < 0) {
|
|
||||||
char magic_err[] = {0xB6, 0xBC, 'e'};
|
|
||||||
printf("Create '%s' failed: %s\r\n", tc->name, strerror(errno));
|
|
||||||
|
|
||||||
usleep(1000);
|
|
||||||
|
|
||||||
rf_write(STDOUT_FILENO, magic_err, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x02: /* file data */
|
|
||||||
if (!parse_file_data(tc))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case 0x03: /* file eof */
|
|
||||||
if (tc->fd > 0) {
|
|
||||||
close(tc->fd);
|
|
||||||
tc->fd = -1;
|
|
||||||
|
|
||||||
if (tc->mode == RF_RECV)
|
|
||||||
printf("\r\n");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
printf("error type\r\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stdin_read_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
|
||||||
{
|
|
||||||
struct transfer_context *tc = w->data;
|
|
||||||
bool eof = false;
|
|
||||||
|
|
||||||
buffer_put_fd(&tc->b, w->fd, -1, &eof, NULL, NULL);
|
|
||||||
|
|
||||||
if (parse_file(tc))
|
|
||||||
ev_io_stop(loop, w);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_cb(struct ev_loop *loop, ev_timer *w, int revents)
|
|
||||||
{
|
|
||||||
struct transfer_context *tc = w->data;
|
|
||||||
static uint8_t buf[RF_BLK_SIZE + 3];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
/* Canceled by user */
|
|
||||||
if (tc->fd < 0) {
|
|
||||||
buf[0] = 0x03;
|
|
||||||
rf_write(STDOUT_FILENO, buf, 1);
|
|
||||||
ev_break(loop, EVBREAK_ALL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = read(tc->fd, buf + 3, RF_BLK_SIZE);
|
|
||||||
if (len == 0) {
|
|
||||||
buf[0] = 0x03;
|
|
||||||
rf_write(STDOUT_FILENO, buf, 1);
|
|
||||||
ev_break(loop, EVBREAK_ALL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = 0x02;
|
|
||||||
*(uint16_t *)&buf[1] = htons(len);
|
|
||||||
|
|
||||||
rf_write(STDOUT_FILENO, buf, len + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void transfer_file(const char *name)
|
|
||||||
{
|
|
||||||
struct ev_loop *loop = EV_DEFAULT;
|
|
||||||
char magic[3] = {0xB6, 0xBC};
|
|
||||||
struct transfer_context tc = {};
|
|
||||||
const char *bname = "";
|
|
||||||
struct ev_timer t;
|
|
||||||
struct ev_io w;
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
bname = basename(name);
|
|
||||||
magic[2] = tc.mode = RF_SEND;
|
|
||||||
|
|
||||||
printf("Transferring '%s'...Press Ctrl+C to cancel\r\n", bname);
|
|
||||||
|
|
||||||
tc.fd = open(name, O_RDONLY);
|
|
||||||
if (tc.fd < 0) {
|
|
||||||
if (errno == ENOENT) {
|
|
||||||
printf("Open '%s' failed: No such file\r\n", name);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Open '%s' failed: %s\r\n", name, strerror(errno));
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fstat(tc.fd, &st);
|
|
||||||
tc.size = st.st_size;
|
|
||||||
|
|
||||||
if (!(st.st_mode & S_IFREG)) {
|
|
||||||
printf("'%s' is not a regular file\r\n", name);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
magic[2] = tc.mode = RF_RECV;
|
|
||||||
|
|
||||||
printf("rtty waiting to receive. Press Ctrl+C to cancel\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
set_stdin(true);
|
|
||||||
|
|
||||||
ev_io_init(&w, stdin_read_cb, STDIN_FILENO, EV_READ);
|
|
||||||
ev_io_start(loop, &w);
|
|
||||||
w.data = &tc;
|
|
||||||
|
|
||||||
rf_write(STDOUT_FILENO, magic, 3);
|
|
||||||
|
|
||||||
if (tc.mode == RF_SEND) {
|
|
||||||
uint8_t info[512] = {0x01};
|
|
||||||
|
|
||||||
ev_timer_init(&t, timer_cb, 0.01, 0.01);
|
|
||||||
ev_timer_start(loop, &t);
|
|
||||||
t.data = &tc;
|
|
||||||
|
|
||||||
info[1] = strlen(bname);
|
|
||||||
memcpy(info + 2, bname, strlen(bname));
|
|
||||||
*(uint32_t *)&info[2 + strlen(bname)] = htonl(tc.size);
|
|
||||||
|
|
||||||
rf_write(STDOUT_FILENO, info, 6 + strlen(bname));
|
|
||||||
}
|
|
||||||
|
|
||||||
ev_run(loop, 0);
|
|
||||||
|
|
||||||
set_stdin(false);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
38
src/file.h
38
src/file.h
@@ -22,30 +22,34 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _FILE_H
|
#ifndef RTTY_FILE_H
|
||||||
#define _FILE_H
|
#define RTTY_FILE_H
|
||||||
|
|
||||||
#include <uwsc/buffer.h>
|
#include "rtty.h"
|
||||||
#include <ev.h>
|
|
||||||
|
|
||||||
#define RF_BLK_SIZE 8912 /* 8KB */
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RF_SEND = 's',
|
RTTY_FILE_MSG_START_DOWNLOAD,
|
||||||
RF_RECV = 'r'
|
RTTY_FILE_MSG_INFO,
|
||||||
|
RTTY_FILE_MSG_DATA,
|
||||||
|
RTTY_FILE_MSG_CANCELED
|
||||||
};
|
};
|
||||||
|
|
||||||
struct transfer_context {
|
struct rtty_file_context {
|
||||||
int size;
|
int sock;
|
||||||
int offset;
|
int sid;
|
||||||
int mode;
|
bool running;
|
||||||
int fd;
|
struct buffer rb;
|
||||||
char name[512];
|
struct buffer wb;
|
||||||
ev_tstamp ts;
|
struct ev_io ior;
|
||||||
struct buffer b;
|
struct ev_io iow;
|
||||||
|
struct rtty *rtty;
|
||||||
};
|
};
|
||||||
|
|
||||||
void transfer_file(const char *name);
|
int start_file_service(struct rtty *rtty);
|
||||||
|
bool detect_file_msg(uint8_t *buf, int len, int sid, int *type);
|
||||||
|
void recv_file(struct buffer *b, int len);
|
||||||
|
int connect_rtty_file_service();
|
||||||
|
void detect_sid(char type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
1094
src/json.c
1094
src/json.c
File diff suppressed because it is too large
Load Diff
295
src/json.h
295
src/json.h
@@ -1,295 +0,0 @@
|
|||||||
|
|
||||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
|
|
||||||
* https://github.com/udp/json-parser
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JSON_H
|
|
||||||
#define _JSON_H
|
|
||||||
|
|
||||||
#ifndef json_char
|
|
||||||
#define json_char char
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef json_int_t
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#include <inttypes.h>
|
|
||||||
#define json_int_t int64_t
|
|
||||||
#else
|
|
||||||
#define json_int_t __int64
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned long max_memory;
|
|
||||||
int settings;
|
|
||||||
|
|
||||||
/* Custom allocator support (leave null to use malloc/free)
|
|
||||||
*/
|
|
||||||
|
|
||||||
void * (* mem_alloc) (size_t, int zero, void * user_data);
|
|
||||||
void (* mem_free) (void *, void * user_data);
|
|
||||||
|
|
||||||
void * user_data; /* will be passed to mem_alloc and mem_free */
|
|
||||||
|
|
||||||
size_t value_extra; /* how much extra space to allocate for values? */
|
|
||||||
|
|
||||||
} json_settings;
|
|
||||||
|
|
||||||
#define json_enable_comments 0x01
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
json_none,
|
|
||||||
json_object,
|
|
||||||
json_array,
|
|
||||||
json_integer,
|
|
||||||
json_double,
|
|
||||||
json_string,
|
|
||||||
json_boolean,
|
|
||||||
json_null
|
|
||||||
|
|
||||||
} json_type;
|
|
||||||
|
|
||||||
extern const struct _json_value json_value_none;
|
|
||||||
|
|
||||||
typedef struct _json_object_entry
|
|
||||||
{
|
|
||||||
json_char * name;
|
|
||||||
unsigned int name_length;
|
|
||||||
|
|
||||||
struct _json_value * value;
|
|
||||||
|
|
||||||
} json_object_entry;
|
|
||||||
|
|
||||||
typedef struct _json_value
|
|
||||||
{
|
|
||||||
struct _json_value * parent;
|
|
||||||
|
|
||||||
json_type type;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int boolean;
|
|
||||||
json_int_t integer;
|
|
||||||
double dbl;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned int length;
|
|
||||||
json_char * ptr; /* null terminated */
|
|
||||||
|
|
||||||
} string;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned int length;
|
|
||||||
|
|
||||||
json_object_entry * values;
|
|
||||||
|
|
||||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
|
||||||
decltype(values) begin () const
|
|
||||||
{ return values;
|
|
||||||
}
|
|
||||||
decltype(values) end () const
|
|
||||||
{ return values + length;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} object;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned int length;
|
|
||||||
struct _json_value ** values;
|
|
||||||
|
|
||||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
|
||||||
decltype(values) begin () const
|
|
||||||
{ return values;
|
|
||||||
}
|
|
||||||
decltype(values) end () const
|
|
||||||
{ return values + length;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} array;
|
|
||||||
|
|
||||||
} u;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct _json_value * next_alloc;
|
|
||||||
void * object_mem;
|
|
||||||
|
|
||||||
} _reserved;
|
|
||||||
|
|
||||||
#ifdef JSON_TRACK_SOURCE
|
|
||||||
|
|
||||||
/* Location of the value in the source JSON
|
|
||||||
*/
|
|
||||||
unsigned int line, col;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Some C++ operator sugar */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
inline _json_value ()
|
|
||||||
{ memset (this, 0, sizeof (_json_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const struct _json_value &operator [] (int index) const
|
|
||||||
{
|
|
||||||
if (type != json_array || index < 0
|
|
||||||
|| ((unsigned int) index) >= u.array.length)
|
|
||||||
{
|
|
||||||
return json_value_none;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *u.array.values [index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const struct _json_value &operator [] (const char * index) const
|
|
||||||
{
|
|
||||||
if (type != json_object)
|
|
||||||
return json_value_none;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < u.object.length; ++ i)
|
|
||||||
if (!strcmp (u.object.values [i].name, index))
|
|
||||||
return *u.object.values [i].value;
|
|
||||||
|
|
||||||
return json_value_none;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator const char * () const
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case json_string:
|
|
||||||
return u.string.ptr;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator json_int_t () const
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case json_integer:
|
|
||||||
return u.integer;
|
|
||||||
|
|
||||||
case json_double:
|
|
||||||
return (json_int_t) u.dbl;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator bool () const
|
|
||||||
{
|
|
||||||
if (type != json_boolean)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return u.boolean != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator double () const
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case json_integer:
|
|
||||||
return (double) u.integer;
|
|
||||||
|
|
||||||
case json_double:
|
|
||||||
return u.dbl;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} json_value;
|
|
||||||
|
|
||||||
json_value * json_parse (const json_char * json,
|
|
||||||
size_t length);
|
|
||||||
|
|
||||||
#define json_error_max 128
|
|
||||||
json_value * json_parse_ex (json_settings * settings,
|
|
||||||
const json_char * json,
|
|
||||||
size_t length,
|
|
||||||
char * error);
|
|
||||||
|
|
||||||
void json_value_free (json_value *);
|
|
||||||
|
|
||||||
|
|
||||||
/* Not usually necessary, unless you used a custom mem_alloc and now want to
|
|
||||||
* use a custom mem_free.
|
|
||||||
*/
|
|
||||||
void json_value_free_ex (json_settings * settings,
|
|
||||||
json_value *);
|
|
||||||
|
|
||||||
|
|
||||||
const json_value *json_get_value(const json_value *value, const char *name);
|
|
||||||
const char *json_get_string(const json_value *value, const char *name);
|
|
||||||
int json_get_int(const json_value *value, const char *name);
|
|
||||||
double json_get_double(const json_value *value, const char *name);
|
|
||||||
bool json_get_bool(const json_value *value, const char *name);
|
|
||||||
|
|
||||||
const char *json_get_array_string(const json_value *value, int index);
|
|
||||||
int json_get_array_int(const json_value *value, int index);
|
|
||||||
double json_get_array_double(const json_value *value, int index);
|
|
||||||
bool json_get_array_bool(const json_value *value, int index);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
130
src/log.c
Normal file
130
src/log.c
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
static int log_threshold = LOG_DEBUG;
|
||||||
|
static bool log_initialized;
|
||||||
|
static const char *ident;
|
||||||
|
|
||||||
|
void (*log_write)(int priority, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
static const char *log_ident()
|
||||||
|
{
|
||||||
|
FILE *self;
|
||||||
|
static char line[64];
|
||||||
|
char *p = NULL;
|
||||||
|
char *sbuf;
|
||||||
|
|
||||||
|
if ((self = fopen("/proc/self/status", "r")) != NULL) {
|
||||||
|
while (fgets(line, sizeof(line), self)) {
|
||||||
|
if (!strncmp(line, "Name:", 5)) {
|
||||||
|
strtok_r(line, "\t\n", &sbuf);
|
||||||
|
p = strtok_r(NULL, "\t\n", &sbuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void log_write_stdout(int priority, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
struct tm tm;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
localtime_r(&now, &tm);
|
||||||
|
strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", &tm);
|
||||||
|
|
||||||
|
fprintf(stderr, "%s ", buf);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void log_write_syslog(int priority, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
vsyslog(priority, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void log_init()
|
||||||
|
{
|
||||||
|
if (log_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ident = log_ident();
|
||||||
|
|
||||||
|
if (isatty(STDOUT_FILENO)) {
|
||||||
|
log_write = log_write_stdout;
|
||||||
|
} else {
|
||||||
|
log_write = log_write_syslog;
|
||||||
|
|
||||||
|
openlog(ident, 0, LOG_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_log_threshold(int threshold)
|
||||||
|
{
|
||||||
|
log_threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_close()
|
||||||
|
{
|
||||||
|
if (!log_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
log_initialized = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ilog(const char *filename, int line, int priority, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
static char new_fmt[256];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (priority > log_threshold)
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_init();
|
||||||
|
|
||||||
|
snprintf(new_fmt, sizeof(new_fmt), "(%s:%d) %s", filename, line, fmt);
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
log_write(priority, new_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
44
src/log.h
Normal file
44
src/log.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOG_H
|
||||||
|
#define _LOG_H
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void set_log_threshold(int threshold);
|
||||||
|
void log_close();
|
||||||
|
|
||||||
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||||
|
|
||||||
|
#define log(priority, fmt...) __ilog(__FILENAME__, __LINE__, priority, fmt)
|
||||||
|
|
||||||
|
#define log_debug(fmt...) log(LOG_DEBUG, fmt)
|
||||||
|
#define log_info(fmt...) log(LOG_INFO, fmt)
|
||||||
|
#define log_err(fmt...) log(LOG_ERR, fmt)
|
||||||
|
|
||||||
|
void __ilog(const char *filename, int line, int priority, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
525
src/main.c
525
src/main.c
@@ -22,471 +22,156 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pty.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <dirent.h>
|
#include <getopt.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <uwsc/uwsc.h>
|
|
||||||
|
|
||||||
#include "list.h"
|
#include "log.h"
|
||||||
#include "file.h"
|
#include "rtty.h"
|
||||||
#include "json.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utils.h"
|
#include "upfile.h"
|
||||||
#include "command.h"
|
#include "downfile.h"
|
||||||
|
|
||||||
#define RTTY_RECONNECT_INTERVAL 5
|
enum {
|
||||||
#define RTTY_MAX_SESSIONS 5
|
LONG_OPT_HELP = 1
|
||||||
#define RTTY_BUFFER_PERSISTENT_SIZE 4096
|
|
||||||
|
|
||||||
struct tty_session {
|
|
||||||
pid_t pid;
|
|
||||||
int pty;
|
|
||||||
int sid;
|
|
||||||
|
|
||||||
struct ev_loop *loop;
|
|
||||||
struct ev_timer timer;
|
|
||||||
struct uwsc_client *cl;
|
|
||||||
struct ev_io ior;
|
|
||||||
struct ev_io iow;
|
|
||||||
struct ev_child cw;
|
|
||||||
struct buffer wb;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static char login[128]; /* /bin/login */
|
|
||||||
static char server_url[512];
|
|
||||||
static char extra_header[128]; /* authorization token */
|
|
||||||
static char *username = NULL;
|
|
||||||
static bool auto_reconnect;
|
|
||||||
static int keepalive = 5; /* second */
|
|
||||||
static struct ev_timer reconnect_timer;
|
|
||||||
static struct tty_session *sessions[RTTY_MAX_SESSIONS + 1];
|
|
||||||
|
|
||||||
static void del_tty_session(struct tty_session *tty)
|
|
||||||
{
|
|
||||||
ev_io_stop(tty->loop, &tty->ior);
|
|
||||||
ev_io_stop(tty->loop, &tty->iow);
|
|
||||||
ev_timer_stop(tty->loop, &tty->timer);
|
|
||||||
ev_child_stop(tty->loop, &tty->cw);
|
|
||||||
|
|
||||||
buffer_free(&tty->wb);
|
|
||||||
|
|
||||||
close(tty->pty);
|
|
||||||
kill(tty->pid, SIGTERM);
|
|
||||||
|
|
||||||
sessions[tty->sid] = NULL;
|
|
||||||
|
|
||||||
uwsc_log_info("Del session: %d\n", tty->sid);
|
|
||||||
|
|
||||||
free(tty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct tty_session *find_tty_session(int sid)
|
|
||||||
{
|
|
||||||
if (sid > RTTY_MAX_SESSIONS)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return sessions[sid];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void del_tty_session_by_sid(int sid)
|
|
||||||
{
|
|
||||||
struct tty_session *tty = find_tty_session(sid);
|
|
||||||
if (tty)
|
|
||||||
del_tty_session(tty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pty_read_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
|
||||||
{
|
|
||||||
struct tty_session *tty = container_of(w, struct tty_session, ior);
|
|
||||||
struct uwsc_client *cl = tty->cl;
|
|
||||||
static uint8_t buf[4096 + 1];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
buf[0] = tty->sid;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
len = read(w->fd, buf + 1, sizeof(buf) - 1);
|
|
||||||
if (likely(len > 0))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (len < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EIO)
|
|
||||||
uwsc_log_err("Read from pty failed: %s\n", strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cl->send(cl, buf, len + 1, UWSC_OP_BINARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pty_write_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
|
||||||
{
|
|
||||||
struct tty_session *tty = container_of(w, struct tty_session, iow);
|
|
||||||
struct buffer *wb = &tty->wb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = buffer_pull_to_fd(wb, w->fd, buffer_length(wb), NULL, NULL);
|
|
||||||
if (ret < 0) {
|
|
||||||
uwsc_log_err("Write to pty failed: %s\n", strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer_length(wb) < 1)
|
|
||||||
ev_io_stop(loop, w);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pty_on_exit(struct ev_loop *loop, struct ev_child *w, int revents)
|
|
||||||
{
|
|
||||||
struct tty_session *tty = container_of(w, struct tty_session, cw);
|
|
||||||
char str[128] = "";
|
|
||||||
|
|
||||||
snprintf(str, sizeof(str) - 1, "{\"type\":\"logout\",\"sid\":%d}", tty->sid);
|
|
||||||
|
|
||||||
tty->cl->send(tty->cl, str, strlen(str), UWSC_OP_TEXT);
|
|
||||||
|
|
||||||
del_tty_session(tty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void new_tty_session(struct uwsc_client *cl, int sid)
|
|
||||||
{
|
|
||||||
struct tty_session *s;
|
|
||||||
char str[128] = "";
|
|
||||||
pid_t pid;
|
|
||||||
int pty;
|
|
||||||
|
|
||||||
s = calloc(1, sizeof(struct tty_session));
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pid = forkpty(&pty, NULL, NULL, NULL);
|
|
||||||
if (pid == 0)
|
|
||||||
username ? execl(login,"-p","-f", username , NULL) : execl(login, login, NULL);
|
|
||||||
|
|
||||||
s->cl = cl;
|
|
||||||
s->sid = sid;
|
|
||||||
s->pid = pid;
|
|
||||||
s->pty = pty;
|
|
||||||
s->loop = cl->loop;
|
|
||||||
|
|
||||||
fcntl(pty, F_SETFL, fcntl(pty, F_GETFL, 0) | O_NONBLOCK);
|
|
||||||
|
|
||||||
ev_io_init(&s->ior, pty_read_cb, pty, EV_READ);
|
|
||||||
ev_io_start(cl->loop, &s->ior);
|
|
||||||
|
|
||||||
ev_io_init(&s->iow, pty_write_cb, pty, EV_WRITE);
|
|
||||||
|
|
||||||
ev_child_init(&s->cw, pty_on_exit, pid, 0);
|
|
||||||
ev_child_start(cl->loop, &s->cw);
|
|
||||||
|
|
||||||
buffer_set_persistent_size(&s->wb, RTTY_BUFFER_PERSISTENT_SIZE);
|
|
||||||
|
|
||||||
sessions[sid] = s;
|
|
||||||
|
|
||||||
/* Notifying the user that the session was successfully created */
|
|
||||||
snprintf(str, sizeof(str) - 1, "{\"type\":\"login\",\"sid\":%d,\"code\":0}", sid);
|
|
||||||
cl->send(cl, str, strlen(str), UWSC_OP_TEXT);
|
|
||||||
|
|
||||||
uwsc_log_info("New session:%llu\n", sid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void change_winsize(int sid, int cols, int rows)
|
|
||||||
{
|
|
||||||
struct tty_session *tty = find_tty_session(sid);
|
|
||||||
struct winsize size = {
|
|
||||||
.ws_col = cols,
|
|
||||||
.ws_row = rows
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!tty) {
|
|
||||||
uwsc_log_err("non-existent sid: %d\n", sid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ioctl(tty->pty, TIOCSWINSZ, &size) < 0)
|
|
||||||
uwsc_log_err("ioctl TIOCSWINSZ error\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uwsc_onmessage(struct uwsc_client *cl, void *data, size_t len, bool binary)
|
|
||||||
{
|
|
||||||
if (binary) {
|
|
||||||
int sid = (*(uint8_t *)data);
|
|
||||||
struct tty_session *tty = find_tty_session(sid);
|
|
||||||
|
|
||||||
if (!tty) {
|
|
||||||
uwsc_log_err("non-existent sid: %d\n", sid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_put_data(&tty->wb, data + 1, len - 1);
|
|
||||||
ev_io_start(tty->loop, &tty->iow);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
const json_value *json;
|
|
||||||
const char *type;
|
|
||||||
int sid;
|
|
||||||
|
|
||||||
json = json_parse((char *)data, len);
|
|
||||||
if (!json) {
|
|
||||||
uwsc_log_err("Invalid format: [%.*s]\n", len, (char *)data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = json_get_string(json, "type");
|
|
||||||
if (!type || !type[0]) {
|
|
||||||
uwsc_log_err("Invalid format, not found type\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
sid = json_get_int(json, "sid");
|
|
||||||
|
|
||||||
if (!strcmp(type, "register")) {
|
|
||||||
uwsc_log_err("register failed: %s\n", json_get_string(json, "msg"));
|
|
||||||
ev_break(cl->loop, EVBREAK_ALL);
|
|
||||||
} else if (!strcmp(type, "login")) {
|
|
||||||
if (sid > RTTY_MAX_SESSIONS) {
|
|
||||||
char str[128] = "";
|
|
||||||
/* Notifies the user that the session creation failed */
|
|
||||||
snprintf(str, sizeof(str) - 1, "{\"type\":\"login\",\"sid\":%d,\"err\":2,\"msg\":\"sessions is full\"}", sid);
|
|
||||||
cl->send(cl, str, strlen(str), UWSC_OP_TEXT);
|
|
||||||
uwsc_log_err("Can only run up to 5 sessions at the same time\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
new_tty_session(cl, sid);
|
|
||||||
} if (!strcmp(type, "logout")) {
|
|
||||||
del_tty_session_by_sid(sid);
|
|
||||||
} if (!strcmp(type, "cmd")) {
|
|
||||||
run_command(cl, json);
|
|
||||||
return;
|
|
||||||
} if (!strcmp(type, "winsize")) {
|
|
||||||
int cols = json_get_int(json, "cols");
|
|
||||||
int rows = json_get_int(json, "rows");
|
|
||||||
change_winsize(sid, cols, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
json_value_free((json_value *)json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uwsc_onopen(struct uwsc_client *cl)
|
|
||||||
{
|
|
||||||
uwsc_log_info("Connect to server succeed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uwsc_onerror(struct uwsc_client *cl, int err, const char *msg)
|
|
||||||
{
|
|
||||||
struct ev_loop *loop = cl->loop;
|
|
||||||
|
|
||||||
uwsc_log_err("onerror:%d: %s\n", err, msg);
|
|
||||||
|
|
||||||
free(cl);
|
|
||||||
|
|
||||||
if (auto_reconnect)
|
|
||||||
ev_timer_again(loop, &reconnect_timer);
|
|
||||||
else
|
|
||||||
ev_break(loop, EVBREAK_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uwsc_onclose(struct uwsc_client *cl, int code, const char *reason)
|
|
||||||
{
|
|
||||||
struct ev_loop *loop = cl->loop;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
uwsc_log_err("onclose:%d: %s\n", code, reason);
|
|
||||||
|
|
||||||
for (i = 0; i < RTTY_MAX_SESSIONS + 1; i++)
|
|
||||||
if (sessions[i])
|
|
||||||
del_tty_session(sessions[i]);
|
|
||||||
|
|
||||||
free(cl);
|
|
||||||
|
|
||||||
if (auto_reconnect)
|
|
||||||
ev_timer_again(loop, &reconnect_timer);
|
|
||||||
else
|
|
||||||
ev_break(loop, EVBREAK_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_connect(struct ev_loop *loop, struct ev_timer *w, int revents)
|
|
||||||
{
|
|
||||||
struct uwsc_client *cl = uwsc_new(loop, server_url, keepalive, extra_header);
|
|
||||||
if (cl) {
|
|
||||||
cl->onopen = uwsc_onopen;
|
|
||||||
cl->onmessage = uwsc_onmessage;
|
|
||||||
cl->onerror = uwsc_onerror;
|
|
||||||
cl->onclose = uwsc_onclose;
|
|
||||||
ev_timer_stop(cl->loop, &reconnect_timer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!auto_reconnect)
|
|
||||||
ev_break(loop, EVBREAK_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
||||||
{
|
{
|
||||||
if (w->signum == SIGINT) {
|
if (w->signum == SIGINT) {
|
||||||
ev_break(loop, EVBREAK_ALL);
|
ev_break(loop, EVBREAK_ALL);
|
||||||
uwsc_log_info("Normal quit\n");
|
log_info("Normal quit\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"id", required_argument, NULL, 'I'},
|
||||||
|
{"host", required_argument, NULL, 'h'},
|
||||||
|
{"port", required_argument, NULL, 'p'},
|
||||||
|
{"description", required_argument, NULL, 'd'},
|
||||||
|
{"token", required_argument, NULL, 't'},
|
||||||
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
|
{"version", no_argument, NULL, 'V'},
|
||||||
|
{"help", no_argument, NULL, LONG_OPT_HELP},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
static void usage(const char *prog)
|
static void usage(const char *prog)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [option]\n"
|
fprintf(stderr, "Usage: %s [option]\n"
|
||||||
" -I id # Set an ID for the device(Maximum 63 bytes, valid character:letter,\n"
|
" -I, --id=string Set an ID for the device(Maximum 63 bytes, valid\n"
|
||||||
" number, underline and short line)\n"
|
" character:letter, number, underline and short line)\n"
|
||||||
" -h host # Server's host or ipaddr\n"
|
" -h, --host=string Server's host or ipaddr(Default is localhost)\n"
|
||||||
" -p port # Server port(Default is 5912)\n"
|
" -p, --port=number Server port(Default is 5912)\n"
|
||||||
" -a # Auto reconnect to the server\n"
|
" -d, --description=string Adding a description to the device(Maximum 126 bytes)\n"
|
||||||
" -v # verbose\n"
|
" -a Auto reconnect to the server\n"
|
||||||
" -d # Adding a description to the device(Maximum 126 bytes)\n"
|
" -s SSL on\n"
|
||||||
" -s # SSL on\n"
|
" -D Run in the background\n"
|
||||||
" -k keepalive # keep alive in seconds for this client. Defaults to 5\n"
|
" -t, --token=string Authorization token\n"
|
||||||
" -b baseurl # Set a base url\n"
|
" -f username Skip a second login authentication. See man login(1) about the details\n"
|
||||||
" -V # Show version\n"
|
" -R Receive file\n"
|
||||||
" -D # Run in the background\n"
|
" -S file Send file\n"
|
||||||
" -R # Receive file\n"
|
" -v, --verbose verbose\n"
|
||||||
" -S file # Send file\n"
|
" -V, --version Show version\n"
|
||||||
" -t token # Authorization token\n"
|
" --help Show usage\n",
|
||||||
" -f username # Skip a second login authentication. See man login(1) about the details\n"
|
prog);
|
||||||
, prog);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int opt;
|
|
||||||
struct ev_loop *loop = EV_DEFAULT;
|
struct ev_loop *loop = EV_DEFAULT;
|
||||||
struct ev_signal signal_watcher;
|
struct ev_signal signal_watcher;
|
||||||
char devid[64] = "";
|
|
||||||
const char *baseurl = NULL;
|
|
||||||
const char *host = NULL;
|
|
||||||
int port = 5912;
|
|
||||||
char *description = NULL;
|
|
||||||
bool background = false;
|
bool background = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool ssl = false;
|
struct rtty rtty = {
|
||||||
|
.host = "localhost",
|
||||||
|
.port = 5912,
|
||||||
|
.loop = loop,
|
||||||
|
.sock = -1,
|
||||||
|
.sock_file = -1
|
||||||
|
};
|
||||||
|
int option_index;
|
||||||
|
int c;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "h:b:f:p:I:avd:sk:VDRS:t:")) != -1) {
|
while (true) {
|
||||||
switch (opt) {
|
c = getopt_long(argc, argv, "I:h:p:d:asDt:f:RS:vV", long_options, &option_index);
|
||||||
case 'h':
|
if (c == -1)
|
||||||
host = optarg;
|
|
||||||
break;
|
break;
|
||||||
case 'b':
|
|
||||||
baseurl = optarg;
|
switch (c) {
|
||||||
break;
|
case 'I':
|
||||||
case 'f':
|
rtty.devid = optarg;
|
||||||
username = optarg;
|
break;
|
||||||
break;
|
case 'h':
|
||||||
case 'p':
|
rtty.host = optarg;
|
||||||
port = atoi(optarg);
|
break;
|
||||||
break;
|
case 'p':
|
||||||
case 'I':
|
rtty.port = atoi(optarg);
|
||||||
strncpy(devid, optarg, sizeof(devid) - 1);
|
break;
|
||||||
break;
|
case 'd':
|
||||||
case 'a':
|
if (strlen(optarg) > 126) {
|
||||||
auto_reconnect = true;
|
log_err("Description too long\n");
|
||||||
break;
|
usage(argv[0]);
|
||||||
case 'v':
|
}
|
||||||
verbose = true;
|
rtty.description = optarg;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'a':
|
||||||
if (strlen(optarg) > 126) {
|
rtty.reconnect = true;
|
||||||
uwsc_log_err("Description too long\n");
|
break;
|
||||||
|
case 's':
|
||||||
|
rtty.ssl_on = true;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
background = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
rtty.token = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
rtty.username = optarg;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
download_file();
|
||||||
|
return 0;
|
||||||
|
case 'S':
|
||||||
|
upload_file(optarg);
|
||||||
|
return 0;
|
||||||
|
case 'v':
|
||||||
|
verbose = true;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
log_info("rtty version %s\n", RTTY_VERSION_STRING);
|
||||||
|
exit(0);
|
||||||
|
case LONG_OPT_HELP:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
break;
|
||||||
description = calloc(1, strlen(optarg) * 4);
|
default: /* '?' */
|
||||||
if (!description) {
|
usage(argv[0]);
|
||||||
uwsc_log_err("malloc failed:%s\n", strerror(errno));
|
break;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
urlencode(description, strlen(optarg) * 4, optarg, strlen(optarg));
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
ssl = true;
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
keepalive = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
uwsc_log_info("rtty version %s\n", RTTY_VERSION_STRING);
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
background = true;
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
transfer_file(NULL);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
transfer_file(optarg);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
snprintf(extra_header, sizeof(extra_header) - 1, "Authorization: %s\r\n", optarg);
|
|
||||||
break;
|
|
||||||
default: /* '?' */
|
|
||||||
usage(argv[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (background && daemon(0, 0))
|
if (background && daemon(0, 0))
|
||||||
uwsc_log_err("Can't run in the background: %s\n", strerror(errno));
|
log_err("Can't run in the background: %s\n", strerror(errno));
|
||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
uwsc_log_threshold(LOG_ERR);
|
set_log_threshold(LOG_ERR);
|
||||||
|
|
||||||
if (!devid[0]) {
|
log_info("rtty version %s\n", RTTY_VERSION_STRING);
|
||||||
uwsc_log_err("You must specify an id\n");
|
|
||||||
usage(argv[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid_id(devid)) {
|
|
||||||
uwsc_log_err("Invalid device id\n");
|
|
||||||
usage(argv[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!host || !port) {
|
|
||||||
uwsc_log_err("You must specify the host and port\n");
|
|
||||||
usage(argv[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
uwsc_log_info("libuwsc version %s\n", UWSC_VERSION_STRING);
|
|
||||||
uwsc_log_info("rtty version %s\n", RTTY_VERSION_STRING);
|
|
||||||
|
|
||||||
if (getuid() > 0) {
|
if (getuid() > 0) {
|
||||||
uwsc_log_err("Operation not permitted\n");
|
log_err("Operation not permitted, must be run as root\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (find_login(login, sizeof(login) - 1) < 0) {
|
|
||||||
uwsc_log_err("The program 'login' is not found\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(server_url, sizeof(server_url),
|
|
||||||
"ws%s://%s:%d%s/ws?device=1&devid=%s&description=%s&keepalive=%d",
|
|
||||||
ssl ? "s" : "", host, port, baseurl ? baseurl : "", devid, description ? description : "", keepalive);
|
|
||||||
|
|
||||||
free(description);
|
|
||||||
|
|
||||||
ev_timer_init(&reconnect_timer, do_connect, 0.0, RTTY_RECONNECT_INTERVAL);
|
|
||||||
ev_timer_start(loop, &reconnect_timer);
|
|
||||||
|
|
||||||
ev_signal_init(&signal_watcher, signal_cb, SIGINT);
|
ev_signal_init(&signal_watcher, signal_cb, SIGINT);
|
||||||
ev_signal_start(loop, &signal_watcher);
|
ev_signal_start(loop, &signal_watcher);
|
||||||
|
|
||||||
|
if (rtty_start(&rtty) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
ev_run(loop, 0);
|
ev_run(loop, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
171
src/net.c
Normal file
171
src/net.c
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include "net.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
struct net_context {
|
||||||
|
struct ev_timer tmr;
|
||||||
|
struct ev_io iow;
|
||||||
|
int sock;
|
||||||
|
void *arg;
|
||||||
|
void (*on_connected)(int sock, void *arg);
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *port2str(int port)
|
||||||
|
{
|
||||||
|
static char buffer[sizeof("65535\0")];
|
||||||
|
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "%u", port);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sock_write_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
struct net_context *ctx = w->data;
|
||||||
|
int err = 0;
|
||||||
|
socklen_t len = sizeof(err);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ev_io_stop(loop, w);
|
||||||
|
ev_timer_stop(loop, &ctx->tmr);
|
||||||
|
|
||||||
|
ret = getsockopt(w->fd, SOL_SOCKET, SO_ERROR, &err, &len);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err("getsockopt: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err > 0) {
|
||||||
|
log_err("network connect failed: %s\n", strerror(err));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->on_connected(w->fd, ctx->arg);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
close(w->fd);
|
||||||
|
ctx->on_connected(-1, ctx->arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
|
||||||
|
{
|
||||||
|
struct net_context *ctx = w->data;
|
||||||
|
|
||||||
|
log_err("network connect timeout\n");
|
||||||
|
|
||||||
|
ev_io_stop(loop, &ctx->iow);
|
||||||
|
close(ctx->sock);
|
||||||
|
ctx->on_connected(-1, ctx->arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wait_connect(struct ev_loop *loop, int sock, int timeout,
|
||||||
|
void (*on_connected)(int sock, void *arg), void *arg)
|
||||||
|
{
|
||||||
|
static struct net_context ctx;
|
||||||
|
|
||||||
|
ctx.arg = arg;
|
||||||
|
ctx.on_connected = on_connected;
|
||||||
|
|
||||||
|
ev_timer_init(&ctx.tmr, timer_cb, timeout, 0);
|
||||||
|
ctx.tmr.data = &ctx;
|
||||||
|
ev_timer_start(loop, &ctx.tmr);
|
||||||
|
|
||||||
|
ev_io_init(&ctx.iow, sock_write_cb, sock, EV_WRITE);
|
||||||
|
ctx.iow.data = &ctx;
|
||||||
|
ev_io_start (loop, &ctx.iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_connect(struct ev_loop *loop, const char *host, int port,
|
||||||
|
void (*on_connected)(int sock, void *arg), void *arg)
|
||||||
|
{
|
||||||
|
struct sockaddr *addr = NULL;
|
||||||
|
struct addrinfo *result, *rp;
|
||||||
|
struct addrinfo hints = {
|
||||||
|
.ai_family = AF_INET,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_flags = AI_ADDRCONFIG
|
||||||
|
};
|
||||||
|
int sock = -1;
|
||||||
|
int addr_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = getaddrinfo(host, port2str(port), &hints, &result);
|
||||||
|
if (ret) {
|
||||||
|
if (ret == EAI_SYSTEM) {
|
||||||
|
log_err("getaddrinfo failed: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_err("getaddrinfo failed: %s\n", gai_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||||
|
if (rp->ai_family == AF_INET) {
|
||||||
|
addr = rp->ai_addr;
|
||||||
|
addr_len = rp->ai_addrlen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!addr) {
|
||||||
|
log_err("getaddrinfo failed: Not found addr\n");
|
||||||
|
goto free_addrinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
log_err("create socket failed: %s\n", strerror(errno));
|
||||||
|
goto free_addrinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, addr, addr_len) < 0) {
|
||||||
|
if (errno != EINPROGRESS) {
|
||||||
|
log_err("connect failed: %s\n", strerror(errno));
|
||||||
|
close(sock);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
wait_connect(loop, sock, 3, on_connected, arg);
|
||||||
|
} else {
|
||||||
|
on_connected(sock, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_addrinfo:
|
||||||
|
freeaddrinfo(result);
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
33
src/net.h
Normal file
33
src/net.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTTY_NET_H
|
||||||
|
#define RTTY_NET_H
|
||||||
|
|
||||||
|
#include <ev.h>
|
||||||
|
|
||||||
|
int tcp_connect(struct ev_loop *loop, const char *host, int port,
|
||||||
|
void (*on_connected)(int sock, void *arg), void *arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
508
src/rtty.c
Normal file
508
src/rtty.c
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pty.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ssl.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "rtty.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
static char login_path[128]; /* /bin/login */
|
||||||
|
|
||||||
|
static void del_tty(struct tty *tty) {
|
||||||
|
struct rtty *rtty = tty->rtty;
|
||||||
|
struct ev_loop *loop = rtty->loop;
|
||||||
|
|
||||||
|
ev_io_stop(loop, &tty->ior);
|
||||||
|
ev_io_stop(loop, &tty->iow);
|
||||||
|
ev_child_stop(loop, &tty->cw);
|
||||||
|
|
||||||
|
buffer_free(&tty->wb);
|
||||||
|
|
||||||
|
close(tty->pty);
|
||||||
|
kill(tty->pid, SIGTERM);
|
||||||
|
|
||||||
|
rtty->ttys[tty->sid] = NULL;
|
||||||
|
|
||||||
|
log_info("delete tty: %d\n", tty->sid);
|
||||||
|
|
||||||
|
free(tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct tty *find_tty(struct rtty *rtty, int sid) {
|
||||||
|
if (sid > RTTY_MAX_TTY - 1)
|
||||||
|
return NULL;
|
||||||
|
return rtty->ttys[sid];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tty_logout(struct rtty *rtty, int sid) {
|
||||||
|
struct tty *tty = find_tty (rtty, sid);
|
||||||
|
if (tty)
|
||||||
|
del_tty (tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pty_on_read(struct ev_loop *loop, struct ev_io *w, int revents) {
|
||||||
|
struct tty *tty = container_of(w, struct tty, ior);
|
||||||
|
struct rtty *rtty = tty->rtty;
|
||||||
|
struct buffer *wb = &rtty->wb;
|
||||||
|
static uint8_t buf[4096];
|
||||||
|
int type;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
len = read(w->fd, buf, sizeof(buf));
|
||||||
|
if (likely(len > 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno != EIO)
|
||||||
|
log_err("read from pty failed: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!detect_file_msg(buf, len, tty->sid, &type)) {
|
||||||
|
buffer_put_u8 (wb, MSG_TYPE_TERMDATA);
|
||||||
|
buffer_put_u16 (wb, htons(len + 1));
|
||||||
|
buffer_put_u8 (wb, tty->sid);
|
||||||
|
buffer_put_data (wb, buf, len);
|
||||||
|
} else if (type > -1) {
|
||||||
|
buffer_put_u8 (wb, MSG_TYPE_FILE);
|
||||||
|
buffer_put_u16 (wb, htons(2));
|
||||||
|
buffer_put_u8 (wb, tty->sid);
|
||||||
|
buffer_put_u8 (wb, type);
|
||||||
|
}
|
||||||
|
ev_io_start(loop, &rtty->iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pty_on_write(struct ev_loop *loop, struct ev_io *w, int revents) {
|
||||||
|
struct tty *tty = container_of(w, struct tty, iow);
|
||||||
|
struct buffer *wb = &tty->wb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = buffer_pull_to_fd(wb, w->fd, buffer_length(wb), NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err("write to pty failed: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_length(wb) < 1)
|
||||||
|
ev_io_stop(loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pty_on_exit(struct ev_loop *loop, struct ev_child *w, int revents) {
|
||||||
|
struct tty *tty = container_of(w, struct tty, cw);
|
||||||
|
struct rtty *rtty = tty->rtty;
|
||||||
|
struct buffer *wb = &rtty->wb;
|
||||||
|
|
||||||
|
del_tty (tty);
|
||||||
|
|
||||||
|
buffer_put_u8 (wb, MSG_TYPE_LOGOUT);
|
||||||
|
buffer_put_u16 (wb, htons(1));
|
||||||
|
buffer_put_u8 (wb, tty->sid);
|
||||||
|
ev_io_start(loop, &rtty->iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tty_login(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
struct tty *tty;
|
||||||
|
pid_t pid;
|
||||||
|
int pty;
|
||||||
|
int sid;
|
||||||
|
|
||||||
|
buffer_put_u8 (&rtty->wb, MSG_TYPE_LOGIN);
|
||||||
|
|
||||||
|
for (sid = 0; sid < RTTY_MAX_TTY; sid++) {
|
||||||
|
if (!rtty->ttys[sid])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sid == RTTY_MAX_TTY) {
|
||||||
|
log_info ("tty login fail, device busy\n");
|
||||||
|
buffer_put_u16 (&rtty->wb, htons(1));
|
||||||
|
buffer_put_u8 (&rtty->wb, 1);
|
||||||
|
ev_io_start (rtty->loop, &rtty->iow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tty = calloc(1, sizeof(struct tty));
|
||||||
|
|
||||||
|
pid = forkpty(&pty, NULL, NULL, NULL);
|
||||||
|
if (pid == 0)
|
||||||
|
rtty->username ? execl(login_path, "-p", "-f", rtty->username, NULL) : execl(login_path, login_path, NULL);
|
||||||
|
|
||||||
|
tty->sid = sid;
|
||||||
|
tty->pid = pid;
|
||||||
|
tty->pty = pty;
|
||||||
|
tty->rtty = rtty;
|
||||||
|
|
||||||
|
fcntl(pty, F_SETFL, fcntl(pty, F_GETFL, 0) | O_NONBLOCK);
|
||||||
|
|
||||||
|
ev_io_init(&tty->ior, pty_on_read, pty, EV_READ);
|
||||||
|
ev_io_start(rtty->loop, &tty->ior);
|
||||||
|
|
||||||
|
ev_io_init(&tty->iow, pty_on_write, pty, EV_WRITE);
|
||||||
|
|
||||||
|
ev_child_init(&tty->cw, pty_on_exit, pid, 0);
|
||||||
|
ev_child_start(rtty->loop, &tty->cw);
|
||||||
|
|
||||||
|
buffer_set_persistent_size(&tty->wb, RTTY_BUFFER_PERSISTENT_SIZE);
|
||||||
|
|
||||||
|
rtty->ttys[sid] = tty;
|
||||||
|
|
||||||
|
buffer_put_u16 (&rtty->wb, htons(2));
|
||||||
|
buffer_put_u8 (&rtty->wb, 0);
|
||||||
|
buffer_put_u8 (&rtty->wb, sid);
|
||||||
|
ev_io_start (rtty->loop, &rtty->iow);
|
||||||
|
|
||||||
|
log_info("new tty: %d\n", sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_data_to_tty(struct rtty *rtty, int sid, int len)
|
||||||
|
{
|
||||||
|
struct tty *tty = find_tty (rtty, sid);
|
||||||
|
if (!tty) {
|
||||||
|
log_err("non-existent sid: %d\n", sid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_put_data (&tty->wb, buffer_data (&rtty->rb), len);
|
||||||
|
buffer_pull(&rtty->rb, NULL, len);
|
||||||
|
ev_io_start(rtty->loop, &tty->iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_tty_winsize(struct rtty *rtty, int sid)
|
||||||
|
{
|
||||||
|
struct tty *tty = find_tty (rtty, sid);
|
||||||
|
struct winsize size;
|
||||||
|
|
||||||
|
if (!tty) {
|
||||||
|
log_err("non-existent sid: %d\n", sid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size.ws_col = ntohs(buffer_pull_u16 (&rtty->rb));
|
||||||
|
size.ws_row = ntohs(buffer_pull_u16 (&rtty->rb));
|
||||||
|
|
||||||
|
if (ioctl(tty->pty, TIOCSWINSZ, &size) < 0)
|
||||||
|
log_err("ioctl TIOCSWINSZ failed: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtty_exit(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
close(rtty->sock);
|
||||||
|
rtty->sock = -1;
|
||||||
|
|
||||||
|
if (rtty->sock_file > -1) {
|
||||||
|
close (rtty->sock_file);
|
||||||
|
rtty->sock_file = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_io_stop (rtty->loop, &rtty->ior);
|
||||||
|
ev_io_stop (rtty->loop, &rtty->iow);
|
||||||
|
ev_io_stop (rtty->loop, &rtty->iof);
|
||||||
|
|
||||||
|
for (int i = 0; i < RTTY_MAX_TTY; i++)
|
||||||
|
if (rtty->ttys[i])
|
||||||
|
del_tty (rtty->ttys[i]);
|
||||||
|
|
||||||
|
if (!rtty->reconnect)
|
||||||
|
ev_break (rtty->loop, EVBREAK_ALL);
|
||||||
|
|
||||||
|
#if RTTY_SSL_SUPPORT
|
||||||
|
rtty_ssl_free(rtty->ssl);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtty_register(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
size_t len = 3 + strlen(rtty->devid);
|
||||||
|
struct buffer *wb = &rtty->wb;
|
||||||
|
|
||||||
|
if (rtty->description)
|
||||||
|
len += strlen(rtty->description);
|
||||||
|
|
||||||
|
if (rtty->token)
|
||||||
|
len += strlen(rtty->token);
|
||||||
|
|
||||||
|
buffer_put_u8(wb, MSG_TYPE_REGISTER);
|
||||||
|
buffer_put_u16(wb, htons(len));
|
||||||
|
|
||||||
|
buffer_put_string(wb, rtty->devid);
|
||||||
|
buffer_put_u8(wb, '\0');
|
||||||
|
|
||||||
|
if (rtty->description)
|
||||||
|
buffer_put_string(wb, rtty->description);
|
||||||
|
buffer_put_u8(wb, '\0');
|
||||||
|
|
||||||
|
if (rtty->token)
|
||||||
|
buffer_put_string(wb, rtty->token);
|
||||||
|
buffer_put_u8(wb, '\0');
|
||||||
|
|
||||||
|
ev_io_start(rtty->loop, &rtty->iow);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_msg(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
struct buffer *rb = &rtty->rb;
|
||||||
|
int msgtype;
|
||||||
|
int msglen;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (buffer_length (rb) < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
msglen = ntohs(buffer_get_u16 (rb, 1));
|
||||||
|
if (buffer_length (rb) < msglen + 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
msgtype = buffer_pull_u8 (rb);
|
||||||
|
buffer_pull_u16 (rb);
|
||||||
|
|
||||||
|
switch (msgtype) {
|
||||||
|
case MSG_TYPE_REGISTER:
|
||||||
|
if (buffer_pull_u8 (rb)) {
|
||||||
|
char errs[128] = "";
|
||||||
|
buffer_pull (rb, errs, msglen - 1);
|
||||||
|
rtty_exit (rtty);
|
||||||
|
log_err("register fail: %s\n", errs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer_pull (rb, NULL, msglen - 1);
|
||||||
|
log_info ("register success\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_LOGIN:
|
||||||
|
tty_login (rtty);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_LOGOUT:
|
||||||
|
tty_logout (rtty, buffer_pull_u8 (rb));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_TERMDATA:
|
||||||
|
write_data_to_tty (rtty, buffer_pull_u8 (rb), msglen - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_WINSIZE:
|
||||||
|
set_tty_winsize (rtty, buffer_pull_u8 (rb));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_CMD:
|
||||||
|
run_command (rtty, buffer_data (rb));
|
||||||
|
buffer_pull (rb, NULL, msglen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_HEARTBEAT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_TYPE_FILE:
|
||||||
|
recv_file(rb, msglen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_err ("invalid message type: %d\n", msgtype);
|
||||||
|
rtty_exit (rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_read(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
struct rtty *rtty = container_of (w, struct rtty, ior);
|
||||||
|
bool eof;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#if RTTY_SSL_SUPPORT
|
||||||
|
if (rtty->ssl)
|
||||||
|
ret = buffer_put_fd(&rtty->rb, w->fd, -1, &eof, rtty_ssl_read, rtty->ssl);
|
||||||
|
else
|
||||||
|
ret = buffer_put_fd(&rtty->rb, w->fd, -1, &eof, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err("socket read error: %s\n", strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtty->active = ev_now(loop);
|
||||||
|
|
||||||
|
parse_msg(rtty);
|
||||||
|
|
||||||
|
if (eof) {
|
||||||
|
log_info ("socket closed by server\n");
|
||||||
|
rtty_exit (rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_write(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
struct rtty *rtty = container_of (w, struct rtty, iow);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#if RTTY_SSL_SUPPORT
|
||||||
|
if (rtty->ssl) {
|
||||||
|
if (!rtty->ssl_handshaked) {
|
||||||
|
ret = rtty_ssl_handshake(rtty->ssl);
|
||||||
|
if (ret == -1) {
|
||||||
|
log_err("ssl handshake failed\n");
|
||||||
|
rtty_exit(rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ret != 1)
|
||||||
|
return;
|
||||||
|
rtty->ssl_handshaked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtty->ssl)
|
||||||
|
ret = buffer_pull_to_fd (&rtty->wb, w->fd, -1, rtty_ssl_write, rtty->ssl);
|
||||||
|
else
|
||||||
|
ret = buffer_pull_to_fd (&rtty->wb, w->fd, -1, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
log_err ("socket write error: %s\n", strerror(errno));
|
||||||
|
rtty_exit(rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_length (&rtty->wb) < 1)
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_connected(int sock, void *arg)
|
||||||
|
{
|
||||||
|
struct rtty *rtty = arg;
|
||||||
|
|
||||||
|
if (sock < 0) {
|
||||||
|
if (!rtty->reconnect)
|
||||||
|
ev_break (rtty->loop, EVBREAK_ALL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info ("connected to server\n");
|
||||||
|
|
||||||
|
rtty->sock = sock;
|
||||||
|
|
||||||
|
ev_io_init(&rtty->ior, on_net_read, sock, EV_READ);
|
||||||
|
ev_io_start (rtty->loop, &rtty->ior);
|
||||||
|
|
||||||
|
ev_io_init(&rtty->iow, on_net_write, sock, EV_WRITE);
|
||||||
|
|
||||||
|
rtty->sock_file = start_file_service(rtty);
|
||||||
|
|
||||||
|
if (rtty->ssl_on) {
|
||||||
|
#if (RTTY_SSL_SUPPORT)
|
||||||
|
rtty_ssl_init((struct rtty_ssl_ctx **)&rtty->ssl, sock, rtty->host);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
rtty_register(rtty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtty_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
|
||||||
|
{
|
||||||
|
struct rtty *rtty = container_of (w, struct rtty, tmr);
|
||||||
|
ev_tstamp now = ev_now(loop);
|
||||||
|
|
||||||
|
if (rtty->sock < 0) {
|
||||||
|
if (now - rtty->active < 5)
|
||||||
|
return;
|
||||||
|
rtty->active = now;
|
||||||
|
log_err ("rtty reconnecting...\n");
|
||||||
|
tcp_connect(rtty->loop, rtty->host, rtty->port, on_net_connected, rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now - rtty->active > RTTY_HEARTBEAT_INTEVAL * 3 / 2) {
|
||||||
|
log_err("Inactive too long time\n");
|
||||||
|
rtty_exit(rtty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now - rtty->last_heartbeat > RTTY_HEARTBEAT_INTEVAL - 1) {
|
||||||
|
rtty->last_heartbeat = now;
|
||||||
|
rtty_send_msg(rtty, MSG_TYPE_HEARTBEAT, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtty_start(struct rtty *rtty)
|
||||||
|
{
|
||||||
|
if (rtty->ssl_on) {
|
||||||
|
#if (!RTTY_SSL_SUPPORT)
|
||||||
|
log_err("SSL is not enabled at compile\n");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rtty->devid) {
|
||||||
|
log_err("you must specify an id for your device\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid_id(rtty->devid)) {
|
||||||
|
log_err("invalid device id\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_login(login_path, sizeof(login_path) - 1) < 0) {
|
||||||
|
log_err("the program 'login' is not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_timer_init(&rtty->tmr, rtty_timer_cb, 1.0, 1.0);
|
||||||
|
ev_timer_start(rtty->loop, &rtty->tmr);
|
||||||
|
|
||||||
|
if (tcp_connect(rtty->loop, rtty->host, rtty->port, on_net_connected, rtty) < 0
|
||||||
|
&& !rtty->reconnect)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rtty->active = ev_now(rtty->loop);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtty_send_msg(struct rtty *rtty, int type, void *data, int len)
|
||||||
|
{
|
||||||
|
struct buffer *wb = &rtty->wb;
|
||||||
|
buffer_put_u8 (wb, type);
|
||||||
|
buffer_put_u16 (wb, htons(len));
|
||||||
|
buffer_put_data(wb, data, len);
|
||||||
|
ev_io_start (rtty->loop, &rtty->iow);
|
||||||
|
}
|
||||||
89
src/rtty.h
Normal file
89
src/rtty.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTTY_RTTY_H
|
||||||
|
#define RTTY_RTTY_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <ev.h>
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#define RTTY_MAX_TTY 5
|
||||||
|
#define RTTY_HEARTBEAT_INTEVAL 5.0
|
||||||
|
#define RTTY_BUFFER_PERSISTENT_SIZE 4096
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_TYPE_REGISTER = 0x00,
|
||||||
|
MSG_TYPE_LOGIN = 0x01,
|
||||||
|
MSG_TYPE_LOGOUT = 0x02,
|
||||||
|
MSG_TYPE_TERMDATA = 0x03,
|
||||||
|
MSG_TYPE_WINSIZE = 0x04,
|
||||||
|
MSG_TYPE_CMD = 0x05,
|
||||||
|
MSG_TYPE_HEARTBEAT = 0x06,
|
||||||
|
MSG_TYPE_FILE = 0x07
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rtty;
|
||||||
|
|
||||||
|
struct tty {
|
||||||
|
pid_t pid;
|
||||||
|
int pty;
|
||||||
|
int sid;
|
||||||
|
struct ev_io ior;
|
||||||
|
struct ev_io iow;
|
||||||
|
struct ev_child cw;
|
||||||
|
struct buffer wb;
|
||||||
|
struct rtty *rtty;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rtty {
|
||||||
|
const char *host;
|
||||||
|
int port;
|
||||||
|
int sock;
|
||||||
|
int sock_file;
|
||||||
|
const char *devid;
|
||||||
|
const char *token; /* authorization token */
|
||||||
|
const char *description;
|
||||||
|
const char *username;
|
||||||
|
bool ssl_on;
|
||||||
|
struct buffer rb;
|
||||||
|
struct buffer wb;
|
||||||
|
struct ev_io iow;
|
||||||
|
struct ev_io ior;
|
||||||
|
struct ev_io iof;
|
||||||
|
struct ev_timer tmr;
|
||||||
|
struct ev_loop *loop;
|
||||||
|
ev_tstamp active;
|
||||||
|
ev_tstamp last_heartbeat;
|
||||||
|
bool reconnect;
|
||||||
|
void *ssl; /* Context wrap of openssl, wolfssl and mbedtls */
|
||||||
|
bool ssl_handshaked;
|
||||||
|
struct tty *ttys[RTTY_MAX_TTY];
|
||||||
|
};
|
||||||
|
|
||||||
|
int rtty_start(struct rtty *rtty);
|
||||||
|
void rtty_send_msg(struct rtty *rtty, int type, void *data, int len);
|
||||||
|
|
||||||
|
#endif
|
||||||
219
src/ssl.c
Normal file
219
src/ssl.c
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "ssl.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#if RTTY_SSL_SUPPORT
|
||||||
|
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
#include <mbedtls/ssl.h>
|
||||||
|
#include <mbedtls/entropy.h>
|
||||||
|
#include <mbedtls/ctr_drbg.h>
|
||||||
|
#include <mbedtls/net_sockets.h>
|
||||||
|
|
||||||
|
struct rtty_ssl_ctx {
|
||||||
|
mbedtls_net_context net;
|
||||||
|
mbedtls_ssl_context ssl;
|
||||||
|
mbedtls_ssl_config cfg;
|
||||||
|
mbedtls_ctr_drbg_context drbg;
|
||||||
|
mbedtls_entropy_context etpy;
|
||||||
|
mbedtls_x509_crt x509;
|
||||||
|
bool last_read_ok;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if RTTY_HAVE_OPENSSL
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#elif RTTY_HAVE_WOLFSSL
|
||||||
|
#define WC_NO_HARDEN
|
||||||
|
#include <wolfssl/openssl/ssl.h>
|
||||||
|
#include <wolfssl/openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct rtty_ssl_ctx {
|
||||||
|
SSL_CTX *ctx;
|
||||||
|
SSL *ssl;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int rtty_ssl_init(struct rtty_ssl_ctx **ctx, int sock, const char *host)
|
||||||
|
{
|
||||||
|
struct rtty_ssl_ctx *c = calloc(1, sizeof(struct rtty_ssl_ctx));
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
log_err("calloc failed: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
mbedtls_net_init(&c->net);
|
||||||
|
mbedtls_ssl_init(&c->ssl);
|
||||||
|
mbedtls_ssl_config_init(&c->cfg);
|
||||||
|
mbedtls_ctr_drbg_init(&c->drbg);
|
||||||
|
mbedtls_x509_crt_init(&c->x509);
|
||||||
|
|
||||||
|
mbedtls_entropy_init(&c->etpy);
|
||||||
|
mbedtls_ctr_drbg_seed(&c->drbg, mbedtls_entropy_func, &c->etpy, NULL, 0);
|
||||||
|
|
||||||
|
mbedtls_ssl_config_defaults(&c->cfg, MBEDTLS_SSL_IS_CLIENT,
|
||||||
|
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_authmode(&c->cfg, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||||
|
mbedtls_ssl_conf_ca_chain(&c->cfg, &c->x509, NULL);
|
||||||
|
mbedtls_ssl_conf_rng(&c->cfg, mbedtls_ctr_drbg_random, &c->drbg);
|
||||||
|
|
||||||
|
mbedtls_ssl_set_bio(&c->ssl, &c->net, mbedtls_net_send,
|
||||||
|
mbedtls_net_recv, NULL);
|
||||||
|
mbedtls_ssl_set_hostname(&c->ssl, host);
|
||||||
|
|
||||||
|
mbedtls_ssl_setup(&c->ssl, &c->cfg);
|
||||||
|
|
||||||
|
c->net.fd = sock;
|
||||||
|
#else
|
||||||
|
#if UHTTPD_HAVE_WOLFSSL
|
||||||
|
wolfSSL_Init();
|
||||||
|
|
||||||
|
c->ctx = SSL_CTX_new(TLSv1_2_client_method());
|
||||||
|
#elif OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
SSL_library_init();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
|
||||||
|
c->ctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
|
#else
|
||||||
|
c->ctx = SSL_CTX_new(TLS_client_method());
|
||||||
|
#endif
|
||||||
|
SSL_CTX_set_verify(c->ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
c->ssl = SSL_new(c->ctx);
|
||||||
|
SSL_set_tlsext_host_name(c->ssl, host);
|
||||||
|
SSL_set_fd(c->ssl, sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*ctx = c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtty_ssl_handshake(struct rtty_ssl_ctx *ctx)
|
||||||
|
{
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
int ret = mbedtls_ssl_handshake(&ctx->ssl);
|
||||||
|
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||||
|
return 0;
|
||||||
|
if (ret == 0)
|
||||||
|
return 1;
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
int ret = SSL_connect(ctx->ssl);
|
||||||
|
if (ret == 1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
int err = SSL_get_error(ctx->ssl, ret);
|
||||||
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
|
||||||
|
return 0;
|
||||||
|
log_err("%s\n", ERR_reason_error_string(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtty_ssl_free(struct rtty_ssl_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
mbedtls_ssl_free(&ctx->ssl);
|
||||||
|
mbedtls_ssl_config_free(&ctx->cfg);
|
||||||
|
#else
|
||||||
|
SSL_shutdown(ctx->ssl);
|
||||||
|
SSL_CTX_free(ctx->ctx);
|
||||||
|
#endif
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtty_ssl_read(int fd, void *buf, size_t count, void *arg)
|
||||||
|
{
|
||||||
|
struct rtty_ssl_ctx *ctx = arg;
|
||||||
|
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (ctx->last_read_ok) {
|
||||||
|
ctx->last_read_ok = false;
|
||||||
|
return P_FD_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mbedtls_ssl_read(&ctx->ssl, buf, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == MBEDTLS_ERR_SSL_WANT_READ)
|
||||||
|
return P_FD_PENDING;
|
||||||
|
return P_FD_ERR;
|
||||||
|
}
|
||||||
|
if (ret > 0)
|
||||||
|
ctx->last_read_ok = true;
|
||||||
|
#else
|
||||||
|
int ret = SSL_read(ctx->ssl, buf, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
int err = SSL_get_error(ctx->ssl, ret);
|
||||||
|
if (err == SSL_ERROR_WANT_READ)
|
||||||
|
return P_FD_PENDING;
|
||||||
|
log_err("%s\n", ERR_reason_error_string(err));
|
||||||
|
return P_FD_ERR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtty_ssl_write(int fd, void *buf, size_t count, void *arg)
|
||||||
|
{
|
||||||
|
struct rtty_ssl_ctx *ctx = arg;
|
||||||
|
|
||||||
|
#if RTTY_HAVE_MBEDTLS
|
||||||
|
int ret = mbedtls_ssl_write(&ctx->ssl, buf, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||||
|
return P_FD_PENDING;
|
||||||
|
return P_FD_ERR;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int ret = SSL_write(ctx->ssl, buf, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
int err = SSL_get_error(ctx->ssl, ret);
|
||||||
|
if (err == SSL_ERROR_WANT_WRITE)
|
||||||
|
return P_FD_PENDING;
|
||||||
|
log_err("%s\n", ERR_reason_error_string(err));
|
||||||
|
return P_FD_ERR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
46
src/ssl.h
Normal file
46
src/ssl.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTTY_SSL_H
|
||||||
|
#define RTTY_SSL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if RTTY_SSL_SUPPORT
|
||||||
|
|
||||||
|
struct rtty_ssl_ctx;
|
||||||
|
|
||||||
|
int rtty_ssl_init(struct rtty_ssl_ctx **ctx, int sock, const char *host);
|
||||||
|
int rtty_ssl_handshake(struct rtty_ssl_ctx *ctx);
|
||||||
|
void rtty_ssl_free(struct rtty_ssl_ctx *ctx);
|
||||||
|
|
||||||
|
int rtty_ssl_read(int fd, void *buf, size_t count, void *arg);
|
||||||
|
int rtty_ssl_write(int fd, void *buf, size_t count, void *arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
157
src/upfile.c
Normal file
157
src/upfile.c
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static struct buffer b;
|
||||||
|
static uint32_t remain;
|
||||||
|
static uint32_t file_size;
|
||||||
|
static ev_tstamp start_time;
|
||||||
|
static struct ev_io iow;
|
||||||
|
static struct ev_io ior;
|
||||||
|
static struct ev_signal sw;
|
||||||
|
static bool canceled;
|
||||||
|
|
||||||
|
static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
||||||
|
{
|
||||||
|
canceled = true;
|
||||||
|
ev_signal_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_net_write(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
int ret = buffer_pull_to_fd (&b, w->fd, -1, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr,"socket write error: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_length (&b) < 1)
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_file_read(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
|
{
|
||||||
|
uint8_t buf[4096];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (canceled) {
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
|
||||||
|
buffer_put_u8 (&b, RTTY_FILE_MSG_CANCELED);
|
||||||
|
buffer_put_u16 (&b, 0);
|
||||||
|
ev_io_start (loop, &iow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_length (&b) > 4096 * 10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = read(w->fd, buf, sizeof (buf));
|
||||||
|
|
||||||
|
buffer_put_u8 (&b, RTTY_FILE_MSG_DATA);
|
||||||
|
buffer_put_u16 (&b, ret);
|
||||||
|
buffer_put_data (&b, buf, ret);
|
||||||
|
ev_io_start (loop, &iow);
|
||||||
|
|
||||||
|
remain -= ret;
|
||||||
|
|
||||||
|
fprintf (stdout, "%100c\r", ' ');
|
||||||
|
fprintf(stdout," %lu%% %s %.3lfs\r",
|
||||||
|
(file_size - remain) * 100UL / file_size,
|
||||||
|
format_size(file_size - remain), ev_now(loop) - start_time);
|
||||||
|
fflush (stdout);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ev_io_stop (loop, w);
|
||||||
|
ev_signal_stop (loop, &sw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upload_file(const char *name)
|
||||||
|
{
|
||||||
|
struct ev_loop *loop = EV_DEFAULT;
|
||||||
|
const char *bname = basename(name);
|
||||||
|
struct stat st;
|
||||||
|
int sock = -1;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
fd = open(name, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf (stderr, "open '%s' failed: ", name);
|
||||||
|
if (errno == ENOENT)
|
||||||
|
fprintf(stderr,"No such file\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr,"%s\n", strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstat(fd, &st);
|
||||||
|
if (!(st.st_mode & S_IFREG)) {
|
||||||
|
fprintf(stderr,"'%s' is not a regular file\n", name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
remain = file_size = st.st_size;
|
||||||
|
|
||||||
|
sock = connect_rtty_file_service();
|
||||||
|
if (sock < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
detect_sid('u');
|
||||||
|
|
||||||
|
buffer_put_u8 (&b, RTTY_FILE_MSG_INFO);
|
||||||
|
buffer_put_u16 (&b, strlen(bname));
|
||||||
|
buffer_put_string (&b, bname);
|
||||||
|
|
||||||
|
ev_signal_init(&sw, signal_cb, SIGINT);
|
||||||
|
ev_signal_start(loop, &sw);
|
||||||
|
|
||||||
|
ev_io_init(&iow, on_net_write, sock, EV_WRITE);
|
||||||
|
ev_io_start(loop, &iow);
|
||||||
|
|
||||||
|
ev_io_init(&ior, on_file_read, fd, EV_READ);
|
||||||
|
ev_io_start (loop, &ior);
|
||||||
|
|
||||||
|
printf("Transferring '%s'...Press Ctrl+C to cancel\n", bname);
|
||||||
|
|
||||||
|
start_time = ev_now (loop);
|
||||||
|
|
||||||
|
ev_run(loop, 0);
|
||||||
|
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (sock > -1)
|
||||||
|
close(sock);
|
||||||
|
if (fd > -1)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
30
src/upfile.h
Normal file
30
src/upfile.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Jianhui Zhao <zhaojh329@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTTY_UPFILE_H_
|
||||||
|
#define RTTY_UPFILE_H_
|
||||||
|
|
||||||
|
void upload_file(const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
87
src/utils.c
87
src/utils.c
@@ -29,35 +29,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <uwsc/log.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
/* blen is the size of buf; slen is the length of src. The input-string need
|
|
||||||
** not be, and the output string will not be, null-terminated. Returns the
|
|
||||||
** length of the encoded string, or -1 on error (buffer overflow) */
|
|
||||||
int urlencode(char *buf, int blen, const char *src, int slen)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int len = 0;
|
|
||||||
static const char hex[] = "0123456789abcdef";
|
|
||||||
|
|
||||||
for (i = 0; (i < slen) && (len < blen); i++) {
|
|
||||||
if (isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
|
|
||||||
(src[i] == '.') || (src[i] == '~')) {
|
|
||||||
buf[len++] = src[i];
|
|
||||||
} else if (src[i] == ' ') {
|
|
||||||
buf[len++] = '+';
|
|
||||||
} else if ((len + 3) <= blen) {
|
|
||||||
buf[len++] = '%';
|
|
||||||
buf[len++] = hex[(src[i] >> 4) & 15];
|
|
||||||
buf[len++] = hex[ src[i] & 15];
|
|
||||||
} else {
|
|
||||||
len = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (i == slen) ? len : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_login(char *buf, int len)
|
int find_login(char *buf, int len)
|
||||||
{
|
{
|
||||||
@@ -86,3 +58,60 @@ bool valid_id(const char *id)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* reference from https://tools.ietf.org/html/rfc4648#section-4 */
|
||||||
|
int b64_encode(const void *src, size_t srclen, void *dest, size_t destsize)
|
||||||
|
{
|
||||||
|
char *Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||||
|
const uint8_t *input = src;
|
||||||
|
char *output = dest;
|
||||||
|
|
||||||
|
while (srclen > 0) {
|
||||||
|
int skip = 1;
|
||||||
|
int i0 = input[0] >> 2;
|
||||||
|
int i1 = (input[0] & 0x3) << 4;
|
||||||
|
int i2 = 64;
|
||||||
|
int i3 = 64;
|
||||||
|
|
||||||
|
if (destsize < 5)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (srclen > 1) {
|
||||||
|
skip++;
|
||||||
|
i1 += input[1] >> 4;
|
||||||
|
i2 = (input[1] & 0xF) << 2;
|
||||||
|
|
||||||
|
if (srclen > 2) {
|
||||||
|
i2 += input[2] >> 6;
|
||||||
|
i3 = input[2] & 0x3F;
|
||||||
|
skip++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*output++ = Base64[i0];
|
||||||
|
*output++ = Base64[i1];
|
||||||
|
*output++ = Base64[i2];
|
||||||
|
*output++ = Base64[i3];
|
||||||
|
|
||||||
|
input += skip;
|
||||||
|
srclen -= skip;
|
||||||
|
destsize -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output++ = 0;
|
||||||
|
return output - (char *)dest - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *format_size(size_t size)
|
||||||
|
{
|
||||||
|
static char str[64];
|
||||||
|
|
||||||
|
if (size < 1024)
|
||||||
|
sprintf(str,"%zu B", size);
|
||||||
|
else if (size < 1024 * 1024)
|
||||||
|
sprintf(str,"%.2f KB", size / 1024.0);
|
||||||
|
else
|
||||||
|
sprintf(str,"%.2f MB", size / 1024.0 / 1024.0);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,12 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int urlencode(char *buf, int blen, const char *src, int slen);
|
|
||||||
|
|
||||||
int find_login(char *buf, int len);
|
int find_login(char *buf, int len);
|
||||||
|
|
||||||
bool valid_id(const char *id);
|
bool valid_id(const char *id);
|
||||||
|
|
||||||
|
int b64_encode(const void *src, size_t srclen, void *dest, size_t destsize);
|
||||||
|
|
||||||
|
const char *format_size(size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -99,23 +99,11 @@ rm -rf /tmp/rtty-build
|
|||||||
mkdir /tmp/rtty-build
|
mkdir /tmp/rtty-build
|
||||||
pushd /tmp/rtty-build
|
pushd /tmp/rtty-build
|
||||||
|
|
||||||
git clone --recursive https://github.com/zhaojh329/libuwsc.git || {
|
|
||||||
echo "Clone libuwsc failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
git clone https://github.com/zhaojh329/rtty.git || {
|
git clone https://github.com/zhaojh329/rtty.git || {
|
||||||
echo "Clone rtty failed"
|
echo "Clone rtty failed"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# libuwsc
|
|
||||||
rm -f /usr/local/lib/libuwsc.*
|
|
||||||
cd libuwsc && cmake . && make install && cd -
|
|
||||||
[ $? -eq 0 ] || exit 1
|
|
||||||
|
|
||||||
# rtty
|
# rtty
|
||||||
cd rtty && cmake . && make install
|
cd rtty && cmake . && make install
|
||||||
[ $? -eq 0 ] || exit 1
|
[ $? -eq 0 ] || exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user