#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
typedefstructthread_arg
{
intpty;
intsockfd;
} thread_arg;
voidprterrmsg(char*msg);
#define prterrmsg(msg) { perror(msg); abort(); }
voidwrterrmsg(char*msg);
#define wrterrmsg(msg) { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }
voidprtinfomsg(char*msg);
#define prtinfomsg(msg) { fputs(msg, stdout); }
voidwrtinfomsg(char*msg);
#define wrtinfomsg(msg) { fputs(msg, logfp); fflush(logfp);}
#define MAXBUF 1024
charbuffer[MAXBUF + 1];
char*host = 0;
char*port = 0;
char*back = 0;
char*dirroot = 0;
char*logdir = 0;
unsignedchardaemon_y_n = 0;
FILE*logfp;
#define MAXPATH 150
/*------------------------------------------------------
*--- AllocateMemory - 分配空间并把d所指的内容复制
*------------------------------------------------------
*/
voidAllocateMemory(char**s,intl,char*d)
{
*s = malloc(l + 1);
bzero(*s, l + 1);
memcpy(*s, d, l);
}
/*------------------------------------------------------
*--- getoption - 分析取出程序的参数
*------------------------------------------------------
*/
voidgetoption(intargc,char**argv)
{
intc, len;
char*p = 0;
opterr = 0;
while(1)
{
intoption_index = 0;
staticstructoption 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);
elseif((!c && !(strcasecmp(long_options[option_index].name,"port")))
|| c =='P')
p = port = malloc(len + 1);
elseif((!c && !(strcasecmp(long_options[option_index].name,"back")))
|| c =='B')
p = back = malloc(len + 1);
elseif((!c && !(strcasecmp(long_options[option_index].name,"dir")))
|| c =='D')
p = dirroot = malloc(len + 1);
elseif((!c && !(strcasecmp(long_options[option_index].name,"log")))
|| c =='L')
p = logdir = malloc(len + 1);
elseif((!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)
{
intret, sockfd, pty;
charbuffer[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
{
continue;
}
printf("%s", buffer);
write(pty, buffer, strlen(buffer));
}
}
voidread_write_pty(intpty,intsockfd)
{
charbuffer[MAX_BUFSIZE];
intret;
// 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())
{
perror("");
exit(1);
}
elseif(pid == 0)
{
while(1)
{
memset(buffer, 0, MAX_BUFSIZE);
ret = recv(sockfd, buffer, MAX_BUFSIZE - 1, 0);
if(ret
{
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;
}
intmain(intargc,char**argv)
{
structsockaddr_in addr;
intsock_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))
{
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(structsockaddr_in);
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen,sizeof(addrlen));
/* 绑定地址、端口等信息 */
if(bind(sock_fd, (structsockaddr *) &addr, addrlen)
{
if(!daemon_y_n)
{
prterrmsg("bind()");
}
else
{
wrterrmsg("bind()");
}
}
/* 开启临听 */
if(listen(sock_fd, atoi(back))
{
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)
{
intnew_fd;
addrlen =sizeof(structsockaddr_in);
/* 接受新连接请求 */
new_fd = accept(sock_fd, (structsockaddr *) &addr, &addrlen);
if(new_fd
{
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())
{
intret, ptrfdm;
charslave_name[PTY_NAME_SIZE];
structtermios slave_termiors;
structwinsize 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
{
printf("pty_fork err ! ret = %d", ret);
return-1;
}
if(ppid
{
printf("pty_fork err !");
return-1;
}
elseif(ppid == 0)
{
execl("/bin/bash","bash", NULL);
}
else
{
read_write_pty(ptrfdm, new_fd);
}
}
close(new_fd);
}
close(sock_fd);
return0;
}