linux伪终端 telnet源码

 

pty_fun.cpp 

#include "pty_fun.h"

int ptym_open(char *pts_name, int pts_namesz)
{
	char *ptr;
	char fdm;
	/*
	 *return the name of the master device so that on failure
	 *the caller can print an error message. Null terminate to
	 *handle case where string lenth > pts_namesz
	 * */

	strncpy(pts_name, "/dev/ptmx", pts_namesz);
	pts_name[pts_namesz - 1] = '\0';

	fdm = posix_openpt(O_RDWR);
	if (fdm < 0)
		return OPEN_PTY_ERR;
	if (grantpt(fdm) < 0)
	{
		close(fdm);
		return GRANT_PTY_ERR;
	}
	if (unlockpt(fdm) < 0)
	{
		close(fdm);
		return UNLOCK_PTY_ERR;
	}
	if ((ptr = ptsname(fdm)) == NULL)
	{
		close(fdm);
		return GET_PTYS_NAME_ERR;
	}
	strncpy(pts_name, ptr, pts_namesz);
	pts_name[pts_namesz - 1] = '\0';

	return fdm;

}

int ptys_open(char *pts_name)
{
	int fds;
	if ((fds = open(pts_name, O_RDWR)) < 0)
		return OPEN_PTYS_ERR;
	return fds;
}

int pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
		const struct termios *slave_termiors,
		const struct winsize *slave_winsize, pid_t *ppid)
{
	int fdm, fds;
	pid_t pid;
	char pts_name[20];

	if ((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0)
	{
		return fdm;
	}

	if (slave_name != NULL)
	{
		strncpy(slave_name, pts_name, slave_namesz);
		slave_name[slave_namesz - 1] = '\0';
	}

	if ((pid = fork()) < 0)
	{
		return FORK_ERR;
	}
	else if (pid == 0)
	{
		if (setsid() < 0)
		{
			return SETSID_ERR;
		}
		if ((fds = ptys_open(pts_name)) < 0)
		{
			close(fdm);
			return OPEN_PTYS_ERR;
		}
#ifdef TIOCSCTTY
		if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
			return TIOCSCTTY_ERR;
#endif
//		if (slave_termiors != NULL)
//		{
//			if (tcsetattr(fds, TCSANOW, slave_termiors) < 0)
//				return INIT_ATTR_ERR;
//		}
//		if (slave_winsize != NULL)
//		{
//			if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
//				return INIT_ATTR_ERR;
//		}

		if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
			return DUP_STDIN_ERR;
		if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
			return DUP_STDOUT_ERR;
		if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
			return DUP_STDERR_ERR;
		if (fds != STDIN_FILENO && fds != STDOUT_FILENO && fds != STDERR_FILENO)
		{
			close(fds);
		}
		*ppid = 0;
		return 0;

	}
	else
	{
		*ptrfdm =fdm;
		*ppid = pid;
		return 0;
	}
}

 

 

pty_fun.h

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/limits.h>
#include <features.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>

//master pty
#ifndef OPEN_PTY_ERR
#define OPEN_PTY_ERR -1
#endif

#ifndef GRANT_PTY_ERR
#define GRANT_PTY_ERR -2
#endif

#ifndef UNLOCK_PTY_ERR
#define UNLOCK_PTY_ERR -3
#endif

#ifndef GET_PTYS_NAME_ERR
#define GET_PTYS_NAME_ERR -4
#endif

//pty slave
#ifndef OPEN_PTYS_ERR
#define OPEN_PTYS_ERR -5
#endif

#ifndef FORK_ERR
#define FORK_ERR -6
#endif

#ifndef SETSID_ERR
#define SETSID_ERR -7
#endif

#ifndef TIOCSCTTY_ERR
#define TIOCSCTTY_ERR -8
#endif

#ifndef INIT_ATTR_ERR
#define INIT_ATTR_ERR -9
#endif

#ifndef DUP_STDIN_ERR
#define DUP_STDIN_ERR -10
#endif

#ifndef DUP_STDOUT_ERR
#define DUP_STDOUT_ERR -11
#endif

#ifndef DUP_STDERR_ERR
#define DUP_STDERR_ERR -12
#endif




int ptym_open(char *pts_name, int pts_namesz);

int ptys_open(char *pts_name);

int pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
		const struct termios *slave_termiors,
		const struct winsize *slave_winsize, pid_t *ppid);


telnetserver.cpp

 

#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>
#include <pthread.h>

#include "pty_fun.h"

#define DEFAULTIP         "127.0.0.1"
#define DEFAULTPORT       "20013"
#define DEFAULTBACK       "10"
#define DEFAULTDIR        "/root"
#define DEFAULTLOG        "/tmp/telnet-server.log"
#define PTY_NAME_SIZE     20
#define MAX_BUFSIZE       512

typedef struct thread_arg
{
	int pty;
	int sockfd;
} thread_arg;

void prterrmsg(char *msg);
#define prterrmsg(msg)        { perror(msg); abort(); }
void wrterrmsg(char *msg);
#define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }

void prtinfomsg(char *msg);
#define prtinfomsg(msg)        { fputs(msg, stdout);  }
void wrtinfomsg(char *msg);
#define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}

#define MAXBUF        1024

char buffer[MAXBUF + 1];
char *host = 0;
char *port = 0;
char *back = 0;
char *dirroot = 0;
char *logdir = 0;
unsigned char daemon_y_n = 0;
FILE *logfp;

#define MAXPATH        150

/*------------------------------------------------------
 *--- AllocateMemory - 分配空间并把d所指的内容复制
 *------------------------------------------------------
 */
void AllocateMemory(char **s, int l, char *d)
{
	*s = malloc(l + 1);
	bzero(*s, l + 1);
	memcpy(*s, d, l);
}

/*------------------------------------------------------
 *--- getoption - 分析取出程序的参数
 *------------------------------------------------------
 */
void getoption(int argc, char **argv)
{
	int c, len;
	char *p = 0;

	opterr = 0;
	while (1)
	{
		int option_index = 0;
		static struct option long_options[] =
		{
		{ "host", 1, 0, 0 },
		{ "port", 1, 0, 0 },
		{ "back", 1, 0, 0 },
		{ "dir", 1, 0, 0 },
		{ "log", 1, 0, 0 },
		{ "daemon", 0, 0, 0 },
		{ 0, 0, 0, 0 } };
		/* 本程序支持如一些参数:
		 * --host IP地址 或者 -H IP地址
		 * --port 端口 或者 -P 端口
		 * --back 监听数量 或者 -B 监听数量
		 * --dir 服务默认目录 或者 -D 服务默认目录
		 * --log 日志存放路径 或者 -L 日志存放路径
		 * --daemon 使程序进入后台运行模式
		 */
		c = getopt_long(argc, argv, "H:P:B:D:L", long_options, &option_index);
		if (c == -1 || c == '?')
			break;

		if (optarg)
			len = strlen(optarg);
		else
			len = 0;

		if ((!c && !(strcasecmp(long_options[option_index].name, "host"))) || c
				== 'H')
			p = host = malloc(len + 1);
		else if ((!c && !(strcasecmp(long_options[option_index].name, "port")))
				|| c == 'P')
			p = port = malloc(len + 1);
		else if ((!c && !(strcasecmp(long_options[option_index].name, "back")))
				|| c == 'B')
			p = back = malloc(len + 1);
		else if ((!c && !(strcasecmp(long_options[option_index].name, "dir")))
				|| c == 'D')
			p = dirroot = malloc(len + 1);
		else if ((!c && !(strcasecmp(long_options[option_index].name, "log")))
				|| c == 'L')
			p = logdir = malloc(len + 1);
		else if ((!c
				&& !(strcasecmp(long_options[option_index].name, "daemon"))))
		{
			daemon_y_n = 1;
			continue;
		}
		else
			break;
		bzero(p, len + 1);
		memcpy(p, optarg, len);
	}
}

void *thread_recv_add_write_pyt(void *arg)
{
	int ret, sockfd, pty;
	char buffer[MAX_BUFSIZE];
	thread_arg *arg1 = (thread_arg*) arg;

	sockfd = arg1->sockfd;
	pty = arg1->pty;

	while (1)
	{
		memset(buffer, 0, MAX_BUFSIZE);
		ret = recv(sockfd, buffer, MAX_BUFSIZE, 0);
		if (ret < 0)
		{
			continue;
		}
		printf("%s", buffer);
		write(pty, buffer, strlen(buffer));
	}
}

void read_write_pty(int pty, int sockfd)
{
	char buffer[MAX_BUFSIZE];
	int ret;
	//	pthread_t thread_t;
	//	pthread_attr_t attr;
	//	thread_arg arg;
	//	arg.pty = pty;
	//	arg.sockfd = sockfd;
	//
	//	if ((ret = pthread_create(&thread_t, &attr, thread_recv_add_write_pyt,
	//			(void*) &arg)))
	//	{
	//		perror("thread create recieve message and write to pty err:\n");
	//	}

	pid_t pid;
	if ((pid = fork()) < 0)
	{
		perror("");
		exit(1);
	}
	else if (pid == 0)
	{
		while (1)
		{
			memset(buffer, 0, MAX_BUFSIZE);
			ret = recv(sockfd, buffer, MAX_BUFSIZE - 1, 0);
			if (ret < 0)
			{
				continue;
			}
			//printf("%s", buffer);
			write(pty, buffer, strlen(buffer));
		}
	}

	memset(buffer, 0, MAX_BUFSIZE);

	while (ret = read(pty, buffer, MAX_BUFSIZE - 1))
	{
		buffer[ret - 1] = 0; //read是读不到字符串结束符的,需要自己添加,否则printf会出错
		if (ret <= 0)
		{
			break;
		}
		fflush(stdout);//这步很重要,std中经常有数据滞留在存储区中需要此函数刷新
		printf("%s", buffer);//打印出结果
		send(sockfd, buffer, strlen(buffer), 0);
		memset(buffer, 0, MAX_BUFSIZE);
	}
	return;
}

int main(int argc, char **argv)
{
	struct sockaddr_in addr;
	int sock_fd, addrlen;

	/* 获得程序工作的参数,如 IP 、端口、监听数、网页根目录、目录存放位置等 */
	getoption(argc, argv);

	if (!host)
	{
		addrlen = strlen(DEFAULTIP);
		AllocateMemory(&host, addrlen, DEFAULTIP);
	}
	if (!port)
	{
		addrlen = strlen(DEFAULTPORT);
		AllocateMemory(&port, addrlen, DEFAULTPORT);
	}
	if (!back)
	{
		addrlen = strlen(DEFAULTBACK);
		AllocateMemory(&back, addrlen, DEFAULTBACK);
	}
	if (!dirroot)
	{
		addrlen = strlen(DEFAULTDIR);
		AllocateMemory(&dirroot, addrlen, DEFAULTDIR);
	}
	if (!logdir)
	{
		addrlen = strlen(DEFAULTLOG);
		AllocateMemory(&logdir, addrlen, DEFAULTLOG);
	}

	/* fork() 两次处于后台工作模式下 */
	if (daemon_y_n)
	{
		if (fork())
			exit(0);
		if (fork())
			exit(0);
		close(0), close(1), close(2);
		logfp = fopen(logdir, "a+");
		if (!logfp)
			exit(0);
	}

	/* 处理子进程退出以免产生僵尸进程 */
	signal(SIGCHLD, SIG_IGN);

	/* 创建 socket */
	if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		if (!daemon_y_n)
		{
			prterrmsg("socket()");
		}
		else
		{
			wrterrmsg("socket()");
		}
	}

	/* 设置端口快速重用 */
	addrlen = 1;

	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(port));
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addrlen = sizeof(struct sockaddr_in);

	setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));
	/* 绑定地址、端口等信息 */
	if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0)
	{
		if (!daemon_y_n)
		{
			prterrmsg("bind()");
		}
		else
		{
			wrterrmsg("bind()");
		}
	}

	/* 开启临听 */
	if (listen(sock_fd, atoi(back)) < 0)
	{
		if (!daemon_y_n)
		{
			prterrmsg("listen()");
		}
		else
		{
			wrterrmsg("listen()");
		}
	}

	printf("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n",
			host, port, back, dirroot, logdir, daemon_y_n ? "" : "不", getpid());

	while (1)
	{
		int new_fd;
		addrlen = sizeof(struct sockaddr_in);
		/* 接受新连接请求 */
		new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen);
		if (new_fd < 0)
		{
			if (!daemon_y_n)
			{
				prterrmsg("accept()");
			}
			else
			{
				wrterrmsg("accept()");
			}
			break;
		}
		bzero(buffer, MAXBUF + 1);
		sprintf(buffer, "连接来自于: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(
				addr.sin_port));
		if (!daemon_y_n)
		{
			prtinfomsg(buffer);
		}
		else
		{
			wrtinfomsg(buffer);
		}
		/* 产生一个子进程去处理请求,当前进程继续等待新的连接到来 */
		if (!fork())
		{
			int ret, ptrfdm;
			char slave_name[PTY_NAME_SIZE];
			struct termios slave_termiors;
			struct winsize slave_winsize;
			pid_t ppid;

			ret = -1;
			ptrfdm = -1;
			memset(slave_name, 0, PTY_NAME_SIZE);
			ppid = -1;

			ret = pty_fork(&ptrfdm, slave_name, PTY_NAME_SIZE, &slave_termiors,
					&slave_winsize, &ppid);

			if (ret < 0)
			{
				printf("pty_fork err ! ret = %d", ret);
				return -1;
			}

			if (ppid < 0)
			{
				printf("pty_fork err !");
				return -1;
			}
			else if (ppid == 0)
			{
				execl("/bin/bash", "bash", NULL);
			}
			else
			{
				read_write_pty(ptrfdm, new_fd);

			}
		}
		close(new_fd);
	}
	close(sock_fd);
	return 0;
}



 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值