更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
telnet_dev.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "telnet_dev.h"
33#ifdef LOSCFG_NET_TELNET
34#include "unistd.h"
35#include "stdlib.h"
36#include "sys/ioctl.h"
37#include "sys/types.h"
38#include "pthread.h"
39
40#include "los_printf.h"
41#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
42#include "los_swtmr_pri.h"
43#endif
44#include "los_sched_pri.h"
45#include "console.h"
46#include "lwip/opt.h"
47#include "lwip/sockets.h"
48#include "telnet_pri.h"
49
50#include "fs/driver.h"
51
52/* event: there are more commands left in the FIFO to run */
53#define TELNET_EVENT_MORE_CMD 0x01 ///< 还有很多命令在FIFO中等待执行的事件
54#define TELNET_DEV_DRV_MODE 0666 ///< 文件权限 chmod = 666
55
56STATIC TELNET_DEV_S g_telnetDev; ///< 远程登录设备
58STATIC struct Vnode *g_currentVnode;
59
60STATIC INLINE TELNET_DEV_S *GetTelnetDevByFile(const struct file *file, BOOL isOpenOp)
61{
62 struct Vnode *telnetInode = NULL;
63 TELNET_DEV_S *telnetDev = NULL;
64
65 if (file == NULL) {
66 return NULL;
67 }
68 telnetInode = file->f_vnode;
69 if (telnetInode == NULL) {
70 return NULL;
71 }
72 /*
73 * Check if the f_vnode is valid here for non-open ops (open is supposed to get invalid f_vnode):
74 * when telnet is disconnected, there still may be 'TelentShellTask' tasks trying to write
75 * to the file, but the file has illegal f_vnode because the file is used by others.
76 */
77 if (!isOpenOp) {
78 if (telnetInode != g_currentVnode) {
79 return NULL;
80 }
81 }
82 telnetDev = (TELNET_DEV_S *)((struct drv_data*)telnetInode->data)->priv;
83 return telnetDev;
84}
85
86/*
87 * Description : When receive user's input commands, first copy commands to the FIFO of the telnet device.
88 * Then, notify a command resolver task (an individual shell task) to take out and run commands.
89 当接收到用户输入的命令时,首先将命令复制到telnet设备的FIFO中,然后通知一个命令解析器任务
90 (一个单独的shell任务)取出并运行命令。
91 * Return : -1 --- On failure
92 * Non-negative integer --- length of written commands
93 */
94INT32 TelnetTx(const CHAR *buf, UINT32 bufLen)
95{
96 UINT32 i;
97 TELNET_DEV_S *telnetDev = NULL;
98
99 TelnetLock();
100
101 telnetDev = &g_telnetDev;
102 if ((buf == NULL) || (telnetDev->cmdFifo == NULL)) {
103 TelnetUnlock();
104 return -1;
105 }
106
107 /* size limited */
108 if (bufLen > telnetDev->cmdFifo->fifoNum) {//一次拿不完数据的情况
109 bufLen = telnetDev->cmdFifo->fifoNum;//只能装满
110 }
111
112 if (bufLen == 0) { //参数要先判断 @note_thinking
113 TelnetUnlock();
114 return 0;
115 }
116
117 /* copy commands to the fifo of the telnet device | 复制命令到telnet设备的fifo*/
118 for (i = 0; i < bufLen; i++) {
119 telnetDev->cmdFifo->rxBuf[telnetDev->cmdFifo->rxIndex] = *buf;
120 telnetDev->cmdFifo->rxIndex++;
121 telnetDev->cmdFifo->rxIndex %= FIFO_MAX;
122 buf++;
123 }
124 telnetDev->cmdFifo->fifoNum -= bufLen;
125
126 if (telnetDev->eventPend) {
127 /* signal that there are some works to do */
128 (VOID)LOS_EventWrite(&telnetDev->eventTelnet, TELNET_EVENT_MORE_CMD);
129 }
130 /* notify the command resolver task */
131 notify_poll(&telnetDev->wait);
132 TelnetUnlock();
133
134 return (INT32)bufLen;
135}
136
137/*
138 * Description : When open the telnet device, init the FIFO, wait queue etc.
139 */
140STATIC INT32 TelnetOpen(struct file *file)
141{
142 struct wait_queue_head *wait = NULL;
143 TELNET_DEV_S *telnetDev = NULL;
144
145 TelnetLock();
146
147 telnetDev = GetTelnetDevByFile(file, TRUE);//获取标准file私有数据
148 if (telnetDev == NULL) {
149 TelnetUnlock();
150 return -1;
151 }
152
153 if (telnetDev->cmdFifo == NULL) {
154 wait = &telnetDev->wait;
155 (VOID)LOS_EventInit(&telnetDev->eventTelnet);//初始化事件
156 g_event = &telnetDev->eventTelnet;
157 telnetDev->cmdFifo = (TELNTE_FIFO_S *)malloc(sizeof(TELNTE_FIFO_S));
158 if (telnetDev->cmdFifo == NULL) {
159 TelnetUnlock();
160 return -1;
161 }
162 (VOID)memset_s(telnetDev->cmdFifo, sizeof(TELNTE_FIFO_S), 0, sizeof(TELNTE_FIFO_S));
163 telnetDev->cmdFifo->fifoNum = FIFO_MAX;
164 LOS_ListInit(&wait->poll_queue);
165 }
166 g_currentVnode = file->f_vnode;
167 TelnetUnlock();
168 return 0;
169}
170
171/*
172 * Description : When close the telnet device, free the FIFO, wait queue etc.
173 */
174STATIC INT32 TelnetClose(struct file *file)
175{
176 struct wait_queue_head *wait = NULL;
177 TELNET_DEV_S *telnetDev = NULL;
178
179 TelnetLock();
180
181 telnetDev = GetTelnetDevByFile(file, FALSE);
182 if (telnetDev != NULL) {
183 wait = &telnetDev->wait;
184 LOS_ListDelete(&wait->poll_queue);
185 free(telnetDev->cmdFifo);
186 telnetDev->cmdFifo = NULL;
187 (VOID)LOS_EventDestroy(&telnetDev->eventTelnet);
188 g_event = NULL;
189 }
190 g_currentVnode = NULL;
191 TelnetUnlock();
192 return 0;
193}
194
195/*
196 * Description : When a command resolver task trys to read the telnet device,
197 * this method is called, and it will take out user's commands from the FIFO to run.
198 * 当命令解析器任务尝试读取 telnet 设备时,调用这个方法,它会从FIFO中取出用户的命令来运行。
199 * 读取远程终端输入的命令,比如: # task
200 * Return : -1 --- On failure
201 * Non-negative integer --- length of commands taken out from the FIFO of the telnet device.
202 */
203STATIC ssize_t TelnetRead(struct file *file, CHAR *buf, size_t bufLen)
204{
205 UINT32 i;
206 TELNET_DEV_S *telnetDev = NULL;
207
208 TelnetLock();
209
210 telnetDev = GetTelnetDevByFile(file, FALSE);//通过文件获取远程登录实体
211 if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
212 TelnetUnlock();
213 return -1;
214 }
215
216 if (telnetDev->eventPend) {//挂起时,说明没有数据可读,等待事件发生
217 TelnetUnlock();
218 (VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);//等待读取 TELNET_EVENT_MORE_CMD 事件
219 TelnetLock();
220 }
221
222 if (bufLen > (FIFO_MAX - telnetDev->cmdFifo->fifoNum)) {
223 bufLen = FIFO_MAX - telnetDev->cmdFifo->fifoNum;
224 }
225 //把远程终端过来的数据接走, 一般由 Shell Entry 任务中的 read(fd,&buf)读走数据
226 for (i = 0; i < bufLen; i++) {
227 *buf++ = telnetDev->cmdFifo->rxBuf[telnetDev->cmdFifo->rxOutIndex++];
228 if (telnetDev->cmdFifo->rxOutIndex >= FIFO_MAX) {
229 telnetDev->cmdFifo->rxOutIndex = 0;
230 }
231 }
232 telnetDev->cmdFifo->fifoNum += bufLen;
233 /* check if no more commands left to run | 检查是否没有更多命令可以运行 */
234 if (telnetDev->cmdFifo->fifoNum == FIFO_MAX) {
235 (VOID)LOS_EventClear(&telnetDev->eventTelnet, ~TELNET_EVENT_MORE_CMD);//清除读取内容事件
236 }
237
238 TelnetUnlock();
239 return (ssize_t)bufLen;
240}
241
242/*
243 * Description : When a command resolver task trys to write command results to the telnet device,
244 * just use lwIP send function to send out results.
245 * Return : -1 --- buffer is NULL
246 * Non-negative integer --- length of written data, maybe 0.
247 */
248STATIC ssize_t TelnetWrite(struct file *file, const CHAR *buf, const size_t bufLen)
249{
250 INT32 ret = 0;
251 TELNET_DEV_S *telnetDev = NULL;
252
253 TelnetLock();
254
255 telnetDev = GetTelnetDevByFile(file, FALSE);
256 if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
257 TelnetUnlock();
258 return -1;
259 }
260
261 if (OS_INT_ACTIVE) {
262 TelnetUnlock();
263 return ret;
264 }
265
266 if (!OsPreemptable()) {//@note_thinking 这里为何要有这个判断?
267 TelnetUnlock();
268 return ret;
269 }
270
271 if (telnetDev->clientFd != 0) {
272#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
273 /* DO NOT call blocking API in software timer task | 不要在软件定时器任务中调用阻塞 API */
275 TelnetUnlock();
276 return ret;
277 }
278#endif
279 ret = send(telnetDev->clientFd, buf, bufLen, 0);//向 socket 发送
280 }
281 TelnetUnlock();
282 return ret;
283}
284/// 远程登录控制操作
285STATIC INT32 TelnetIoctl(struct file *file, const INT32 cmd, unsigned long arg)
286{
287 TELNET_DEV_S *telnetDev = NULL;
288
289 TelnetLock();
290
291 telnetDev = GetTelnetDevByFile(file, FALSE);
292 if (telnetDev == NULL) {
293 TelnetUnlock();
294 return -1;
295 }
296
297 if (cmd == CFG_TELNET_EVENT_PEND) {
298 if (arg == 0) {
299 telnetDev->eventPend = FALSE;
300 (VOID)LOS_EventWrite(&(telnetDev->eventTelnet), TELNET_EVENT_MORE_CMD);
301 (VOID)LOS_EventClear(&(telnetDev->eventTelnet), ~TELNET_EVENT_MORE_CMD);
302 } else {
303 telnetDev->eventPend = TRUE;
304 }
305 } else if (cmd == CFG_TELNET_SET_FD) {
306 if (arg >= (FD_SETSIZE - 1)) {
307 TelnetUnlock();
308 return -1;
309 }
310 telnetDev->clientFd = (INT32)arg;
311 }
312 TelnetUnlock();
313 return 0;
314}
315
316STATIC INT32 TelnetPoll(struct file *file, poll_table *table)
317{
318 TELNET_DEV_S *telnetDev = NULL;
319
320 TelnetLock();
321
322 telnetDev = GetTelnetDevByFile(file, FALSE);
323 if ((telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
324 TelnetUnlock();
325 return -1;
326 }
327
328 poll_wait(file, &telnetDev->wait, table);
329
330 /* check if there are some commands to run */
331 if (telnetDev->cmdFifo->fifoNum != FIFO_MAX) {
332 TelnetUnlock();
333 return POLLIN | POLLRDNORM;
334 }
335 TelnetUnlock();
336 return 0;
337}
338//远程登录操作命令
339STATIC const struct file_operations_vfs g_telnetOps = {
344 NULL,
346 NULL,
347#ifndef CONFIG_DISABLE_POLL
349#endif
350 NULL,
351};
352
353/* Once the telnet server stopped, remove the telnet device file. */
355{
357 g_telnetDev.cmdFifo = NULL;
358 (VOID)unregister_driver(TELNET);//注销字符设备驱动
359
360 return 0;
361}
362
363/* Once the telnet server started, setup the telnet device file.
364| telnet 服务器启动后,设置 telnet 设备文件*/
366{
367 INT32 ret;
368
369 g_telnetDev.id = 0;
370 g_telnetDev.cmdFifo = NULL;
371 g_telnetDev.eventPend = TRUE;
372 //注册 telnet 驱动, g_telnetDev为私有数据
373 ret = register_driver(TELNET, &g_telnetOps, TELNET_DEV_DRV_MODE, &g_telnetDev);//翻译过来是当读TELNET时,真正要去操作的是 g_telnetDev
374 if (ret != 0) {
375 PRINT_ERR("Telnet register driver error.\n");
376 }
377 return ret;
378}
379
380/* When a telnet client connection established, update the output console for tasks.
381| 建立 telnet 客户端连接后,更新任务的输出控制台 */
383{
384 INT32 ret;
385
386 if (clientFd < 0) {
387 PRINT_ERR("Invalid telnet clientFd.\n");
388 return -1;
389 }
390 ret = system_console_init(TELNET);//创建一个带远程登录功能的控制台
391 if (ret != 0) {
392 PRINT_ERR("Telnet console init error.\n");
393 return ret;
394 }
395 ret = ioctl(STDIN_FILENO, CFG_TELNET_SET_FD, clientFd);//绑定FD,相当于shell和控制台绑定
396 if (ret != 0) {
397 PRINT_ERR("Telnet device ioctl error.\n");
398 (VOID)system_console_deinit(TELNET);
399 }
400 return ret;
401}
402
403/* When closing the telnet client connection, reset the output console for tasks. |
404关闭 telnet 客户端连接时,重置任务的控制台信息。*/
406{
407 INT32 ret;
408
409 ret = system_console_deinit(TELNET);
410 if (ret != 0) {
411 PRINT_ERR("Telnet console deinit error.\n");
412 }
413 return ret;
414}
415#endif
416
INT32 system_console_deinit(const CHAR *deviceName)
控制台结束前的处理 和 system_console_init成对出现,像控制台的析构函数
Definition: console.c:1375
INT32 system_console_init(const CHAR *deviceName)
初始化系统控制台并返回 stdinfd stdoutfd stderrfd ,和system_console_deinit成对出现,像控制台的构造函数
Definition: console.c:1329
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask)
清除指定的事件类型
Definition: los_event.c:355
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
销毁指定的事件控制块
Definition: los_event.c:334
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout)
读取指定事件类型,超时时间为相对时间:单位为Tick
Definition: los_event.c:313
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
写指定的事件类型
Definition: los_event.c:318
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
初始化一个事件控制块
Definition: los_event.c:95
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
STATIC INLINE BOOL OsPreemptable(VOID)
BOOL OsIsSwtmrTask(const LosTaskCB *taskCB)
Definition: los_swtmr.c:383
signed int INT32
Definition: los_typedef.h:60
INT64 ssize_t
Definition: los_typedef.h:79
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
size_t BOOL
Definition: los_typedef.h:88
void * malloc(size_t size)
动态分配内存块大小
Definition: malloc.c:81
void free(void *ptr)
释放ptr所指向的内存空间
Definition: malloc.c:66
ssize_t send(int s, const void *dataptr, size_t size, int flags)
相当于文件操作的 write 功能,区别是第四个参数 同 recv
Definition: socket.c:257
void poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
INT32 clientFd
打开终端文件句柄
Definition: telnet_dev.h:64
BOOL eventPend
任务是否处于挂起
Definition: telnet_dev.h:66
UINT32 id
Definition: telnet_dev.h:65
EVENT_CB_S eventTelnet
远程登录事件
Definition: telnet_dev.h:67
wait_queue_head_t wait
等待队列
Definition: telnet_dev.h:68
TELNTE_FIFO_S * cmdFifo
Definition: telnet_dev.h:69
UINT32 rxOutIndex
Definition: telnet_dev.h:57
CHAR rxBuf[FIFO_MAX]
Definition: telnet_dev.h:60
UINT32 fifoNum
Definition: telnet_dev.h:58
UINT32 rxIndex
Definition: telnet_dev.h:56
vnode并不包含文件名,因为 vnode和文件名是 1:N 的关系
Definition: vnode.h:164
void * data
Definition: vnode.h:176
INT32 TelnetedRegister(VOID)
Definition: telnet_dev.c:365
STATIC INT32 TelnetOpen(struct file *file)
Definition: telnet_dev.c:140
STATIC INT32 TelnetIoctl(struct file *file, const INT32 cmd, unsigned long arg)
远程登录控制操作
Definition: telnet_dev.c:285
STATIC EVENT_CB_S * g_event
Definition: telnet_dev.c:57
STATIC TELNET_DEV_S g_telnetDev
远程登录设备
Definition: telnet_dev.c:56
INT32 TelnetTx(const CHAR *buf, UINT32 bufLen)
Definition: telnet_dev.c:94
INT32 TelnetDevDeinit(VOID)
Definition: telnet_dev.c:405
STATIC INLINE TELNET_DEV_S * GetTelnetDevByFile(const struct file *file, BOOL isOpenOp)
Definition: telnet_dev.c:60
INT32 TelnetedUnregister(VOID)
Definition: telnet_dev.c:354
STATIC INT32 TelnetPoll(struct file *file, poll_table *table)
Definition: telnet_dev.c:316
STATIC const struct file_operations_vfs g_telnetOps
Definition: telnet_dev.c:339
STATIC struct Vnode * g_currentVnode
Definition: telnet_dev.c:58
INT32 TelnetDevInit(INT32 clientFd)
Definition: telnet_dev.c:382
STATIC ssize_t TelnetWrite(struct file *file, const CHAR *buf, const size_t bufLen)
Definition: telnet_dev.c:248
STATIC INT32 TelnetClose(struct file *file)
Definition: telnet_dev.c:174
STATIC ssize_t TelnetRead(struct file *file, CHAR *buf, size_t bufLen)
Definition: telnet_dev.c:203
VOID TelnetLock(VOID)
Definition: telnet_loop.c:157
VOID TelnetUnlock(VOID)
Definition: telnet_loop.c:162