更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
telnet_loop.c 文件参考

telnet实现过程 https://docs.huihoo.com/rfc/RFC854.txt 更多...

浏览源代码.

函数

VOID TelnetLock (VOID)
 
VOID TelnetUnlock (VOID)
 
STATIC UINT8ReadFilter (const UINT8 *src, UINT32 srcLen, UINT32 *dstLen)
 
STATIC ssize_t WriteToFd (INT32 fd, const CHAR *src, size_t srcLen)
 
STATIC VOID TelnetClientClose (VOID)
 
STATIC VOID TelnetRelease (VOID)
 
STATIC VOID TelnetdDeinit (VOID)
 
STATIC INT32 TelnetdInit (UINT16 port)
 
STATIC INT32 TelnetClientPrepare (INT32 clientFd)
 远程登录客户端准备阶段 更多...
 
STATIC VOID * TelnetClientLoop (VOID *arg)
 TelnetClientLoop 处理远程客户端的请求任务的入口函数 更多...
 
STATIC VOID TelnetClientTaskAttr (pthread_attr_t *threadAttr)
 
STATIC INT32 TelnetdAcceptClient (INT32 clientFd, const struct sockaddr_in *inTelnetAddr)
 
STATIC VOID TelnetdAcceptLoop (INT32 listenFd)
 
STATIC INT32 TelnetdMain (VOID)
 TelnetdMain 更多...
 
STATIC VOID TelnetdTaskInit (VOID)
 TelnetdTaskInit 创建 telnet 服务端任务

1. telnet启动要确保网络驱动及网络协议栈已经初始化完成,且板子的网卡是link up状态。
2. 暂时无法支持多个客户端(telnet + IP)同时连接开发板。
须知: telnet属于调测功能,默认配置为关闭,正式产品中禁止使用该功能。 更多...
 
STATIC VOID TelnetdTaskDeinit (VOID)
 
STATIC VOID TelnetUsage (VOID)
 远程登录用法 telnet [on | off] 更多...
 
INT32 TelnetCmd (UINT32 argc, const CHAR **argv)
 本命令用于启动或关闭telnet server服务 更多...
 
 SHELLCMD_ENTRY (telnet_shellcmd, CMD_TYPE_EX, "telnet", 1,(CmdCallBackFunc) TelnetCmd)
 

变量

STATIC volatile INT32 g_telnetClientFd = -1
 
STATIC volatile INT32 g_telnetListenFd = -1
 
STATIC volatile UINT32 g_telnetMask = 0
 
STATIC atomic_t g_telnetTaskId = 0
 telnet 服务端任务ID 更多...
 
pthread_mutex_t g_telnetMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 

详细描述

telnet实现过程 https://docs.huihoo.com/rfc/RFC854.txt

 telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,
 是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的 能力。
 在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,
 就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个 telnet会话,必须输入用户名和密码来登录服务器。
 Telnet是常用的远程控制Web服务器的方法。

 但是,telnet因为采用明文传送报文,安全性不好,很多Linux服务器都不开放telnet服务,而改用更安全的ssh方式了。
 但仍然有很多别的系统可能采用了telnet方式来提供远程登录,因此弄清楚telnet客户端的使用方式仍是很有必要的。

 telnet命令还可做别的用途,比如确定远程服务的状态,比如确定远程服务器的某个端口是否能访问。

 下面几个编码对NVT打印机有确定意义:
 
 名称                         编码          意义
 
 NULL (NUL)                 0       没有操作
 BELL (BEL)                 7       产生一个可以看到或可以听到的信号(而不移动打印头。)
 Back Space (BS)            8       向左移动打印头一个字符位置。
 Horizontal Tab (HT)        9       把打印头移到下一个水平制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
 Line Feed (LF)             10      打印头移到下一个打印行,但不改变打印头的水平位置。
 Vertical Tab (VT)      11      把打印头移到下一个垂直制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
 Form Feed (FF)             12      把打印头移到下一页的顶部,保持打印头在相同的水平位置上。
 Carriage Return (CR)   13      把打印头移到当前行的左边 。


 下面是所有已定义的TELNET命令。需要注意的是,这些代码和代码序列只有在前面跟一个IAC时才有意义。
 ------------------------------------------------------------------------
 名称                     代码                     意义
 ------------------------------------------------------------------------
 SE                      240                子谈判参数的结束
 NOP                     241                空操作
 Data Mark               242                一个同步信号的数据流部分。该命令的后面经常跟着一个TCP紧急通知
 Break                   243                NVT的BRK字符
 Interrupt Process       244                IP功能.
 Abort output            245                AO功能.
 Are You There           246                AYT功能.
 Erase character         247                EC功能.
 Erase Line              248                EL功能.
 Go ahead                249                GA信号.
 SB                      250                表示后面所跟的是对需要的选项的子谈判
 WILL (option code)      251                表示希望开始使用或者确认所使用的是指定的选项。
 WON'T (option code)     252                表示拒绝使用或者继续使用指定的选项。
 DO (option code)        253                表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
 DON'T (option code)     254                表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。 
 IAC                     255                   Data Byte 255.
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-22

在文件 telnet_loop.c 中定义.

函数说明

◆ ReadFilter()

STATIC UINT8 * ReadFilter ( const UINT8 src,
UINT32  srcLen,
UINT32 dstLen 
)

在文件 telnet_loop.c168 行定义.

169{
170 STATIC UINT8 buf[TELNET_CLIENT_READ_FILTER_BUF_SIZE];
171 UINT8 *dst = buf;
172 UINT32 left = srcLen;
173
174 while (left > 0) {
175 if (*src != TELNET_IAC) {
176 *dst = *src;
177 dst++;
178 src++;
179 left--;
180 continue;
181 }
182
183 /*
184 * if starting with IAC, filter out IAC as following
185 * |IAC| --> skip
186 * |IAC|NOP|... --> ... : skip for putty keepalive etc.
187 * |IAC|x| --> skip
188 * |IAC|IAC|x|... --> |IAC|... : skip for literal cmds
189 * |IAC|SB|NAWS|x1|x2|x3|x4|IAC|SE|... --> ... : skip NAWS(unsupported)
190 * |IAC|x|x|... --> ... : skip unsupported IAC
191 */
192 if (left == 1) {
193 break;
194 }
195 /* left no less than 2 */
196 if (*(src + 1) == TELNET_NOP) {
197 src += LEN_IAC_CMD;
198 left -= LEN_IAC_CMD;
199 continue;
200 }
201 if (left == LEN_IAC_CMD) {
202 break;
203 }
204 /* left no less than 3 */
205 if (*(src + 1) == TELNET_IAC) {
206 *dst = TELNET_IAC;
207 dst++;
208 src += LEN_IAC_CMD;
209 left -= LEN_IAC_CMD;
210 continue;
211 }
212 if ((*(src + 1) == TELNET_SB) && (*(src + LEN_IAC_CMD) == TELNET_NAWS)) {
213 if (left > LEN_IAC_CMD_NAWS) {
214 src += LEN_IAC_CMD_NAWS;
215 left -= LEN_IAC_CMD_NAWS;
216 continue;
217 }
218 break;
219 }
220 src += LEN_IAC_CMD_OPT;
221 left -= LEN_IAC_CMD_OPT;
222 }
223
224 if (dstLen != NULL) {
225 *dstLen = dst - buf;
226 }
227 return buf;
228}
unsigned char UINT8
Definition: los_typedef.h:55
unsigned int UINT32
Definition: los_typedef.h:57
这是这个函数的调用关系图:

◆ SHELLCMD_ENTRY()

SHELLCMD_ENTRY ( telnet_shellcmd  ,
CMD_TYPE_EX  ,
"telnet"  ,
,
(CmdCallBackFunc TelnetCmd 
)

◆ TelnetClientClose()

STATIC VOID TelnetClientClose ( VOID  )

在文件 telnet_loop.c265 行定义.

266{
267 /* check if there is any client connection */
268 if (g_telnetMask == 0) {//没有任务在远程链接,
269 return;
270 }
271 (VOID)TelnetDevDeinit();
272 g_telnetMask = 0;
273 printf("telnet client disconnected.\n");
274}
INT32 TelnetDevDeinit(VOID)
Definition: telnet_dev.c:405
STATIC volatile UINT32 g_telnetMask
Definition: telnet_loop.c:151
函数调用图:
这是这个函数的调用关系图:

◆ TelnetClientLoop()

STATIC VOID * TelnetClientLoop ( VOID *  arg)

TelnetClientLoop 处理远程客户端的请求任务的入口函数

参数
arg
返回
参见

在文件 telnet_loop.c409 行定义.

410{
411 struct pollfd pollFd;
412 INT32 ret;
413 INT32 nRead;
414 UINT32 len;
415 UINT8 buf[TELNET_CLIENT_READ_BUF_SIZE];
416 UINT8 *cmdBuf = NULL;
417 INT32 clientFd = (INT32)(UINTPTR)arg;
418
419 (VOID)prctl(PR_SET_NAME, "TelnetClientLoop", 0, 0, 0);
420 TelnetLock();
421 if (TelnetClientPrepare(clientFd) != 0) {//做好准备工作
422 TelnetUnlock();
423 (VOID)close(clientFd);
424 return NULL;
425 }
426 TelnetUnlock();
427
428 while (1) {//死循环接受远程输入的数据
429 pollFd.fd = clientFd;
430 pollFd.events = POLLIN | POLLRDHUP;//监听读数据和挂起事件
431 pollFd.revents = 0;
432 /*
433 POLLIN 普通或优先级带数据可读
434 POLLRDNORM 普通数据可读
435 POLLRDBAND 优先级带数据可读
436 POLLPRI 高优先级数据可读
437 POLLOUT 普通数据可写
438 POLLWRNORM 普通数据可写
439 POLLWRBAND 优先级带数据可写
440 POLLERR 发生错误
441 POLLHUP 发生挂起
442 POLLNVAL 描述字不是一个打开的文件
443 poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,
444 如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,
445 直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。
446   这个过程经历了多次无谓的遍历。
447   poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
448   poll与select的不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,
449 pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次
450   poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,
451 然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。poll返回后,
452 需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。
453 优点
454 1)poll() 不要求开发者计算最大文件描述符加一的大小。
455 2)poll() 在应付大数目的文件描述符的时候速度更快,相比于select。
456 3)它没有最大连接数的限制,原因是它是基于链表来存储的。
457 缺点
458 1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
459 2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
460 */
461 ret = poll(&pollFd, 1, TELNET_CLIENT_POLL_TIMEOUT);//等2秒钟返回
462 if (ret < 0) {//失败时,poll()返回-1
463 break;
464 /* ret < 0 各值
465   EBADF   一个或多个结构体中指定的文件描述符无效。
466   EFAULTfds   指针指向的地址超出进程的地址空间。
467   EINTR     请求的事件之前产生一个信号,调用可以重新发起。
468   EINVALnfds  参数超出PLIMIT_NOFILE值。
469   ENOMEM   可用内存不足,无法完成请求
470
471 */
472 }
473 if (ret == 0) {//如果在超时前没有任何事件发生,poll()返回0
474 continue;
475 }
476 /* connection reset, maybe keepalive failed or reset by peer | 连接重置,可能keepalive失败或被peer重置*/
477 if ((UINT16)pollFd.revents & (POLLERR | POLLHUP | POLLRDHUP)) {
478 break;
479 }
480
481 if ((UINT16)pollFd.revents & POLLIN) {//数据事件
482 nRead = read(clientFd, buf, sizeof(buf));//读远程终端过来的数据
483 if (nRead <= 0) {
484 /* telnet client shutdown */
485 break;
486 }
487 cmdBuf = ReadFilter(buf, (UINT32)nRead, &len);//对数据过滤
488 if (len > 0) {
489 (VOID)TelnetTx((CHAR *)cmdBuf, len);//对数据加工处理
490 }
491 }
492 }
493 TelnetLock();
495 (VOID)close(clientFd);
496 clientFd = -1;
497 g_telnetClientFd = -1;
498 TelnetUnlock();
499 return NULL;
500}
unsigned short UINT16
Definition: los_typedef.h:56
signed int INT32
Definition: los_typedef.h:60
unsigned long UINTPTR
Definition: los_typedef.h:68
char CHAR
Definition: los_typedef.h:63
INT32 TelnetTx(const CHAR *buf, UINT32 len)
Definition: telnet_dev.c:94
STATIC INT32 TelnetClientPrepare(INT32 clientFd)
远程登录客户端准备阶段
Definition: telnet_loop.c:358
VOID TelnetLock(VOID)
Definition: telnet_loop.c:157
VOID TelnetUnlock(VOID)
Definition: telnet_loop.c:162
STATIC VOID TelnetClientClose(VOID)
Definition: telnet_loop.c:265
STATIC UINT8 * ReadFilter(const UINT8 *src, UINT32 srcLen, UINT32 *dstLen)
Definition: telnet_loop.c:168
STATIC volatile INT32 g_telnetClientFd
Definition: telnet_loop.c:145
函数调用图:
这是这个函数的调用关系图:

◆ TelnetClientPrepare()

STATIC INT32 TelnetClientPrepare ( INT32  clientFd)

远程登录客户端准备阶段

在文件 telnet_loop.c358 行定义.

359{
360 INT32 keepAlive = TELNET_KEEPALIVE;
361 INT32 keepIdle = TELNET_KEEPIDLE;
362 INT32 keepInterval = TELNET_KEEPINTV;
363 INT32 keepCnt = TELNET_KEEPCNT;
364 const UINT8 doEcho[] = { TELNET_IAC, TELNET_DO, TELNET_ECHO };
365 const UINT8 doNaws[] = { TELNET_IAC, TELNET_DO, TELNET_NAWS };
366 const UINT8 willEcho[] = { TELNET_IAC, TELNET_WILL, TELNET_ECHO };
367 const UINT8 willSga[] = { TELNET_IAC, TELNET_WILL, TELNET_SGA };
368
369 if (g_telnetListenFd == -1) {
370 return -1;
371 }
372 g_telnetClientFd = clientFd;
373 if (TelnetDevInit(clientFd) != 0) {//远程登录设备初始化
374 g_telnetClientFd = -1;
375 return -1;
376 }
377 g_telnetMask = 1;//表示有任务在远程登录
378
379 /* negotiate with client | 与客户协商*/
380 (VOID)WriteToFd(clientFd, (CHAR *)doEcho, sizeof(doEcho));
381 (VOID)WriteToFd(clientFd, (CHAR *)doNaws, sizeof(doNaws));
382 (VOID)WriteToFd(clientFd, (CHAR *)willEcho, sizeof(willEcho));
383 (VOID)WriteToFd(clientFd, (CHAR *)willSga, sizeof(willSga));
384
385 /* enable TCP keepalive to check whether telnet link is alive | 设置保持连接的方式 */
386 if (setsockopt(clientFd, SOL_SOCKET, SO_KEEPALIVE, (VOID *)&keepAlive, sizeof(keepAlive)) < 0) {
387 PRINT_ERR("telnet setsockopt SO_KEEPALIVE error.\n");
388 }
389 if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPIDLE, (VOID *)&keepIdle, sizeof(keepIdle)) < 0) {
390 PRINT_ERR("telnet setsockopt TCP_KEEPIDLE error.\n");
391 }
392 if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPINTVL, (VOID *)&keepInterval, sizeof(keepInterval)) < 0) {
393 PRINT_ERR("telnet setsockopt TCP_KEEPINTVL error.\n");
394 }
395 if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPCNT, (VOID *)&keepCnt, sizeof(keepCnt)) < 0) {
396 PRINT_ERR("telnet setsockopt TCP_KEEPCNT error.\n");
397 }
398 return 0;
399}
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
设置socket 配置项
Definition: socket.c:148
INT32 TelnetDevInit(INT32 fd)
Definition: telnet_dev.c:382
STATIC ssize_t WriteToFd(INT32 fd, const CHAR *src, size_t srcLen)
Definition: telnet_loop.c:237
STATIC volatile INT32 g_telnetListenFd
Definition: telnet_loop.c:148
函数调用图:
这是这个函数的调用关系图:

◆ TelnetClientTaskAttr()

STATIC VOID TelnetClientTaskAttr ( pthread_attr_t *  threadAttr)

在文件 telnet_loop.c502 行定义.

503{
504 (VOID)pthread_attr_init(threadAttr);//初始化线程属性
505 threadAttr->inheritsched = PTHREAD_EXPLICIT_SCHED;//
506 threadAttr->schedparam.sched_priority = TELNET_TASK_PRIORITY;//线程优先级
507 threadAttr->detachstate = PTHREAD_CREATE_DETACHED;//任务分离模式
508 (VOID)pthread_attr_setstacksize(threadAttr, TELNET_TASK_STACK_SIZE);//设置任务内核栈大小
509}
int pthread_attr_init(pthread_attr_t *attr)
Definition: pthread_attr.c:36
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stackSize)
设置栈大小
Definition: pthread_attr.c:216
函数调用图:
这是这个函数的调用关系图:

◆ TelnetCmd()

INT32 TelnetCmd ( UINT32  argc,
const CHAR **  argv 
)

本命令用于启动或关闭telnet server服务

在文件 telnet_loop.c692 行定义.

693{
694 if (argc != 1) {
695 TelnetUsage();
696 return 0;
697 }
698
699 if (strcmp(argv[0], "on") == 0) {// 输入 telnet on
700 /* telnet on: try to start telnet server task */
701 TelnetdTaskInit(); //启动远程登录 服务端任务
702 return 0;
703 }
704 if (strcmp(argv[0], "off") == 0) {// 输入 telnet off
705 /* telnet off: try to stop clients, then stop server task */
706 TelnetdTaskDeinit();//关闭所有的客户端,并关闭服务端任务
707 return 0;
708 }
709
710 TelnetUsage();
711 return 0;
712}
STATIC VOID TelnetdTaskInit(VOID)
TelnetdTaskInit 创建 telnet 服务端任务 1. telnet启动要确保网络驱动及网络协议栈已经初始化完成,且板子的网卡是link up状态。 2....
Definition: telnet_loop.c:646
STATIC VOID TelnetdTaskDeinit(VOID)
Definition: telnet_loop.c:671
STATIC VOID TelnetUsage(VOID)
远程登录用法 telnet [on | off]
Definition: telnet_loop.c:684
函数调用图:

◆ TelnetdAcceptClient()

STATIC INT32 TelnetdAcceptClient ( INT32  clientFd,
const struct sockaddr_in *  inTelnetAddr 
)

在文件 telnet_loop.c517 行定义.

518{
519 INT32 ret = 0;
520 pthread_t tmp;
521 pthread_attr_t useAttr;
522
523 TelnetClientTaskAttr(&useAttr);
524
525 if (clientFd < 0) {
526 ret = -1;
527 goto ERROUT;
528 }
529
530 TelnetLock();
531
532 if (g_telnetListenFd == -1) {
533 /* server already has been closed, so quit this task now */
534 ret = -1;
535 goto ERROUT_UNLOCK;
536 }
537
538 if (g_telnetClientFd >= 0) { //只接收一个客户端
539 /* alreay connected and support only one */
540 goto ERROUT_UNLOCK;
541 }
542
543 g_telnetClientFd = clientFd;
544 //创建一个线程处理客户端的请求
545 if (pthread_create(&tmp, &useAttr, TelnetClientLoop, (VOID *)(UINTPTR)clientFd) != 0) {
546 PRINT_ERR("Failed to create client handle task\n");
547 g_telnetClientFd = -1;
548 goto ERROUT_UNLOCK;
549 }
550 TelnetUnlock();
551 return ret;
552
553ERROUT_UNLOCK:
554 (VOID)close(clientFd);
555 clientFd = -1;
556 TelnetUnlock();
557ERROUT:
558 return ret;
559}
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*startRoutine)(void *), void *arg)
pthread_create 创建线程
Definition: pthread.c:229
STATIC VOID * TelnetClientLoop(VOID *arg)
TelnetClientLoop 处理远程客户端的请求任务的入口函数
Definition: telnet_loop.c:409
STATIC VOID TelnetClientTaskAttr(pthread_attr_t *threadAttr)
Definition: telnet_loop.c:502
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdAcceptLoop()

STATIC VOID TelnetdAcceptLoop ( INT32  listenFd)

在文件 telnet_loop.c565 行定义.

566{
567 INT32 clientFd = -1;
568 struct sockaddr_in inTelnetAddr;
569 INT32 len = sizeof(inTelnetAddr);
570
571 TelnetLock();
572 g_telnetListenFd = listenFd;
573
574 while (g_telnetListenFd >= 0) {//必须启动监听
575 TelnetUnlock();
576
577 (VOID)memset_s(&inTelnetAddr, sizeof(inTelnetAddr), 0, sizeof(inTelnetAddr));
578 clientFd = accept(listenFd, (struct sockaddr *)&inTelnetAddr, (socklen_t *)&len);//接收数据
579 if (TelnetdAcceptClient(clientFd, &inTelnetAddr) == 0) {//
580 /*
581 * Sleep sometime before next loop: mostly we already have one connection here,
582 * and the next connection will be declined. So don't waste our cpu.
583 | 在下一个循环来临之前休息片刻,因为鸿蒙只支持一个远程登录,此时已经有一个链接,
584 在TelnetdAcceptClient中创建线程不会立即调度, 休息下任务会挂起,重新调度
585 */
586 LOS_Msleep(TELNET_ACCEPT_INTERVAL);//以休息的方式发起调度. 直接申请调度也未尝不可吧 @note_thinking
587 } else {
588 return;
589 }
590 TelnetLock();
591 }
592 TelnetUnlock();
593}
LITE_OS_SEC_TEXT_MINOR VOID LOS_Msleep(UINT32 msecs)
Sleep the current task.
Definition: los_misc.c:44
int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
Definition: socket.c:70
STATIC INT32 TelnetdAcceptClient(INT32 clientFd, const struct sockaddr_in *inTelnetAddr)
Definition: telnet_loop.c:517
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdDeinit()

STATIC VOID TelnetdDeinit ( VOID  )

在文件 telnet_loop.c291 行定义.

292{
293 if (atomic_read(&g_telnetTaskId) == 0) {
294 PRINTK("telnet server is not running!\n");
295 return;
296 }
297
299 (VOID)TelnetedUnregister();
300 atomic_set(&g_telnetTaskId, 0);
301 PRINTK("telnet server closed.\n");
302}
INT32 TelnetedUnregister(VOID)
Definition: telnet_dev.c:354
STATIC atomic_t g_telnetTaskId
telnet 服务端任务ID
Definition: telnet_loop.c:153
STATIC VOID TelnetRelease(VOID)
Definition: telnet_loop.c:277
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdInit()

STATIC INT32 TelnetdInit ( UINT16  port)

ai_family参数指定调用者期待返回的套接口地址结构的类型。它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC AF_INET: 不能返回任何IPV6相关的地址信息 AF_INET6: 不能返回任何IPV4地址信息 AF_UNSPEC: 返回的是适用于指定主机名和服务名且适合任何协议族的地址。如果某个主机既有AAAA记录(IPV6)地址, 同时又有A记录(IPV4)地址,那么AAAA记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回

在文件 telnet_loop.c310 行定义.

311{
312 INT32 listenFd;
313 INT32 reuseAddr = 1;
314 struct sockaddr_in inTelnetAddr;
315 /**
316 ai_family参数指定调用者期待返回的套接口地址结构的类型。它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC
317 AF_INET: 不能返回任何IPV6相关的地址信息
318 AF_INET6: 不能返回任何IPV4地址信息
319 AF_UNSPEC: 返回的是适用于指定主机名和服务名且适合任何协议族的地址。如果某个主机既有AAAA记录(IPV6)地址,
320 同时又有A记录(IPV4)地址,那么AAAA记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回
321 */
322 //SOCK_STREAM 表示TCP协议
323 listenFd = socket(AF_INET, SOCK_STREAM, 0);//打开一个socker fd
324 if (listenFd == -1) {
325 PRINT_ERR("TelnetdInit : socket error.\n");
326 goto ERR_OUT;
327 }
328
329 /* reuse listen port */
330 if (setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0) {
331 PRINT_ERR("TelnetdInit : setsockopt REUSEADDR error.\n");
332 goto ERR_CLOSE_FD;
333 }
334
335 (VOID)memset_s(&inTelnetAddr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
336 inTelnetAddr.sin_family = AF_INET;
337 inTelnetAddr.sin_addr.s_addr = INADDR_ANY;
338 inTelnetAddr.sin_port = htons(port);
339 //绑定端口
340 if (bind(listenFd, (const struct sockaddr *)&inTelnetAddr, sizeof(struct sockaddr_in)) == -1) {
341 PRINT_ERR("TelnetdInit : bind error.\n");
342 goto ERR_CLOSE_FD;
343 }
344 //监听端口数据
345 if (listen(listenFd, TELNET_LISTEN_BACKLOG) == -1) {
346 PRINT_ERR("TelnetdInit : listen error.\n");
347 goto ERR_CLOSE_FD;
348 }
349
350 return listenFd;
351
352ERR_CLOSE_FD:
353 (VOID)close(listenFd);
354ERR_OUT:
355 return -1;
356}
int bind(int s, const struct sockaddr *name, socklen_t namelen)
Definition: socket.c:94
int listen(int s, int backlog)
Definition: socket.c:209
int socket(int domain, int type, int protocol)
Definition: socket.c:314
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdMain()

STATIC INT32 TelnetdMain ( VOID  )

TelnetdMain

    telnet启动要确保网络驱动及网络协议栈已经初始化完成,且板子的网卡是link up状态。
   暂时无法支持多个客户端(telnet + IP)同时连接开发板。
    输入 telnet on
    OHOS # telnet on
    OHOS # start telnet server successfully, waiting for connection.
返回

参见

在文件 telnet_loop.c608 行定义.

609{
610 INT32 sock;
611 INT32 ret;
612
613 sock = TelnetdInit(TELNETD_PORT);//1.初始化 创建 socket ,socket的本质就是打开了一个虚拟文件
614 if (sock == -1) {
615 PRINT_ERR("telnet init error.\n");
616 return -1;
617 }
618
619 TelnetLock();
620 ret = TelnetedRegister();//2.注册驱动程序 /dev/telnet ,g_telnetOps g_telnetDev
621 TelnetUnlock();
622
623 if (ret != 0) {
624 PRINT_ERR("telnet register error.\n");
625 (VOID)close(sock);
626 return -1;
627 }
628
629 PRINTK("start telnet server successfully, waiting for connection.\n");
630 TelnetdAcceptLoop(sock);//3.等待连接,处理远程终端过来的命令 例如#task 命令
631 return 0;
632}
INT32 TelnetedRegister(VOID)
Definition: telnet_dev.c:365
STATIC INT32 TelnetdInit(UINT16 port)
Definition: telnet_loop.c:310
STATIC VOID TelnetdAcceptLoop(INT32 listenFd)
Definition: telnet_loop.c:565
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdTaskDeinit()

STATIC VOID TelnetdTaskDeinit ( VOID  )

在文件 telnet_loop.c671 行定义.

672{
673 if (atomic_read(&g_telnetTaskId) == 0) {
674 PRINTK("telnet server is not running, please start up telnet server first.\n");
675 return;
676 }
677
678 TelnetLock();
681 TelnetUnlock();
682}
STATIC VOID TelnetdDeinit(VOID)
Definition: telnet_loop.c:291
函数调用图:
这是这个函数的调用关系图:

◆ TelnetdTaskInit()

STATIC VOID TelnetdTaskInit ( VOID  )

TelnetdTaskInit 创建 telnet 服务端任务

1. telnet启动要确保网络驱动及网络协议栈已经初始化完成,且板子的网卡是link up状态。
2. 暂时无法支持多个客户端(telnet + IP)同时连接开发板。
须知: telnet属于调测功能,默认配置为关闭,正式产品中禁止使用该功能。

返回
参见

在文件 telnet_loop.c646 行定义.

647{
648 UINT32 ret;
649 TSK_INIT_PARAM_S initParam = {0};
650
651 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TelnetdMain; // telnet任务入口函数
652 initParam.uwStackSize = TELNET_TASK_STACK_SIZE; // 8K
653 initParam.pcName = "TelnetServer"; //任务名称
654 initParam.usTaskPrio = TELNET_TASK_PRIORITY; //优先级 9,和 shell 的优先级一样
655 initParam.uwResved = LOS_TASK_STATUS_DETACHED; //独立模式
656
657 if (atomic_read(&g_telnetTaskId) != 0) {//只支持一个 telnet 服务任务
658 PRINT_ERR("telnet server is already running!\n");
659 return;
660 }
661
662 ret = LOS_TaskCreate((UINT32 *)&g_telnetTaskId, &initParam);//创建远程登录服务端任务并发起调度
663 if (ret != LOS_OK) {
664 PRINT_ERR("failed to create telnet server task!\n");
665 }
666}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务
Definition: los_task.c:718
VOID *(* TSK_ENTRY_FUNC)(UINTPTR param1, UINTPTR param2, UINTPTR param3, UINTPTR param4)
Define the type of a task entrance function.
Definition: los_task.h:480
UINT16 usTaskPrio
Definition: los_task.h:505
UINT32 uwStackSize
Definition: los_task.h:508
CHAR * pcName
Definition: los_task.h:509
TSK_ENTRY_FUNC pfnTaskEntry
Definition: los_task.h:504
UINT32 uwResved
Definition: los_task.h:513
STATIC INT32 TelnetdMain(VOID)
TelnetdMain
Definition: telnet_loop.c:608
函数调用图:
这是这个函数的调用关系图:

◆ TelnetLock()

VOID TelnetLock ( VOID  )

在文件 telnet_loop.c157 行定义.

158{
160}
int pthread_mutex_lock(pthread_mutex_t *mutex)
互斥锁加锁操作
pthread_mutex_t g_telnetMutex
Definition: telnet_loop.c:155
函数调用图:
这是这个函数的调用关系图:

◆ TelnetRelease()

STATIC VOID TelnetRelease ( VOID  )

在文件 telnet_loop.c277 行定义.

278{
279 if (g_telnetClientFd >= 0) {
280 (VOID)close(g_telnetClientFd);
281 g_telnetClientFd = -1;
282 }
283
284 if (g_telnetListenFd >= 0) {
285 (VOID)close(g_telnetListenFd);
286 g_telnetListenFd = -1;
287 }
288}
这是这个函数的调用关系图:

◆ TelnetUnlock()

VOID TelnetUnlock ( VOID  )

在文件 telnet_loop.c162 行定义.

163{
165}
int pthread_mutex_unlock(pthread_mutex_t *mutex)
解锁互斥锁
函数调用图:
这是这个函数的调用关系图:

◆ TelnetUsage()

STATIC VOID TelnetUsage ( VOID  )

远程登录用法 telnet [on | off]

在文件 telnet_loop.c684 行定义.

685{
686 PRINTK("Usage: telnet [OPTION]...\n");
687 PRINTK("Start or close telnet server.\n\n");
688 PRINTK(" on Init the telnet server\n");
689 PRINTK(" off Deinit the telnet server\n");
690}
这是这个函数的调用关系图:

◆ WriteToFd()

STATIC ssize_t WriteToFd ( INT32  fd,
const CHAR src,
size_t  srcLen 
)

在文件 telnet_loop.c237 行定义.

238{
239 size_t sizeLeft;
240 ssize_t sizeWritten;
241
242 sizeLeft = srcLen;
243 while (sizeLeft > 0) {
244 sizeWritten = write(fd, src, sizeLeft);
245 if (sizeWritten < 0) {
246 /* last write failed */
247 if (sizeLeft == srcLen) {
248 /* nothing was written in any loop */
249 return -1;
250 } else {
251 /* something was written in previous loop */
252 break;
253 }
254 } else if (sizeWritten == 0) {
255 break;
256 }
257 sizeLeft -= (size_t)sizeWritten;
258 src += sizeWritten;
259 }
260
261 return (ssize_t)(srcLen - sizeLeft);
262}
UINT64 size_t
Definition: los_typedef.h:80
INT64 ssize_t
Definition: los_typedef.h:79
这是这个函数的调用关系图:

变量说明

◆ g_telnetClientFd

STATIC volatile INT32 g_telnetClientFd = -1

在文件 telnet_loop.c145 行定义.

◆ g_telnetListenFd

STATIC volatile INT32 g_telnetListenFd = -1

在文件 telnet_loop.c148 行定义.

◆ g_telnetMask

STATIC volatile UINT32 g_telnetMask = 0

在文件 telnet_loop.c151 行定义.

◆ g_telnetMutex

pthread_mutex_t g_telnetMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP

在文件 telnet_loop.c155 行定义.

◆ g_telnetTaskId

STATIC atomic_t g_telnetTaskId = 0

telnet 服务端任务ID

在文件 telnet_loop.c153 行定义.