MiniFtp
一.项目介绍
FTP就是文件传输协议。用于互联网双向传输,控制文件下载空间在服务器复制文件从本地计算机或本 地上传文件复制到服务器上的空间,miniftp实现了FTP传输的主要功能,简洁高效;
二.环境配置
1.下载vsptpd工具:
yum install vsftpd -y
2.启动vsftpd
systemctl status vsftpd //查看状态
systemctl start vsftpd //打开工具
systemctl stop vsftpd
systemctl restart vsftpd
在/ect/vsftpd/vsftpd.conf 修改配置文件
3.配置Windows下的Editplus
chmod 给予相关文件权限
三.系统框架
1.创建common.h模块
#ifndef _COMMON_H_
#define _COMMON_H
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinnet/in.h>
#include<arpa/inet.h>
#define ERR_EXIT(m) \
do{\
prror(m);/
exit(EXIT_FAILURE);/
}while(0)
#endif
2.创建系统调用模块
#include"sysutil"
int tcp_server(const char* host ,unsigned short port)
{
int listenfd;
listenfd = socket(AF_INET,SOCK_STRERAM,0);//创建套接字,参数分别为IPV4协议版本,字节流数据报,协议类型
if(listenfd < 0)
ERR_EXIT("tcp_server);
struct sockaddr_in addrSer;//套接字参数,服务器地址信息
addrSer.sin_family = AF_INET;服务器地址域IPV4
addrSer.sin_port = htons(port);服务器端口号
addrSer,sin_addr.s_addt = inet_addr(host);服务器IP地址
int on = 1;
if(setsockopt(listenfd,SOL_REUSEADDR , &on,sizeof(on)))//设置socket属性
ERR_EXIT("setsockopt");
if(bind(listenfd,(struct sockaddr*)&addrSer,sizeof(addrSer)) < 0)
ERR_EXIT("bind");//绑定套接字
if(listen(listenfd,SOMAXCONN) < 0)//开始监听,参数为linten操作句柄和接收队列
ERR_EXIT("listen");
return listenfd;
}
///
int tcp_client()
{
int sock;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
ERR_EXIT("tcp_client");
if(port > 0)
{
int on = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)//设置系统绑定
ERR_EXIT("setsockopt");
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if(bind(sock, (struct sockaddr*)&address, sizeof(struct sockaddr)) < 0)
ERR_EXIT("bind 20");
}
return sock;
}
const char* statbuf_get_perms(struct stat *sbuf)
{
//- --- --- ---
static char perms[] = "----------";
mode_t mode = sbuf->st_mode;
switch(mode & S_IFMT)
{
case S_IFSOCK:
perms[0] = 's';
break;
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFREG:
perms[0] = '-';
break;
case S_IFBLK:
perms[0] = 'b';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFIFO:
perms[0] = 'p';
break;
}
if(mode & S_IRUSR)
perms[1] = 'r';
if(mode & S_IWUSR)
perms[2] = 'w';
if(mode & S_IXUSR)
perms[3] = 'x';
if(mode & S_IRGRP)
perms[4] = 'r';
if(mode & S_IWGRP)
perms[5] = 'w';
if(mode & S_IXGRP)
perms[6] = 'x';
if(mode & S_IROTH)
perms[7] = 'r';
if(mode & S_IWOTH)
perms[8] = 'w';
if(mode & S_IXOTH)
perms[9] = 'x';
return perms;
}
const char* statbuf_get_date(struct stat *sbuf)
{
static char datebuf[64] = {0};
time_t file_time = sbuf->st_mtime;
struct tm *ptm = localtime(&file_time);
strftime(datebuf, 64, "%b %e %H:%M", ptm);
return datebuf;
}
void send_fd(int sock_fd, int fd)//发送操作描述符
{
int ret;
struct msghdr msg;
struct cmsghdr *p_cmsg;
struct iovec vec;
char cmsgbuf[CMSG_SPACE(sizeof(fd))];
int *p_fds;
char sendchar = 0;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
p_cmsg = CMSG_FIRSTHDR(&msg);
p_cmsg->cmsg_level = SOL_SOCKET;
p_cmsg->cmsg_type = SCM_RIGHTS;
p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
p_fds = (int*)CMSG_DATA(p_cmsg);
*p_fds = fd;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
vec.iov_base = &sendchar;
vec.iov_len = sizeof(sendchar);
ret = sendmsg(sock_fd, &msg, 0);
if (ret != 1)
ERR_EXIT("sendmsg");
}
int recv_fd(const int sock_fd)//接收操作描述符
{
int ret;
struct msghdr msg;
char recvchar;
struct iovec vec;
int recv_fd;
char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
struct cmsghdr *p_cmsg;
int *p_fd;
vec.iov_base = &recvchar;
vec.iov_len = sizeof(recvchar);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = 0;
p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
*p_fd = -1;
ret = recvmsg(sock_fd, &msg, 0);
if (ret != 1)
ERR_EXIT("recvmsg");
p_cmsg = CMSG_FIRSTHDR(&msg);
if (p_cmsg == NULL)
ERR_EXIT("no passed fd");
p_fd = (int*)CMSG_DATA(p_cmsg);
recv_fd = *p_fd;
if (recv_fd == -1)
ERR_EXIT("no passed fd");
return recv_fd;
}
3.创建会话session模块
#include"session.h"
void begin_session(session_t *sess)
{
//初始化父子进程通讯通道
priv_sock_init(sess);
pid_t pid = fork();
if(pid == -1)
ERR_EXIT("fork");
if(pid == 0)
{
//ftp 服务进程
priv_sock_set_child_context(sess);
handle_child(sess);
}
else
{
//nobody 进程
priv_sock_set_parent_context(sess);
//把root进程更改进程名为nobody
struct passwd *pw = getpwnam("nobody");
if(pw == NULL)
ERR_EXIT("getpwname");
if(setegid(pw->pw_gid) < 0)
ERR_EXIT("setegid");
if(seteuid(pw->pw_uid) < 0)
ERR_EXIT("seteuid");
handle_parent(sess);
}
}
4.创建服务进程模块
#include"ftpproto.h"
#include"ftpcodes.h"
#include"str.h"
void ftp_reply(session_t *sess, int code, const char *text)
{
char buf[MAX_BUFFER_SIZE] = {0};
sprintf(buf, "%d %s\r\n", code, text);
send(sess->ctrl_fd, buf, strlen(buf), 0);
}//回复命令
/
//命令映射机制
//操作函数
static void do_user(session_t *sess);
static void do_pass(session_t *sess);
static void do_syst(session_t *sess);
static void do_feat(session_t *sess);//回复内容服务器功能
static void do_pwd (session_t *sess);//显示当前目录
static void do_type(session_t *sess);
static void do_port(session_t *sess);
static void do_list(session_t *sess);
typedef struct ftpcmd
{
const char *cmd;
void(*cmd_handler)(session_t *sess);
}ftpcmd_t;//回应结构体
//命令映射表
static ftpcmd_t ctrl_cmds[] =
{
{"USER", do_user},
{"PASS", do_pass},
{"SYST", do_syst},
{"FEAT", do_feat},
{"PWD", do_pwd },
{"TYPE", do_type},
{"PORT", do_port},
{"LIST", do_list}
};
/
//ftp 服务进程
void handle_child(session_t *sess)
{
ftp_reply(sess, FTP_GREET, "(bit65 miniftp 1.0 )");
int ret;
while(1)
{
//不停的等待客户端的命令并进行处理
memset(sess->cmdline, 0, MAX_COMMAND_LINE);
memset(sess->cmd, 0, MAX_COMMAND);
memset(sess->arg, 0, MAX_ARG);
ret = recv(sess->ctrl_fd, sess->cmdline, MAX_COMMAND_LINE, 0);//回复命令
if(ret == -1)
ERR_EXIT("readline");
else if(ret == 0)
exit(EXIT_SUCCESS);
str_trim_crlf(sess->cmdline);
//printf("cmdline = %s\n", sess->cmdline);
str_split(sess->cmdline, sess->cmd, sess->arg, ' ');
//printf("cmd = %s\n", sess->cmd);
//printf("arg = %s\n", sess->arg);
int table_size = sizeof(ctrl_cmds) / sizeof(ftpcmd_t);
int i;
for(i=0; i<table_size; ++i)//遍历寻找命令对应函数
{
if(strcmp(sess->cmd, ctrl_cmds[i].cmd) == 0)
{
if(ctrl_cmds[i].cmd_handler != NULL)
ctrl_cmds[i].cmd_handler(sess);
else
ftp_reply(sess, FTP_COMMANDNOTIMPL, "Unimplement command.");
break;
}
}
if(i >= table_size)//没有找到
ftp_reply(sess, FTP_BADCMD, "Unknown command.");
}
}
//USER abc
static void do_user(session_t *sess)
{
struct passwd *pwd = getpwnam(sess->arg);
if(pwd != NULL)
sess->uid = pwd->pw_uid;
ftp_reply(sess, FTP_GIVEPWORD, "Please specify the password.");
}//do_user函数回复内容
//PASS 123abc
static void do_pass(session_t *sess)
{
//鉴权
struct passwd *pwd = getpwuid(sess->uid);
if(pwd == NULL)
{
ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
return;
}
struct spwd *spd = getspnam(pwd->pw_name);
if(spd == NULL)
{
ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
return;
}
char *encry_pwd = crypt(sess->arg, spd->sp_pwdp);
if(strcmp(encry_pwd, spd->sp_pwdp) != 0)
{
ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
return;
}
setegid(pwd->pw_gid);
seteuid(pwd->pw_uid);
chdir(pwd->pw_dir);
ftp_reply(sess, FTP_LOGINOK, "Login successful.");
}
static void do_syst(session_t *sess)
{
ftp_reply(sess, FTP_SYSTOK, "UNIX Type: L8");
}
static void do_feat(session_t *sess)//do_feat回复内容服务器功能
{
send(sess->ctrl_fd, "211-Features:\r\n" ,strlen("211-Features:\r\n"), 0);
send(sess->ctrl_fd, " EPRT\r\n", strlen(" EPRT\r\n"), 0);
send(sess->ctrl_fd, " EPSV\r\n", strlen(" EPSV\r\n"), 0);
send(sess->ctrl_fd, " MDTM\r\n", strlen(" MDTM\r\n"), 0);
send(sess->ctrl_fd, " PASV\r\n", strlen(" PASV\r\n"), 0);
send(sess->ctrl_fd, " REST STREAM\r\n", strlen(" REST STREAM\r\n"), 0);
send(sess->ctrl_fd, " SIZE\r\n", strlen(" SIZE\r\n"), 0);
send(sess->ctrl_fd, " TVFS\r\n", strlen(" TVFS\r\n"), 0);
send(sess->ctrl_fd, " UTF8\r\n", strlen(" UTF8\r\n"), 0);
send(sess->ctrl_fd, "211 End\r\n", strlen("211 End\r\n"), 0);
}
static void do_pwd (session_t *sess)//显示当前目录
{
char buffer[MAX_BUFFER_SIZE] = {0};
getcwd(buffer, MAX_BUFFER_SIZE); // 获取工作目录
char msg[MAX_BUFFER_SIZE] = {0};
sprintf(msg, "\"%s\"", buffer); //给内容加上“”
ftp_reply(sess, FTP_PWDOK, msg);
}
static void do_type(session_t *sess)//传输方式
{
//TYPE A or TYPE I
if(strcmp(sess->arg, "A") == 0)//ASCII码模式
{
sess->is_ascii = 1;
ftp_reply(sess, FTP_TYPEOK, "Switching to ASCII mode.");
}
else if(strcmp(sess->arg, "I") == 0)//二进制模式
{
sess->is_ascii = 0;
ftp_reply(sess, FTP_TYPEOK, "Switching to Binary mode.");
}
else//不制持
ftp_reply(sess, FTP_BADCMD, "Unrecognised TYPE command.");
}
static void do_port(session_t *sess)//发送IP地址及端口号
{
//PORT 192,168,232,1,7,34
unsigned int v[6] = {0};
sscanf(sess->arg, "%u,%u,%u,%u,%u,%u", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5]);
sess->port_addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
unsigned char *p = (unsigned char *)&sess->port_addr->sin_port;//端口号映射
p[0] = v[4];
p[1] = v[5];
p = (unsigned char *)&sess->port_addr->sin_addr;//IP地址映射
p[0] = v[0];
p[1] = v[1];
p[2] = v[2];
p[3] = v[3];
sess->port_addr->sin_family = AF_INET;//地址域IPV4
ftp_reply(sess, FTP_PORTOK, "command successful. Consider using PASV.");//发送成功消息
}
static void do_pasv(session_t *sess)
{
// 227 Entering Passive Mode (192,168,232,10,140,176).
char ip[16] = "192.168.232.10"; //服务器的IP
sess->pasv_listen_fd = tcp_server(ip, 0);//port为0代表生成临时端口号
struct sockaddr_in address;
socklen_t addrlen = sizeof(struct sockaddr);
if(getsockname(sess->pasv_listen_fd, (struct sockaddr*)&address, &addrlen) < 0)//获取套接字信息
ERR_EXIT("getsockname");
unsigned short port = ntohs(address.sin_port);//字节序转化
int v[4] = {0};
sscanf(ip, "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]);//将字符串格式化
char msg[MAX_BUFFER_SIZE] = {0};
sprintf(msg, "Entering Passive Mode (%u,%u,%u,%u,%u,%u).", v[0],v[1],v[2],v[3], port>>8, port&0x00ff);//输出格式>>取高八位,&x00ff取低八位
ftp_reply(sess, FTP_PASVOK, msg);
}
int port_active(session_t *sess)//判断port模式是否被激活
{
if(sess->port_addr)
return 1;
return 0;
}
int pasv_active(session_t *sess)//判断pasv模式是否激活
{
if(sess->pasv_listen_fd != -1)
return 1;
return 0;
}
int get_port_fd(session_t *sess)
{
int ret = 1;
//ftp 向 nobody 发起通讯
priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_GET_DATA_SOCK);//向对方进程发送指令
unsigned short port = ntohs(sess->port_addr->sin_port);//端口号
char *ip = inet_ntoa(sess->port_addr->sin_addr);//IP地址
//发送port端口号及ip地址
priv_sock_send_int(sess->child_fd, (int)port);
priv_sock_send_buf(sess->child_fd, ip, strlen(ip));
char res = priv_sock_get_result(sess->child_fd);
if(res == PRIV_SOCK_RESULT_BAD)
ret = 0;
else if(res == PRIV_SOCK_RESULT_OK)//连接成功返回数据连接操作句柄
sess->data_fd = priv_sock_recv_fd(sess->child_fd);
return ret;
}
int get_pasv_fd(session_t *sess)
{
int ret = 1;
priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_PASV_ACCEPT);//发送连接命令
char res = priv_sock_get_result(sess->child_fd);
if(res == PRIV_SOCK_RESULT_BAD)
ret = 0;
else if(res == PRIV_SOCK_RESULT_OK)
sess->data_fd = priv_sock_recv_fd(sess->child_fd);
return ret;
}
int get_transfer_fd(session_t *sess)//建立连接
{
if(!port_active(sess) && !pasv_active(sess))
{
ftp_reply(sess, FTP_BADSENDCONN,"Use PORT or PASV first.");
return 0;
}
int ret = 1;
//port
if(port_active(sess))
{
if(!get_port_fd(sess))
ret = 0;
}
//pasv
if(pasv_active(sess))
{
if(!get_pasv_fd(sess))
ret = 0;
}
if(sess->port_addr)
{
free(sess->port_addr);
sess->port_addr = NULL;
}
return ret;
}
static void list_common(session_t *sess)//列表显示
{
DIR *dir = opendir(".");//打开当前目录
if(dir == NULL)
return;
//drwxr-xr-x 3 1000 1000 30 Sep 09 2019 Desktop
char buf[MAX_BUFFER_SIZE] = {0};
struct stat sbuf; //用于保存文件的属性
struct dirent *dt;
while((dt = readdir(dir)) != NULL)
{
if(stat(dt->d_name, &sbuf) < 0)
continue;
if(dt->d_name[0] == '.') //过滤掉隐藏文件
continue;
memset(buf, MAX_BUFFER_SIZE, 0);
//先组合权限
const char *perms = statbuf_get_perms(&sbuf); //drwxr-xr-x
int offset = 0;
offset += sprintf(buf, "%s", perms);
offset += sprintf(buf+offset, "%3d %-8d %-8d %8u", sbuf.st_nlink, sbuf.st_uid, sbuf.st_gid, sbuf.st_size);
//后组合时间日期
const char *pdate = statbuf_get_date(&sbuf); //Sep 09 2019
offset += sprintf(buf+offset, "%s", pdate);
sprintf(buf+offset, "%s\r\n", dt->d_name);
//发送数据
send(sess->data_fd, buf, strlen(buf), 0);
}
}
static void do_list(session_t *sess)
{
//1 建立数据连接
if(get_transfer_fd(sess) == 0)//主动和被动连接
return;
//2 回复 150
ftp_reply(sess, FTP_DATACONN ,"Here comes the directory listing.");
//3 显示列表
list_common(sess);
//4 关闭连接
close(sess->data_fd);
sess->data_fd = -1;
//5 回复 226
ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK.");
}
5.创建nobody进程模块:
#include"privparent.h"
#include"privsock.h"
#include"session.h"
//获取主动模式数据连接套接字
static void privop_pasv_get_data_sock(session_t *sess);
//判断是否处于被动模式的激活状态
static void privop_pasv_active(session_t *sess);
//获取被动模式下的监听端口
static void privop_pasv_listen(session_t *sess);
//获取被动模式下的数据连接套接字
static void privop_pasv_accept(session_t *sess);
//提升权限
static void minimize_privilege()
{
//把root进程更改进程名为nobody
struct passwd *pw = getpwnam("nobody");
if(pw == NULL)
ERR_EXIT("getpwname");
if(setegid(pw->pw_gid) < 0)
ERR_EXIT("setegid");
if(seteuid(pw->pw_uid) < 0)
ERR_EXIT("seteuid");
struct __user_cap_header_struct cap_header;
struct __user_cap_data_struct cap_data;
memset(&cap_header, 0, sizeof(cap_header));
memset(&cap_data, 0, sizeof(cap_data));
cap_header.version = _LINUX_CAPABILITY_VERSION_2;
cap_header.pid = 0;//代表是root进程
unsigned int cap_mask = 0;
cap_mask |= (1 << CAP_NET_BIND_SERVICE); //0000 0000 0000 0000 0001 0000 0100 0000
cap_data.effective = cap_data.permitted = cap_mask;
cap_data.inheritable = 0; // 不继承之前权限
capset(&cap_header, &cap_data);//用于设置权限能力
}
//nobody 进程
void handle_parent(session_t *sess)
{
minimize_privilege();//提升权限
char cmd;
while(1)
{
//不停的等待ftp进程的命令
cmd = priv_sock_get_cmd(sess->parent_fd);
switch(cmd)
{
case PRIV_SOCK_GET_DATA_SOCK:
privop_pasv_get_data_sock(sess);
break;
case PRIV_SOCK_PASV_ACTIVE:
privop_pasv_active(sess);
break;
case PRIV_SOCK_PASV_LISTEN:
privop_pasv_listen(sess);
break;
case PRIV_SOCK_PASV_ACCEPT:
privop_pasv_accept(sess);
break;
}
}
}
static void privop_pasv_get_data_sock(session_t *sess)
{
unsigned short port = (unsigned short)priv_sock_get_int(sess->parent_fd);
char ip[16] = {0};
priv_sock_recv_buf(sess->parent_fd, ip, sizeof(ip));
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = inet_addr(ip);
int fd = tcp_client(20); //绑定20端口
if(fd == -1)
{
priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
return;
}
if(connect(fd, (struct sockaddr*)&address, sizeof(address)) < 0)
{
close(fd);
priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
return;
}
priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK);
priv_sock_send_fd(sess->parent_fd, fd);
close(fd);
}
static void privop_pasv_active(session_t *sess)
{
int active;
if(sess->pasv_listen_fd != -1)
active = 1;
else
active = 0;
priv_sock_send_int(sess->parent_fd, active);
}
static void privop_pasv_listen(session_t *sess)
{
char *ip = "192.168.232.10"; //暂且写死
sess->pasv_listen_fd = tcp_server(ip, 0); //传端口0表示绑定临时端口
struct sockaddr_in address;
socklen_t addrlen = sizeof(struct sockaddr);
if(getsockname(sess->pasv_listen_fd, (struct sockaddr*)&address, &addrlen) < 0)
ERR_EXIT("getsockname");
unsigned short port = ntohs(address.sin_port);
priv_sock_send_int(sess->parent_fd, (int)port);
}
static void privop_pasv_accept(session_t *sess)
{
int fd = accept(sess->pasv_listen_fd, 0, 0);
close(sess->pasv_listen_fd);
sess->pasv_listen_fd = -1;
if(fd == -1)
{
priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
return;
}
priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK);
priv_sock_send_fd(sess->parent_fd, fd);
close(fd);
}
6.主进程模块
#include"common.h"
#include"sysutil.h"
#include"session.h"
int main()
{
session_t sess =
{
-1;//控制连接
};
int listenfd = tcp_server("192.168.219.131",8080);//开始监听
int sockConn;
struct sockaddr_in addrCli;
socklen_t sddrlen;
while(1)
{
if(sockConn = accpet(listenfd,(struct sockaddr*)&addrCli, &addrlen) < 0)//接收连接参数为客户端地址信息,客户端地址长度
ERR_EXIT("accpet");
pid_t pid = fork();//创建进程
if(pid == -1)//创建失败
ERR_EXIT("fork");
if(pid == 0)
{
close(listenfd);
//创建会话
sess.ctrl_fd = sockConn;//控制连接
begin_session(&sess);
exit(EXIT_SUCCESS);
//子进程
}
else
{
close(sockConn);//父进程
}
}
close(listenfd);
return 0;
}
//
7.创建markfile
8.创建字符操作模块str
#include"str.h"
void str_trim_crlf(char *str)
{
assert(str != NULL);
char *p = str + (strlen(str)-1);
while(*p=='\n' || *p=='\r')
*p-- = '\0';
}//替换\r\n字符
void str_split(const char *str, char *left, char *right, char c)
{
assert(str != NULL);
char *pos = strchr(str, c);
if(pos == NULL)
strcpy(left, str);
else
{
strncpy(left, str, pos-str);
strcpy(right, pos+1);
}
}//字符串分割
9.创建进程通信privsock.h
#include"privsock.h"
#include"sysutil.h"
void priv_sock_init(session_t *sess)//初始化
{
int sockfds[2];
if(socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds) < 0)//建立一个双向的传输方式
ERR_EXIT("socketpair");
sess->child_fd = sockfds[1];
sess->parent_fd = sockfds[0];
}
void priv_sock_close(session_t *sess)//关闭传输接口
{
if(sess->parent_fd != -1)
{
close(sess->parent_fd);
sess->parent_fd = -1;
}
if(sess->child_fd != -1)
{
close(sess->child_fd);
sess->child_fd = -1;
}
}
void priv_sock_set_parent_context(session_t *sess)
{
if(sess->child_fd != -1)
{
close(sess->child_fd);
sess->child_fd = -1;
}
}
void priv_sock_set_child_context(session_t *sess)
{
if(sess->parent_fd != -1)
{
close(sess->parent_fd);
sess->parent_fd = -1;
}
}
void priv_sock_send_cmd(int fd, char cmd)//发送命令
{
int ret = send(fd, &cmd, sizeof(cmd), 0);
if(ret != sizeof(cmd))
ERR_EXIT("priv_sock_send_cmd error.");
}
char priv_sock_get_cmd(int fd)//接收命令
{
char cmd;
int ret;
ret = recv(fd, &cmd, sizeof(cmd), 0);
if(ret == 0)
{
printf("ftp process exit.\n");
exit(EXIT_SUCCESS);
}
if(ret != sizeof(cmd))
ERR_EXIT("priv_sock_get_cmd error.");
return cmd;
}
void priv_sock_send_result(int fd, char res)//发送处理结果
{
int ret = send(fd, &res, sizeof(res), 0);
if(ret != sizeof(res))
ERR_EXIT("priv_sock_send_result error.");
}
char priv_sock_get_result(int fd)//接收处理结果
{
char res;
int ret;
ret = recv(fd, &res, sizeof(res), 0);
if(ret == 0)
{
printf("ftp process exit.\n");
exit(EXIT_SUCCESS);
}
if(ret != sizeof(res))
ERR_EXIT("priv_sock_get_result error.");
return res;
}
void priv_sock_send_int(int fd, int the_int)//发送整型数据
{
int ret = send(fd, &the_int, sizeof(the_int), 0);
if(ret != sizeof(the_int))
ERR_EXIT("priv_sock_send_int error.");
}
int priv_sock_get_int(int fd)//接收整型数据
{
int res;
int ret;
ret = recv(fd, &res, sizeof(res), 0);
if(ret == 0)
{
printf("ftp process exit.\n");
exit(EXIT_SUCCESS);
}
if(ret != sizeof(res))
ERR_EXIT("priv_sock_get_int error.");
return res;
}
void priv_sock_send_buf(int fd, const char *buf, unsigned int len)//发送字符串类型
{
priv_sock_send_int(fd, len);
int ret = send(fd, buf, len, 0);
if(ret != len)
ERR_EXIT("priv_sock_send_buf error.");
}
void priv_sock_recv_buf(int fd, char *buf, unsigned int len)//接收字符串类型
{
unsigned int recv_len = priv_sock_get_int(fd);
int ret = recv(fd, buf, recv_len, 0);
if(ret != recv_len)//判断接收长度是否一直
ERR_EXIT("priv_sock_recv_buf error.");
}
void priv_sock_send_fd(int sock_fd, int fd)
{
send_fd(sock_fd, fd);
}
int priv_sock_recv_fd(int sock_fd)
{
return recv_fd(sock_fd);
}