代码仅供参考,如用于正式项目,根据实际添加并发处理代码。代码使用的libevent库和使用的CMakeLists.txt文件参考本系列博客前面的篇章。
简介
在本次测试中实现的命令:
CWD:切换到指定的目录
USER:登录用户
CDUP:回到上一层目录
PORT:主动传输方式
LIST:获取目录列表
RETR:请求服务器想客户端发送指定文件
STOR:客户端向服务器上传指定文件
这些命令的参数在下面的表格中都有详细说明。
表10-1 常用的FTP访问控制命令
表10-2 传输参数命令
表10-3 常用的服务命令
表10-4 不同应答码的含义
根据表10-4中对应答码含义的规定,表10-5按照功能划分列举了常用的FTP应答码并介绍了其具体含义。
表10-5 常用的FTP应答码及其含义说明 文章来源:https://www.toymoban.com/news/detail-578115.html
测试代码
#include <sys/types.h>
#include <event2/event-config.h>
#include <event2/listener.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
,__FILE__,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
#define _DEBUG_PRINT
#ifdef _DEBUG_PRINT
#define DEBUG_PRINT(format,...) printf(format,##__VA_ARGS__)
#else
#define DEBUG_PRINT(format,...)
#endif
//sudo ip addr add 192.168.0.12/24 dev ens33
//添加新的IP地址用于测试
struct private_base_data{
struct event_base *base;
struct evconnlistener *control_listener;
struct sockaddr_in control_server_addr;
int current_user_count;
};
struct private_client_data{
struct private_base_data* pbd;
struct bufferevent *bev;
int client_socket;
char buf[4096 + 1];
int len;
char remote_ips[20];
int remote_port;
struct bufferevent *list_bev;
char root_dir[1024];
char current_dir[1024];
struct bufferevent *stor_bev;
FILE *stor_fp;
struct bufferevent *retr_bev;
FILE *retr_fp;
};
void event_cb(struct bufferevent *bev, short what, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
);
if(bev != pcd->list_bev){
DEBUG_INFO("listbev error");
}
if(what & BEV_EVENT_EOF){
bufferevent_free(bev);
pcd->list_bev = NULL;
}else if(what == BEV_EVENT_CONNECTED){
DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
}else
{
bufferevent_free(bev);
pcd->list_bev = NULL;
}
}
void write_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("write_cb");
if(bev != pcd->list_bev){
DEBUG_INFO("pcd->remote_host error");
}
//bufferevent_write(pcd->remote_host, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
if(bev == pcd->list_bev){
DEBUG_INFO("list close");
write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
bufferevent_free(pcd->list_bev);
pcd->list_bev = NULL;
return;
}
DEBUG_INFO("bev error");
return;
}
void read_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
int len;
DEBUG_INFO("readcb %d",pcd->client_socket);
if(bev == pcd->stor_bev && pcd->stor_fp != NULL){
while (1) {
len = bufferevent_read(bev, pcd->buf, sizeof(pcd->buf) - 1);
if (len <= 0) {
return;
}
pcd->buf[pcd->len] = '\0';
fwrite(pcd->buf, 1, len, pcd->stor_fp);
}
return;
}
pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
pcd->buf[pcd->len] = '\0';
DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);
return;
}
void stor_event_cb(struct bufferevent *bev, short what, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
);
if(bev != pcd->stor_bev){
DEBUG_INFO("bev error");
}
if(what & BEV_EVENT_EOF){
bufferevent_free(bev);
write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
pcd->stor_bev = NULL;
if(pcd->stor_fp != NULL){
DEBUG_INFO("close file");
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
}else if(what == BEV_EVENT_CONNECTED){
DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
}else
{
DEBUG_INFO("uknown error");
bufferevent_free(bev);
write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
pcd->stor_bev = NULL;
if(pcd->stor_fp != NULL){
DEBUG_INFO("close file");
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
}
}
void stor_write_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("write_cb");
if(bev != pcd->stor_bev){
DEBUG_INFO("pcd->remote_host error");
}
//bufferevent_write(pcd->remote_host, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
if(bev == pcd->stor_bev){
DEBUG_INFO("stor write");
write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
bufferevent_free(pcd->stor_bev);
pcd->stor_bev = NULL;
if(pcd->stor_fp != NULL){
DEBUG_INFO("close file");
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
return;
}
DEBUG_INFO("bev error");
bufferevent_free(bev);
return;
}
void stor_read_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
int len;
DEBUG_INFO("readcb %d",pcd->client_socket);
char *buf = NULL;
if(bev == pcd->stor_bev && pcd->stor_fp != NULL){
buf = malloc(1024);
while (1) {
len = bufferevent_read(bev, buf, 1024);
if (len <= 0) {
free(buf);
return;
}
buf[len] = '\0';
DEBUG_INFO("buf = %s",buf);
fwrite(buf, 1, len, pcd->stor_fp);
}
free(buf);
return;
}else{
if(pcd->stor_bev != NULL){
bufferevent_free(pcd->stor_bev);
pcd->stor_bev = NULL;
}
if(pcd->stor_fp != NULL){
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
}
return;
}
void retr_event_cb(struct bufferevent *bev, short what, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
);
if(bev != pcd->retr_bev){
DEBUG_INFO("bev error");
}
if(what == BEV_EVENT_CONNECTED){
DEBUG_INFO("连接 %s:%d成功",pcd->remote_ips,pcd->remote_port);
return;
}
//if(what & BEV_EVENT_EOF)
{
bufferevent_free(pcd->retr_bev);
//write(pcd->client_socket, "226 Transfer comlete\r\n", sizeof("226 Transfer comlete\r\n"));
pcd->retr_bev = NULL;
if(pcd->retr_fp != NULL){
DEBUG_INFO("close retr file");
fclose(pcd->retr_fp);
pcd->retr_fp = NULL;
}
}
}
void retr_write_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
int len = 0;
char *buf = NULL;
int send_len = 0;
if(bev == pcd->retr_bev){
DEBUG_INFO("retr write");
if(pcd->retr_fp == NULL){
DEBUG_INFO("file is not open");
return;
}
buf = malloc(1024 + 1);
do{
len = fread(buf, 1, 1024, pcd->retr_fp);
if (len <= 0) {
DEBUG_INFO("retr read finish");
//bufferevent_flush(pcd->retr_bev,EV_WRITE,BEV_FLUSH);
// bufferevent_free(pcd->retr_bev);
// pcd->retr_bev = NULL;
// fclose(pcd->retr_fp);
// pcd->retr_fp = NULL;
free(buf);
write(pcd->client_socket, "226 Transfer comlete", sizeof("226 Transfer comlete"));
return;
}
send_len += len;
buf[len] = '\0';
DEBUG_INFO("buf = %s,len = %d", buf, len);
DEBUG_INFO("send_len = %d", send_len);
bufferevent_write(pcd->retr_bev, buf, len);
}while(1);
free(buf);
}
DEBUG_INFO("bev error");
bufferevent_free(bev);
return;
}
void retr_read_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("readcb %d",pcd->client_socket);
pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
pcd->buf[pcd->len] = '\0';
DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);
return;
}
struct bufferevent * connect_to_remote_port(struct private_client_data *pcd,int type){
struct sockaddr_in sin;
struct bufferevent *bev;
if(type == 0){//list
if(pcd->list_bev != NULL){
bufferevent_free(pcd->list_bev);
pcd->list_bev = NULL;
}
}else if(type == 1){//stor
if(pcd->stor_bev != NULL){
bufferevent_free(pcd->stor_bev);
pcd->stor_bev = NULL;
}
}else if(type == 2){
if(pcd->retr_bev != NULL){
bufferevent_free(pcd->retr_bev);
pcd->retr_bev = NULL;
}
}else{
DEBUG_INFO("unknown type %d",type);
exit(0);
}
bev = bufferevent_socket_new(pcd->pbd->base,
-1, BEV_OPT_CLOSE_ON_FREE);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(pcd->remote_port);
evutil_inet_pton(AF_INET, pcd->remote_ips, &sin.sin_addr.s_addr);
if(type == 0){
DEBUG_INFO("list");
bufferevent_setcb(bev, read_cb, write_cb, event_cb, pcd);
bufferevent_enable(bev, EV_READ | EV_WRITE);
}else if(type == 1){
DEBUG_INFO("stor");
bufferevent_setcb(bev, stor_read_cb, stor_write_cb, stor_event_cb, pcd);
bufferevent_enable(bev, EV_READ | EV_WRITE);
}else if(type == 2){
DEBUG_INFO("retr");
bufferevent_setcb(bev, retr_read_cb, retr_write_cb, retr_event_cb, pcd);
bufferevent_enable(bev, EV_READ|EV_WRITE);
}else{
bufferevent_free(bev);
DEBUG_INFO("unknown type %d",type);
exit(0);
}
struct timeval t = {1, 0};
bufferevent_set_timeouts(bev, &t, 0);
bufferevent_socket_connect(bev, (struct sockaddr*)&sin, sizeof(sin));
DEBUG_INFO("connected to %s:%d finish",pcd->remote_ips,pcd->remote_port);
if(type == 0){
//list
pcd->list_bev = bev;
}else if(type == 1){
//stor
pcd->stor_bev = bev;
}else if(type == 2){
//retr
pcd->retr_bev = bev;
}else{
bev = NULL;
DEBUG_INFO("error");
DEBUG_INFO("unknown type %d",type);
exit(0);
}
return bev;
}
char * get_list_data(char* _path,int *_datasize) {
char* _cmd = "ls -l ";
char cmd[1024] = "ls -l ";
char *pnew;
int current_len = 0;
int len;
int size = 1024*1024;
char* buf ;
snprintf(cmd,1024,"%s%s",_cmd,_path);
DEBUG_INFO("cmd = %s",cmd);
FILE *f = popen(cmd, "r");
if (!f){
return NULL;
}
buf = malloc(size + 2);
while (1) {
len = fread(&buf[current_len], 1, size - 1 - current_len, f);
if (len <= 0){
break;
}
current_len += len;
buf[current_len] = '\0';
if(current_len >= size - 1){
pnew = realloc(buf,current_len+size);
if(pnew != NULL){
size += current_len;
buf = pnew;
}else{
DEBUG_INFO("realloc fail");
break;
}
}
}
pclose(f);
buf[current_len] = '\r';
buf[current_len + 1] = '\n';
*_datasize = current_len + 2;
return buf;
}
void client_read_bufferevent_data_cb(struct bufferevent *bev, void *ctx){
// char *pret;
int i = 0;
int nums[20];
int index = 0;
int temp = 0;
char* path = NULL;
int path_len = 0;
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("readcb %d",pcd->client_socket);
pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
pcd->buf[pcd->len] = '\0';
DEBUG_INFO("pcd->len = %d,pcd->buf = %s",pcd->len,pcd->buf);
if(pcd->len == 0){
return;
}
if(pcd->buf[0] == 'U'){
if(strncmp(&pcd->buf[0],"USER",4) == 0){
DEBUG_INFO("user name = %s",&pcd->buf[5]);
write(pcd->client_socket,"230 Login successsful.\r\n",sizeof("230 Login successsful.\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'F'){
if(strncmp(&pcd->buf[0],"FEAT",4) == 0){
DEBUG_INFO("FEAT = %s",&pcd->buf[5]);
//write(pcd->client_socket,"230 Login successsful.\r\n",sizeof("230 Login successsful.\r\n"));
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'P'){
if(strncmp(&pcd->buf[0],"PORT",4) == 0){
DEBUG_INFO("PORT = %s",&pcd->buf[5]);
//获取IP地址和端口号
for (i = 5; i < pcd->len; i++) {
if (pcd->buf[i] == ',' || pcd->buf[i] == '\r') {
nums[index] = temp;
index++;
temp = 0;
continue;
}
temp = (pcd->buf[i] - 0x30) + temp*10;
}
for(i = 0; i < index;i++){
printf("%d,",nums[i]);
}
printf("\n");
if (index != 6) {
write(pcd->client_socket,("501 Syntax error in parameters or arguments."),
sizeof("501 Syntax error in parameters or arguments."));
return;
}
memset(pcd->remote_ips,0,sizeof(pcd->remote_ips));
snprintf(pcd->remote_ips,sizeof(pcd->remote_ips),"%d.%d.%d.%d",nums[0],nums[1],nums[2],nums[3]);
pcd->remote_port = ((uint16_t)nums[4] << 8) + (uint16_t)nums[5];
DEBUG_INFO("ips = %s,port = %d",pcd->remote_ips,pcd->remote_port);
write(pcd->client_socket,"200 PORT command success.\r\n",sizeof("200 PORT command success.\r\n"));
return;
}
if(strncmp(&pcd->buf[0],"PASS",4) == 0){
DEBUG_INFO("PORT = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
if(strncmp(&pcd->buf[0],"PWD",3) == 0){
DEBUG_INFO("PWD = %s",&pcd->buf[4]);
DEBUG_INFO("pcd->current_dir = %s ",pcd->current_dir);
if(strlen(pcd->current_dir) == 1){
write(pcd->client_socket,"257 \"/\" is current dir.\r\n",sizeof("230 Login successsful.\r\n"));
return;
}
path_len = 100 + strlen(pcd->current_dir);
path = malloc(100 + strlen(pcd->current_dir));
snprintf(path,path_len,"257 \"%s/\" is current dir.\r\n",pcd->current_dir);
// write(pcd->client_socket,"257 \"/\" is current dir.\r\n",sizeof("230 Login successsful.\r\n"));
write(pcd->client_socket,path,strlen(path));
DEBUG_INFO("path = %s",path);
free(path);
return;
}
if(strncmp(&pcd->buf[0],"PASV",4) == 0){
DEBUG_INFO("PASV = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'L'){
if(strncmp(&pcd->buf[0],"LIST",4) == 0){
DEBUG_INFO("LIST = %s",&pcd->buf[5]);
connect_to_remote_port(pcd,0);
path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + 1;
path = malloc(path_len);
snprintf(path,path_len,"%s%s",pcd->root_dir,pcd->current_dir);
path[path_len] = '\0';
DEBUG_INFO("path = %s",path);
int datasize;
char* listdata = get_list_data(path,&datasize);
free(path);
char *pret = "150 Here coms the directory listing.\r\n";
write(pcd->client_socket,pret,strlen(pret));
DEBUG_INFO("datasize = %d",datasize);
if(pcd->list_bev == NULL){
DEBUG_INFO("remote host not connected");
}
// bufferevent_write(pcd->remote_host,
// "150 Here coms the directory listing.\r\n",
// sizeof("150 Here coms the directory listing.\r\n"));
DEBUG_INFO("listdata = %s",listdata);
if(datasize > 0 && listdata != NULL){
int ret = bufferevent_write(pcd->list_bev, listdata, datasize);
DEBUG_INFO("ret = %d,datasize = %d",ret,datasize);
}
if(listdata != NULL){
free(listdata);
}
DEBUG_INFO("process LIST finish");
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'C'){
if(strncmp(&pcd->buf[0],"CWD",3) == 0){
DEBUG_INFO("CWD = %s",&pcd->buf[4]);
path_len = strlen(&pcd->buf[4]);
path = malloc(path_len + 1);
memset(path,0,path_len);
memcpy(path,&pcd->buf[4],path_len);
path[path_len] = '\0';
while(1){
if(path_len == 0){
break;
}
if(path[path_len - 1] == '\r' || path[path_len - 1] == '\n' || path[path_len - 1] == '\0'){
path[path_len - 1] = '\0';
path_len--;
}else{
break;
}
}
DEBUG_INFO("path: %s", path);
if(path_len > 0){
memcpy(pcd->current_dir,path,path_len);
pcd->current_dir[path_len] = '\0';
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
}else{
write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
}
free(path);
return;
}
if(strncmp(&pcd->buf[0],"CDUP",4) == 0){
DEBUG_INFO("CDUP = %s",&pcd->buf[5]);
path_len = strlen(pcd->current_dir);
while(path_len > 1){
if(pcd->current_dir[path_len - 1] != '/'){
pcd->current_dir[path_len - 1] = '\0';
path_len--;
}else{
pcd->current_dir[path_len - 1] = '\0';
path_len--;
break;
}
}
DEBUG_INFO("pcd->current_dir = %s",pcd->current_dir);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'D'){
if(strncmp(&pcd->buf[0],"DELE",4) == 0){
DEBUG_INFO("DELE = %s",&pcd->buf[4]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'M'){
if(strncmp(&pcd->buf[0],"MKD",3) == 0){
DEBUG_INFO("MKD = %s",&pcd->buf[4]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'R'){
if(strncmp(&pcd->buf[0],"RMD",3) == 0){
DEBUG_INFO("RMD = %s",&pcd->buf[4]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
if(strncmp(&pcd->buf[0],"RETR",4) == 0){
DEBUG_INFO("RETR = %s",&pcd->buf[5]);
path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + strlen(&pcd->buf[5]);
path = malloc(path_len);
memset(path,0,path_len);
snprintf(path,path_len,"%s%s/%s",pcd->root_dir,pcd->current_dir,&pcd->buf[5]);
path[path_len] = '\0';
do{
if(path_len == 0){
break;
}
if(path[path_len - 1] == 0x0a || path[path_len - 1] == 0x0d || path[path_len - 1] == 0){
path[path_len - 1] = '\0';
path_len--;
}else{
DEBUG_INFO("path[%d]=%02x",path_len,path[path_len - 1]);
break;
}
}while(1);
DEBUG_INFO("path = %s",path);
for(i = 0;i < path_len;i++){
printf("%02x,",path[i]);
}
printf("\n");
if(pcd->retr_fp != NULL){
fclose(pcd->retr_fp);
pcd->retr_fp = NULL;
}
pcd->retr_fp = fopen(path,"r");
if(pcd->retr_fp != NULL){
DEBUG_INFO("open %s ok\r\n",path);
connect_to_remote_port(pcd,2);
write(pcd->client_socket,"150 File OK.\r\n",strlen("150 File OK.\r\n"));
char*buf = malloc(4096);
while(1){
int read_len = fread(buf,1,4096,pcd->retr_fp);
if(read_len <= 0){
break;
}
bufferevent_write(pcd->retr_bev,buf,read_len);
}
write(pcd->client_socket,"226 Transfer complete\r\n",sizeof("226 Transfer complete\r\n"));
//bufferevent_trigger(pcd->retr_bev, EV_WRITE, 0);
free(buf);
}else{
DEBUG_INFO("open %s error\r\n",path);
write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
}
free(path);
if(pcd->retr_bev == NULL){
DEBUG_INFO("retr_bev remote host not connected");
}
DEBUG_INFO("process RETR finish");
return;
}
if(strncmp(&pcd->buf[0],"REST",4) == 0){
DEBUG_INFO("REST = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'S'){
if(strncmp(&pcd->buf[0],"SIZE",4) == 0){
DEBUG_INFO("SIZE = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
if(strncmp(&pcd->buf[0],"STOR",4) == 0){
DEBUG_INFO("STOR = %s",&pcd->buf[5]);
path_len = strlen(pcd->root_dir) + strlen(pcd->current_dir) + strlen(&pcd->buf[5]);
path = malloc(path_len + 1);
snprintf(path,path_len,"%s%s/%s",pcd->root_dir,pcd->current_dir,&pcd->buf[5]);
path[path_len] = '\0';
do{
if(path_len == 0){
break;
}
if(path[path_len - 1] == 0x0a || path[path_len - 1] == 0x0d || path[path_len - 1] == 0){
path[path_len - 1] = '\0';
path_len--;
}else{
DEBUG_INFO("path[%d]=%02x",path_len,path[path_len - 1]);
break;
}
}while(1);
DEBUG_INFO("path = %s",path);
for(i = 0;i < path_len;i++){
printf("%02x,",path[i]);
}
printf("\n");
if(pcd->stor_fp != NULL){
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
pcd->stor_fp = fopen(path,"wb");
if(pcd->stor_fp){
connect_to_remote_port(pcd,1);
write(pcd->client_socket,"125 File OK.\r\n",strlen("125 File OK.\r\n"));
bufferevent_trigger(pcd->stor_bev, EV_READ, 0);
}else{
write(pcd->client_socket,"450 file open failed!\r\n",strlen("450 file open failed!\r\n"));
}
free(path);
if(pcd->stor_bev == NULL){
DEBUG_INFO("remote host not connected");
}
DEBUG_INFO("process STOR finish");
return;
}
if(strncmp(&pcd->buf[0],"SYST",4) == 0){
DEBUG_INFO("SYST = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
if(pcd->buf[0] == 'T'){
if(strncmp(&pcd->buf[0],"TYPE",4) == 0){
DEBUG_INFO("TYPE = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
}
if(pcd->buf[0] == 'Q'){
if(strncmp(&pcd->buf[0],"QUIT",4) == 0){
DEBUG_INFO("QUIT = %s",&pcd->buf[5]);
write(pcd->client_socket,"200 OK\r\n",strlen("200 OK\r\n"));
return;
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
DEBUG_INFO("unkown %c",pcd->buf[0]);exit(0);
}
void client_event_bufferevent_event_cb(struct bufferevent *bev, short what, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
);
pcd->pbd->current_user_count--;
if(what & BEV_EVENT_EOF){
close(pcd->client_socket);
bufferevent_free(bev);
if(pcd->list_bev != NULL){
bufferevent_free(pcd->list_bev);
pcd->list_bev = NULL;
}
if(pcd->stor_bev != NULL){
bufferevent_free(pcd->stor_bev);
pcd->stor_bev = NULL;
}
if(pcd->retr_bev != NULL){
bufferevent_free(pcd->retr_bev);
pcd->retr_bev = NULL;
}
if(pcd->stor_fp != NULL){
fclose(pcd->stor_fp);
pcd->stor_fp = NULL;
}
if(pcd->retr_fp != NULL){
fclose(pcd->retr_fp);
pcd->retr_fp = NULL;
}
free(pcd);
}else{
DEBUG_INFO("未知错误");
//即便是未知错误,也关闭连接并释放资源比较好吧
close(pcd->client_socket);
bufferevent_free(bev);
free(pcd);
}
}
void server_evconnlistener_cb(struct evconnlistener *listener, evutil_socket_t new_client, struct sockaddr *addr, int socklen, void *arg){
int options = 0;
struct private_base_data *pbd = (struct private_base_data*)arg;
struct sockaddr_in *paddr = (struct sockaddr_in *)addr;
DEBUG_INFO("a new client fd = %d",new_client);
DEBUG_INFO("ip = %s,port = %d",inet_ntoa(paddr->sin_addr),ntohs(paddr->sin_port));
options |= BEV_OPT_CLOSE_ON_FREE;
struct bufferevent *bev = bufferevent_socket_new(pbd->base,new_client, options);
if(bev == NULL){
DEBUG_INFO("bufferevent_socket_new error");
exit(-1);
}
pbd->current_user_count++;
struct private_client_data * pcd = (struct private_client_data*)malloc(sizeof(struct private_client_data));
memset(pcd, 0, sizeof(struct private_client_data));
pcd->root_dir[0]='.';
pcd->current_dir[0]='/';
pcd->client_socket = new_client;
pcd->pbd = pbd;
pcd->list_bev = NULL;
write(new_client,"220 Welcome to XFtpServer\r\n",sizeof("220 Welcome to XFtpServer\r\n"));
bufferevent_setcb(bev,
client_read_bufferevent_data_cb,
NULL,
client_event_bufferevent_event_cb,
pcd);
bufferevent_enable(bev,EV_READ);
}
int main(int argc, char **argv)
{
struct private_base_data *pbd = (struct private_base_data*)malloc(sizeof(struct private_base_data));
if(pbd == NULL){
DEBUG_INFO("malloc error");
return 0;
}
pbd->current_user_count = 0;
pbd->control_server_addr.sin_family = AF_INET;
pbd->control_server_addr.sin_addr.s_addr = INADDR_ANY;
// pbd->control_server_addr.sin_addr.s_addr = inet_addr("192.168.0.12");
pbd->control_server_addr.sin_port = htons(6021);
pbd->base = event_base_new();
if(pbd->base == NULL){
DEBUG_INFO("event_base_new error");
return 0;
}
pbd->control_listener = evconnlistener_new_bind(
pbd->base,
server_evconnlistener_cb,
pbd,
LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
5,
(struct sockaddr*)&pbd->control_server_addr,
sizeof(pbd->control_server_addr));
if(pbd->control_listener == NULL){
DEBUG_INFO("evconnlistener_new_bind error");
return 0;
}
event_base_dispatch(pbd->base);
evconnlistener_free(pbd->control_listener);
event_base_free(pbd->base);
free(pbd);
DEBUG_INFO("bye bye");
return 0;
}
测试
文章来源地址https://www.toymoban.com/news/detail-578115.html
小结
到了这里,关于libevent实践11:主动模式的FTP服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!