You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
723 lines
21 KiB
C
723 lines
21 KiB
C
/*****************************************************************************
|
|
* file lib/management/cmd_SSH2.c
|
|
* author YuLiang
|
|
* version 1.0.0
|
|
* date 20-Mar-2025
|
|
* brief This file provides all the SSH2 cmd related operation functions.
|
|
******************************************************************************
|
|
* Attention
|
|
*
|
|
* <h2><center>© COPYRIGHT(c) 2025 LandPower</center></h2>
|
|
*
|
|
* 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.
|
|
* 3. Neither the name of LandPower nor the names of its contributors may be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
|
*
|
|
******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
/* 标准C库头文件. */
|
|
#include <ctype.h>
|
|
#include <libssh/libssh.h>
|
|
#include <libssh/server.h>
|
|
#include <libssh/callbacks.h>
|
|
|
|
/* 用户代码头文件. */
|
|
#include "main.h"
|
|
#include "vty.h"
|
|
#include "cmd.h"
|
|
#include "mtimer.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
#define VTYCMD_PORT "2222"
|
|
#define VTYCMD_RSA_PATH "/home/root/ssh/ssh_host_rsa_key"
|
|
#define VTYCMD_HOSTKEY_PATH "/home/root/ssh/ssh_host_ed25519_key"
|
|
|
|
#define VTYCMD_BUF_OUT_LEN 32768
|
|
|
|
typedef struct _vtycmd_ctrl
|
|
{
|
|
vty_t *vtycmd;
|
|
ssh_bind sshbind;
|
|
ssh_session session;
|
|
ssh_channel channel;
|
|
struct ssh_server_callbacks_struct server_cb;
|
|
struct ssh_channel_callbacks_struct channel_cb;
|
|
uint8_t is_connect;
|
|
uint8_t is_recv;
|
|
uint16_t cmd_idx;
|
|
char cmd[VTY_BUFSIZ];
|
|
uint16_t out_buf_start;
|
|
uint16_t out_buf_end;
|
|
char out_buf[VTYCMD_BUF_OUT_LEN];
|
|
} vtycmd_ctrl_t;
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* cmd vty结构体. */
|
|
static vtycmd_ctrl_t vtycmd_ctrl;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* 在终端上显示当前配置信息. */
|
|
CMD(show_sshcmd,
|
|
show_sshcmd_cmd,
|
|
"show sshcmd",
|
|
SHOW_STR
|
|
"SSHCMD\n")
|
|
{
|
|
vty_out(vty, "Connect: %s\r\n\n", vtycmd_ctrl.is_connect ? "yes" : "no");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
#if 0
|
|
|
|
/* Insert a word into vty interface with overwrite mode. */
|
|
void _vtycmd_insert_word(char *str)
|
|
{
|
|
int len = strlen(str);
|
|
|
|
ssh_channel_write(vtycmd_ctrl.channel, str, len);
|
|
strcpy(&vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx], str);
|
|
vtycmd_ctrl.cmd_idx += len;
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
}
|
|
|
|
/* commandLine '?'响应函数. */
|
|
int _vtycmd_question(void)
|
|
{
|
|
array_t *cmd_line = NULL;
|
|
|
|
cmd_line = cmd_strs_create(vtycmd_ctrl.cmd);
|
|
if (NULL == cmd_line)
|
|
{
|
|
cmd_line = array_init(1, MTYPE_CLI);
|
|
array_append(cmd_line, '\0', MTYPE_CLI);
|
|
}
|
|
else
|
|
if (vtycmd_ctrl.cmd_idx && isspace((int)vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx - 1]))
|
|
array_append(cmd_line, '\0', MTYPE_CLI);
|
|
|
|
vty_question(vtycmd_ctrl.vtycmd, cmd_line);
|
|
|
|
cmd_strs_free(cmd_line);
|
|
vty_prompt(vtycmd_ctrl.vtycmd);
|
|
vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd);
|
|
return 0;
|
|
}
|
|
|
|
/* 用于自动补齐命令行关键字. */
|
|
void _vtycmd_completion_append(array_t *cmd_line, char *word, int32_t status)
|
|
{
|
|
uint32_t index = array_active(cmd_line) - 1;
|
|
uint32_t len = 0;
|
|
uint32_t i = 0;
|
|
|
|
if (NULL == array_get(cmd_line, index))
|
|
{
|
|
_vtycmd_insert_word(word);
|
|
}
|
|
else
|
|
{
|
|
len = strlen(array_get(cmd_line, index));
|
|
for(i = 0; i < len; i++)
|
|
{
|
|
if (vtycmd_ctrl.cmd_idx)
|
|
{
|
|
vtycmd_ctrl.cmd_idx--;
|
|
vty_out(vtycmd_ctrl.vtycmd, "%c%c%c", 8, ' ', 8);
|
|
}
|
|
}
|
|
_vtycmd_insert_word(word);
|
|
}
|
|
|
|
if (CMD_COMPLETE_FULL_MATCH == status)
|
|
_vtycmd_insert_word(" ");
|
|
}
|
|
|
|
/* commandLine 'TAB'响应函数. */
|
|
int _vtycmd_completion(void)
|
|
{
|
|
array_t *cmd_line = NULL;
|
|
char **match_strs = NULL;
|
|
int32_t complete_status = CMD_ERR_NO_MATCH;
|
|
|
|
cmd_line = cmd_strs_create(vtycmd_ctrl.cmd);
|
|
if (NULL == cmd_line)
|
|
{
|
|
cmd_line = array_init(1, MTYPE_CLI);
|
|
array_append(cmd_line, '\0', MTYPE_CLI);
|
|
}
|
|
else
|
|
if (vtycmd_ctrl.cmd_idx && isspace((int)vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx - 1]))
|
|
array_append(cmd_line, '\0', MTYPE_CLI);
|
|
|
|
match_strs = cmd_complete_command(cmd_line, vtycmd_ctrl.vtycmd, &complete_status);
|
|
if (NULL == match_strs)
|
|
{
|
|
cmd_strs_free(cmd_line);
|
|
return 0;
|
|
}
|
|
|
|
if (CMD_COMPLETE_MATCH == complete_status ||
|
|
CMD_COMPLETE_FULL_MATCH == complete_status)
|
|
_vtycmd_completion_append(cmd_line, match_strs[0], complete_status);
|
|
else
|
|
{
|
|
vty_print_word(vtycmd_ctrl.vtycmd, match_strs);
|
|
vty_prompt(vtycmd_ctrl.vtycmd);
|
|
vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd);
|
|
}
|
|
|
|
vty_free_match_strs(match_strs);
|
|
cmd_strs_free(cmd_line);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Internal functions --------------------------------------------------------*/
|
|
/* Print command line history. This function is called from
|
|
vty_next_line and vty_previous_line. */
|
|
static void _vtycmd_history_print(vty_t *vty)
|
|
{
|
|
uint16_t i= 0;
|
|
|
|
for(i = 0; i < vtycmd_ctrl.cmd_idx; i++)
|
|
{
|
|
vty_out(vtycmd_ctrl.vtycmd, "%c%c%c", 8, ' ', 8);
|
|
}
|
|
vtycmd_ctrl.cmd_idx = 0;
|
|
|
|
/* Get previous line from history buffer */
|
|
vtycmd_ctrl.cmd_idx = strlen(vty->hist[vty->hp]);
|
|
memcpy(vtycmd_ctrl.cmd, vty->hist[vty->hp], vtycmd_ctrl.cmd_idx);
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
|
|
/* Redraw current line */
|
|
vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd);
|
|
}
|
|
|
|
/* Show previous command line history. */
|
|
static void _vtycmd_previous_line(vty_t *vty)
|
|
{
|
|
unsigned int try_index = 0;
|
|
|
|
try_index = vty->hp;
|
|
if (try_index == 0)
|
|
try_index = VTY_MAXHIST - 1;
|
|
else
|
|
try_index--;
|
|
|
|
if (vty->hist[try_index] == NULL)
|
|
return;
|
|
else
|
|
vty->hp = try_index;
|
|
|
|
_vtycmd_history_print(vty);
|
|
}
|
|
|
|
/* Show next command line history. */
|
|
static void _vtycmd_next_line(vty_t *vty)
|
|
{
|
|
unsigned int try_index = 0;
|
|
|
|
if (vty->hp == vty->hindex)
|
|
return;
|
|
|
|
/* Try is there history exist or not. */
|
|
try_index = vty->hp;
|
|
if (try_index == (VTY_MAXHIST - 1))
|
|
try_index = 0;
|
|
else
|
|
try_index++;
|
|
|
|
/* If there is not history return. */
|
|
if (vty->hist[try_index] == NULL)
|
|
return;
|
|
else
|
|
vty->hp = try_index;
|
|
|
|
_vtycmd_history_print(vty);
|
|
}
|
|
|
|
int _vtycmd_cmd(char *buf, uint32_t len)
|
|
{
|
|
uint16_t i = 0;
|
|
vty_t *vty = vtycmd_ctrl.vtycmd;
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
switch (buf[i])
|
|
{
|
|
case '\033':
|
|
if (i + 2 < len && buf[i + 1] == '[')
|
|
{
|
|
if (buf[i + 2] == 'A')
|
|
{
|
|
_vtycmd_previous_line(vty);
|
|
}
|
|
else if (buf[i + 2] == 'B')
|
|
{
|
|
_vtycmd_next_line(vty);
|
|
}
|
|
i += 2;
|
|
}
|
|
break;
|
|
case CONTROL('H'):
|
|
case 0x7f:
|
|
if (vtycmd_ctrl.cmd_idx)
|
|
{
|
|
vtycmd_ctrl.cmd_idx--;
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
vty_out(vty, "%c%c%c", 8, ' ', 8);
|
|
}
|
|
break;
|
|
case '\n':
|
|
case '\r':
|
|
vty_out(vty, "%s", VTY_NEWLINE);
|
|
/* 执行命令 */
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
vty->length = vtycmd_ctrl.cmd_idx;
|
|
snprintf(vty->buf, VTY_BUFSIZ, "%s", vtycmd_ctrl.cmd);
|
|
vty_execute(vty);
|
|
vtycmd_ctrl.cmd_idx = 0;
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
break;
|
|
case '\t':
|
|
_vtycmd_completion();
|
|
break;
|
|
case '?':
|
|
_vtycmd_question();
|
|
break;
|
|
default:
|
|
if (buf[i] > 31 && buf[i] < 127)
|
|
{
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = buf[i];
|
|
vtycmd_ctrl.cmd_idx++;
|
|
vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0;
|
|
vty_out(vty, "%c", buf[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* 客户端通讯相关的回调 */
|
|
int _vtycmd_channel_pty_request(ssh_session session, ssh_channel channel,
|
|
const char *term, int cols, int rows, int py, int px,
|
|
void *userdata)
|
|
{
|
|
ssh_channel_write(vtycmd_ctrl.channel, "Username: ", 10);
|
|
ssh_channel_request_pty_size(channel, term, cols, rows);
|
|
return SSH_OK;
|
|
}
|
|
|
|
int _vtycmd_channel_pty_resize(ssh_session session, ssh_channel channel, int cols,
|
|
int rows, int py, int px, void *userdata)
|
|
{
|
|
return ssh_channel_change_pty_size(channel, cols, rows);
|
|
}
|
|
|
|
int _vtycmd_channel_shell_request(ssh_session session, ssh_channel channel,
|
|
void *userdata)
|
|
{
|
|
return SSH_OK;
|
|
}
|
|
|
|
int _vtycmd_channel_exec_request(ssh_session session, ssh_channel channel,
|
|
const char *command, void *userdata)
|
|
{
|
|
return ssh_channel_request_exec(channel, command);
|
|
}
|
|
|
|
int _vtycmd_channel_subsystem_request(ssh_session session, ssh_channel channel,
|
|
const char *subsystem, void *userdata)
|
|
{
|
|
return SSH_OK;
|
|
}
|
|
|
|
int _vtycmd_channel_env_request_function(ssh_session session, ssh_channel channel, const char *env_name,
|
|
const char *env_value, void *userdata)
|
|
{
|
|
return ssh_channel_request_env(channel, env_name, env_value);
|
|
}
|
|
|
|
/* 数据处理 */
|
|
int _vtycmd_channel_data_function(ssh_session session, ssh_channel channel, void *data,
|
|
uint32_t len, int is_stderr, void *userdata)
|
|
{
|
|
vtycmd_ctrl.is_recv = TRUE;
|
|
_vtycmd_cmd((char*)data, len);
|
|
return len;
|
|
}
|
|
|
|
void _vtycmd_channel_close(ssh_session session, ssh_channel channel, void *userdata)
|
|
{
|
|
vtycmd_ctrl.is_connect = FALSE;
|
|
}
|
|
|
|
/* 服务端认证通道相关回调 */
|
|
int _vtycmd_server_auth_pass(ssh_session session, const char *user, const char *password, void *userdata)
|
|
{
|
|
if (strcmp("root", user) == 0 && strcmp("123456", password) == 0)
|
|
{
|
|
return SSH_AUTH_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return SSH_AUTH_DENIED;
|
|
}
|
|
}
|
|
|
|
/* 空认证方法 */
|
|
int _vtycmd_server_auth_none_callback(ssh_session session, const char *user, void *userdata)
|
|
{
|
|
return SSH_AUTH_SUCCESS;
|
|
}
|
|
|
|
/* pubkey 认证方法 */
|
|
int _vtycmd_server_auth_pubkey(ssh_session session, const char *user, struct ssh_key_struct *pubkey,
|
|
char signature_state, void *userdata)
|
|
{
|
|
return SSH_AUTH_SUCCESS;
|
|
}
|
|
|
|
int _vtycmd_server_request_callback(ssh_session session, const char *service, void *userdata)
|
|
{
|
|
return SSH_OK;
|
|
}
|
|
|
|
ssh_channel _vtycmd_server_open_channel(ssh_session session, void *userdata)
|
|
{
|
|
vtycmd_ctrl.channel = ssh_channel_new(session);
|
|
|
|
ssh_callbacks_init(&vtycmd_ctrl.channel_cb);
|
|
ssh_set_channel_callbacks(vtycmd_ctrl.channel, &vtycmd_ctrl.channel_cb);
|
|
|
|
return vtycmd_ctrl.channel;
|
|
}
|
|
|
|
/* SSH2 命令行主函数 */
|
|
void *_vtycmd_handle(void *arg)
|
|
{
|
|
/* 初始化 libssh */
|
|
if (ssh_init() < 0)
|
|
{
|
|
log_err(LOG_CLI, "ssh_init failed\r\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* 初始化结构体 */
|
|
vtycmd_ctrl.server_cb.auth_password_function = _vtycmd_server_auth_pass;
|
|
vtycmd_ctrl.server_cb.auth_none_function = _vtycmd_server_auth_none_callback;
|
|
vtycmd_ctrl.server_cb.auth_pubkey_function = _vtycmd_server_auth_pubkey;
|
|
vtycmd_ctrl.server_cb.service_request_function = _vtycmd_server_request_callback;
|
|
vtycmd_ctrl.server_cb.channel_open_request_session_function = _vtycmd_server_open_channel;
|
|
|
|
vtycmd_ctrl.channel_cb.channel_data_function = _vtycmd_channel_data_function;
|
|
vtycmd_ctrl.channel_cb.channel_close_function = _vtycmd_channel_close;
|
|
vtycmd_ctrl.channel_cb.channel_pty_request_function = _vtycmd_channel_pty_request;
|
|
vtycmd_ctrl.channel_cb.channel_shell_request_function = _vtycmd_channel_shell_request;
|
|
vtycmd_ctrl.channel_cb.channel_pty_window_change_function = _vtycmd_channel_pty_resize;
|
|
vtycmd_ctrl.channel_cb.channel_exec_request_function = _vtycmd_channel_exec_request;
|
|
vtycmd_ctrl.channel_cb.channel_env_request_function = _vtycmd_channel_env_request_function;
|
|
vtycmd_ctrl.channel_cb.channel_subsystem_request_function = _vtycmd_channel_subsystem_request;
|
|
|
|
/* 创建 SSH2 接口 */
|
|
vtycmd_ctrl.sshbind = ssh_bind_new();
|
|
ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, VTYCMD_PORT);
|
|
ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_RSAKEY, VTYCMD_RSA_PATH);
|
|
ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_HOSTKEY, VTYCMD_HOSTKEY_PATH);
|
|
if (ssh_bind_listen(vtycmd_ctrl.sshbind) < 0)
|
|
{
|
|
log_err(LOG_CLI, "Error listening to socket: %s", ssh_get_error(vtycmd_ctrl.sshbind));
|
|
return NULL;
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
/* 等待连接 */
|
|
ssh_session session = ssh_new();
|
|
if (ssh_bind_accept(vtycmd_ctrl.sshbind, session) != SSH_OK)
|
|
{
|
|
DBG(DBG_M_CLI, "Error accept to socket: %s\n", ssh_get_error(vtycmd_ctrl.sshbind));
|
|
continue;
|
|
}
|
|
|
|
/* 只能接收一个连接 */
|
|
if (vtycmd_ctrl.is_connect)
|
|
{
|
|
ssh_disconnect(session);
|
|
ssh_free(session);
|
|
continue;
|
|
}
|
|
|
|
/* 初始化连接 */
|
|
log_notice(LOG_CLI, "SSH2 command is connect.\n");
|
|
vtycmd_ctrl.is_connect = TRUE;
|
|
ssh_callbacks_init(&vtycmd_ctrl.server_cb);
|
|
ssh_set_server_callbacks(session, &vtycmd_ctrl.server_cb);
|
|
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
|
if (ssh_handle_key_exchange(session) != SSH_OK)
|
|
{
|
|
DBG(DBG_M_CLI, "Error performing key exchange: %s\n", ssh_get_error(session));
|
|
ssh_disconnect(session);
|
|
ssh_free(session);
|
|
continue;
|
|
}
|
|
|
|
ssh_set_blocking(session, 0);
|
|
ssh_event event = ssh_event_new();
|
|
ssh_event_add_session(event, session);
|
|
|
|
/* 处理连接断开 */
|
|
while(1)
|
|
{
|
|
if (ssh_event_dopoll(event, 3000) == SSH_ERROR
|
|
|| !vtycmd_ctrl.is_connect)
|
|
{
|
|
/* 终端断开处理 */
|
|
log_notice(LOG_CLI, "SSH2 command is disconnect.\n");
|
|
ssh_channel_close(vtycmd_ctrl.channel);
|
|
ssh_channel_free(vtycmd_ctrl.channel);
|
|
ssh_disconnect(session);
|
|
ssh_event_free(event);
|
|
ssh_free(session);
|
|
vtycmd_ctrl.is_connect = FALSE;
|
|
if (CONFIG_NODE == vtycmd_ctrl.vtycmd->node)
|
|
{
|
|
vty_config_unlock(vtycmd_ctrl.vtycmd);
|
|
}
|
|
vtycmd_ctrl.vtycmd->node = USERNAME_NODE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* 用于判断终端是否超时 */
|
|
void* _vtycmd_timer(void *arg)
|
|
{
|
|
if (!vtycmd_ctrl.is_recv && vtycmd_ctrl.is_connect)
|
|
{
|
|
vtycmd_ctrl.is_connect = FALSE;
|
|
}
|
|
vtycmd_ctrl.is_recv = FALSE;
|
|
|
|
/* 重新加入定时器. */
|
|
mtimer_add(_vtycmd_timer, NULL, 120, "VTYCMD_TIMER");
|
|
return NULL;
|
|
}
|
|
|
|
/* SSH2 命令行发送数据 */
|
|
void *_vtycmd_send_handle(void *arg)
|
|
{
|
|
char *buf = NULL;
|
|
uint16_t end = 0;
|
|
|
|
while(1)
|
|
{
|
|
usleep(100000);
|
|
|
|
if (!vtycmd_ctrl.is_connect)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
end = vtycmd_ctrl.out_buf_end;
|
|
buf = vtycmd_ctrl.out_buf + vtycmd_ctrl.out_buf_start;
|
|
|
|
if (end == vtycmd_ctrl.out_buf_start)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (end < vtycmd_ctrl.out_buf_start)
|
|
{
|
|
ssh_channel_write(vtycmd_ctrl.channel, buf, VTYCMD_BUF_OUT_LEN - vtycmd_ctrl.out_buf_start);
|
|
vtycmd_ctrl.out_buf_start = 0;
|
|
}
|
|
else
|
|
{
|
|
ssh_channel_write(vtycmd_ctrl.channel, buf, end - vtycmd_ctrl.out_buf_start);
|
|
vtycmd_ctrl.out_buf_start = end;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
/* Interface functions -------------------------------------------------------*/
|
|
/* 初始化 SSH2 命令行 */
|
|
void vtycmd_init(void)
|
|
{
|
|
/* Make vty structure. */
|
|
vtycmd_ctrl.vtycmd = vty_create();
|
|
vtycmd_ctrl.vtycmd->type = VTY_CMD;
|
|
vtycmd_ctrl.vtycmd->node = USERNAME_NODE;
|
|
memset(vtycmd_ctrl.vtycmd->hist, 0, sizeof(vtycmd_ctrl.vtycmd->hist));
|
|
vtycmd_ctrl.vtycmd->hp = 0;
|
|
vtycmd_ctrl.vtycmd->hindex = 0;
|
|
|
|
cmd_install_element(COMMON_NODE, &show_sshcmd_cmd);
|
|
}
|
|
|
|
/* 启动 SSH2 命令行 */
|
|
void vtycmd_cmd_init(void)
|
|
{
|
|
return ;
|
|
#if 0
|
|
pthread_t pid;
|
|
struct sched_param param;
|
|
pthread_attr_t attr;
|
|
int32_t rv = 0;
|
|
|
|
/* 配置线程RR调度, 优先级75 */
|
|
pthread_attr_init(&attr);
|
|
param.sched_priority = 75;
|
|
pthread_attr_setschedpolicy(&attr, SCHED_RR);
|
|
pthread_attr_setschedparam(&attr, ¶m);
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
|
|
rv = pthread_create(&pid, &attr, _vtycmd_handle, NULL);
|
|
if (rv != 0)
|
|
{
|
|
log_err(LOG_DEFAULT, "vtycmd_cmd_init can't create pthread %d!", rv);
|
|
}
|
|
else
|
|
{
|
|
thread_m_add("CMD", pid);
|
|
}
|
|
pthread_attr_destroy(&attr);
|
|
|
|
mtimer_add(_vtycmd_timer, NULL, 120, "VTYCMD_TIMER");
|
|
|
|
/* 配置线程RR调度, 优先级75 */
|
|
pthread_attr_init(&attr);
|
|
param.sched_priority = 75;
|
|
pthread_attr_setschedpolicy(&attr, SCHED_RR);
|
|
pthread_attr_setschedparam(&attr, ¶m);
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
|
|
rv = pthread_create(&pid, &attr, _vtycmd_send_handle, NULL);
|
|
if (rv != 0)
|
|
{
|
|
log_err(LOG_DEFAULT, "vtycmd_cmd_init can't create pthread %d!", rv);
|
|
}
|
|
else
|
|
{
|
|
thread_m_add("CMD_SNED", pid);
|
|
}
|
|
pthread_attr_destroy(&attr);
|
|
#endif
|
|
}
|
|
|
|
/* cmd 是否连接 */
|
|
bool vtycmd_connect(void)
|
|
{
|
|
return vtycmd_ctrl.is_connect;
|
|
}
|
|
|
|
/* 命令行输出 */
|
|
void vtycmd_print(const char *format, va_list va)
|
|
{
|
|
char *buf = vtycmd_ctrl.out_buf + vtycmd_ctrl.out_buf_end;
|
|
char buf_temp[VTY_BUFSIZ];
|
|
char *buf_temp_p = buf_temp;
|
|
uint16_t start = 0;;
|
|
int len = 0;
|
|
int len_remain = 0;
|
|
int len_temp = 0;
|
|
|
|
if (!vtycmd_ctrl.is_connect)
|
|
{
|
|
vtycmd_ctrl.out_buf_start = 0;
|
|
vtycmd_ctrl.out_buf_end = 0;
|
|
return;
|
|
}
|
|
|
|
len = vsnprintf(buf_temp, VTY_BUFSIZ, format, va);
|
|
if (len <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* 计算可写入的数据量 */
|
|
start = vtycmd_ctrl.out_buf_start;
|
|
if (vtycmd_ctrl.out_buf_end >= start)
|
|
{
|
|
len_remain = VTYCMD_BUF_OUT_LEN - 1 - (vtycmd_ctrl.out_buf_end - start);
|
|
}
|
|
else
|
|
{
|
|
len_remain = start - vtycmd_ctrl.out_buf_end - 1;
|
|
}
|
|
if (len_remain <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (len > len_remain)
|
|
{
|
|
len = len_remain;
|
|
}
|
|
|
|
/* 超过 out_buf 需要分段存储 */
|
|
if (len + vtycmd_ctrl.out_buf_end > VTYCMD_BUF_OUT_LEN)
|
|
{
|
|
len_temp = VTYCMD_BUF_OUT_LEN - vtycmd_ctrl.out_buf_end;
|
|
memcpy(buf, buf_temp_p, len_temp);
|
|
vtycmd_ctrl.out_buf_end = 0;
|
|
buf = vtycmd_ctrl.out_buf;
|
|
buf_temp_p = buf_temp_p + len_temp;
|
|
len -= len_temp;
|
|
|
|
memcpy(buf, buf_temp_p, len);
|
|
vtycmd_ctrl.out_buf_end += len;
|
|
}
|
|
else
|
|
{
|
|
memcpy(buf, buf_temp_p, len);
|
|
len_temp = vtycmd_ctrl.out_buf_end + len;
|
|
if (VTYCMD_BUF_OUT_LEN == len_temp)
|
|
{
|
|
vtycmd_ctrl.out_buf_end = 0;
|
|
}
|
|
else
|
|
{
|
|
vtycmd_ctrl.out_buf_end = len_temp;
|
|
}
|
|
}
|
|
}
|
|
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/
|