最近在看telnet终端登陆的相关程序,了解到了telnet登陆的进程安排。对照UNIX环境高级编程对其中使用伪终端的部分进行了一些学习。
首先,telnet登陆的典型安排如下:
1.telnet client通过connect连接telnet server
2.telnet server 调用accept接受连接请求,并fork子进程1处理与client之间的连接。同时打开伪终端主设备
3.子进程1再fork子进程调用login,同时打开伪终端从设备
4.login处理完验证等处理后,exec登陆shell
5.登陆shell利用伪终端从设备和子进程1之间进行通信
下面是打开伪终端的代码:
ptym_open用于打开伪终端主设备,并通过参数输出对应的伪终端从设备名称
ptys_open用伪终端从设备名打开从设备
grantpt用于更改从设备的节点的权限为用户读写,组写。
unlockpt函数用于准予对伪终端从设备的访问,从而允许应用程序打开该设备。阻止其他进程打开从设备后,建立该设备的应用程序有机会在使用主,从设备之间正确地初始化
这些设备。
有一些用编译宏控制打开的函数,这些函数在Linux系统上一般是存在的,如果对应的系统上支持这些函数,可以通过编译宏将这些函数关闭。如果对应的系统上不存在,可以
用编译宏打开这些函数,同时可以了解这些函数的实现机制。
#include "apue.h"
#include <fcntl.h>
#ifndef _HAS_OPENPT
INT posix_openpt(INT iFlag)
{
INT iFdMaster;
iFdMaster = open("/dev/ptmx",iFlag);
return iFdMaster;
}
#endif
#ifndef _HAS_PTSNAME
CHAR *ptsname(int iFd)
{
int iSlave;
STATIC CHAR szPtsName[16];
if(ioctl(iFd,TIOCGPTN,&iSlave) < 0)
{
return NULL;
}
szPtsName[0] = 0;
snprintf(szPtsName,sizeof(szPtsName),"/dev/pts/%d",iSlave);
return szPtsName;
}
#endif
#ifndef _HAS_GRANTPT
INT grantpt(int iMaster)
{
CHAR *pcPtsName;
pcPtsName = ptsname(iMaster);
return (chmod(pcPtsName,S_IRUSR|S_IWUSR|S_IWGRP);
}
#endif
#ifndef _HAS_UNLOCKPT
INT unlockpt(int iMaster)
{
INT iLock = 0;
return (ioctl(iMaster,TIOCSPTLCK,&iLock));
}
#endif
INT ptym_open(CHAR *pcPtsName,INT iNameLen)
{
CHAR *pcName;
INT iMaster;
strncpy(pcPtsName,"/dev/ptmx",iNameLen);
pcPtsName[iNameLen - 1] = 0;
iMaster = posix_openpt(O_RDWR);
if(iMaster < 0)
{
return -1;
}
if(grantpt(iMaster) < 0)
{
close(iMaster);
return -2;
}
if(unlockpt(iMaster) < 0)
{
close(iMaster);
return -3;
}
if((pcName = ptsname(iMaster)) == NULL)
{
close(iMaster);
return -4;
}
strncpy(pcPtsName,pcName,iNameLen);
pcPtsName[iNameLen - 1] = 0;
return iMaster;
}
INT ptys_open(const CHAR *pcName)
{
int iSlave;
if((iSlave = open(pcName,O_RDWR))<0)
{
return -5;
}
return iSlave;
}
INT main()
{
CHAR szPtsName[16];
INT iMaster,iSlave;
iMaster = ptym_open(szPtsName,sizeof(szPtsName));
if(iMaster < 0)
{
printf("ptym_open err [%d]\n",iMaster);
return iMaster;
}
printf("ptym_open success %s\n",szPtsName);
iSlave = ptys_open(szPtsName);
if(iSlave < 0)
{
printf("ptys_open err [%d]\n",iSlave);
return iSlave;
}
sleep(10);
close(iMaster);
close(iSlave);
return 0;
}