代码拉取完成,页面将自动刷新
同步操作将从 wang/miniftpd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#include "common.h"
#include "sysutil.h"
#include "session.h"
#include "str.h"
#include "tunable.h"
#include "parseconf.h"
#include "ftpproto.h"
#include "ftpcodes.h"
#include "hash.h"
/*
typedef struct session
{
// 控制连接
char cmdline[MAX_COMMAND_LINE];
char cmd[MAX_COMMAND];
char arg[MAX_ARG];
// 父子进程通道
int parent_fd;
int child_fd;
} session_t;
*/
extern session_t *p_sess;
static unsigned int s_children; //子进程数目
static hash_t *s_ip_count_hash;
static hash_t *s_pid_ip_hash;
void check_limits(session_t *sess);
void handle_sigchld(int sig);
unsigned int hash_func(unsigned int buckets, void *key);
unsigned int handle_ip_count(void *ip);
void drop_ip_count(void *ip);
int main(void)
{
//获取指定网卡地址
/*
char ip[16];
get_local_ip(eth, ip);
printf("local %s ip: %s\n", eth, ip);
*/
/*
list_common();
exit(EXIT_SUCCESS);
*/
// 字符串测试
/*
char *str1 = " a b";
char *str2 = " ";
if (str_all_space(str1))
printf("str1 all space\n");
else
printf("str1 not all space\n");
if (str_all_space(str2))
printf("str2 all space\n");
else
printf("str2 not all space\n");
//char *str3 = "abcDef"; // 指针指向一个字符串常量,常量不能被修改
char str3[] = "abcDef";
str_upper(str3);
printf("str3=%s\n", str3);
long long result = str_to_longlong("12345678901234");
printf("result = %lld\n", result);
int n = str_octal_to_uint("711");
printf("n=%d\n", n);
*/
parseconf_load_file(MINIFTP_CONF);
/*必须放到LoadFile的后面---守候进程*/
daemon(0, 0); //后台工作
printf("tunable_pasv_enable=%d\n", tunable_pasv_enable);
printf("tunable_port_enable=%d\n", tunable_port_enable);
printf("tunable_listen_port=%u\n", tunable_listen_port);
printf("tunable_max_clients=%u\n", tunable_max_clients);
printf("tunable_max_per_ip=%u\n", tunable_max_per_ip);
printf("tunable_accept_timeout=%u\n", tunable_accept_timeout);
printf("tunable_connect_timeout=%u\n", tunable_connect_timeout);
printf("tunable_idle_session_timeout=%u\n", tunable_idle_session_timeout);
printf("tunable_data_connection_timeout=%u\n", tunable_data_connection_timeout);
printf("tunable_local_umask=0%o\n", tunable_local_umask);
printf("tunable_upload_max_rate=%u\n", tunable_upload_max_rate);
printf("tunable_download_max_rate=%u\n", tunable_download_max_rate);
if (tunable_listen_address == NULL)
printf("tunable_listen_address=NULL\n");
else
printf("tunable_listen_address=%s\n", tunable_listen_address);
/*必须用root用户启动,sudo ./miniftpd start*/
if (getuid() != 0)
{
fprintf(stderr, "miniftpd: must be started as root\n");
exit(EXIT_FAILURE);
}
/*添加时候更新这段注释--防止初始化时候出错*/
/*
typedef struct session
{
// 控制连接
uid_t uid;
int ctrl_fd;
char cmdline[MAX_COMMAND_LINE];
char cmd[MAX_COMMAND];
char arg[MAX_ARG];
// 数据连接
struct sockaddr_in *port_addr;
int pasv_listen_fd;
int data_fd;
int data_process;
// 限速
unsigned int bw_upload_rate_max;
unsigned int bw_download_rate_max;
long bw_transfer_start_sec;
long bw_transfer_start_usec;
// 父子进程通道
int parent_fd;
int child_fd;
// FTP协议状态
int is_ascii;
long long restart_pos;
char *rnfr_name;
int abor_received;
// 连接数限制
unsigned int num_clients;
unsigned int num_this_ip;
} session_t;
*/
/*初始化session,一个会话两个进程*/
session_t sess =
{
/* 控制连接 */
0, -1, "", "", "",
/* 数据连接 */
NULL, -1, -1, 0,
/* 限速 */
0, 0, 0, 0,
/* 父子进程通道 */
-1, -1,
/* FTP协议状态 */
0, 0, NULL, 0,
/* 连接数限制 */
0, 0
};
p_sess = &sess;
sess.bw_upload_rate_max = tunable_upload_max_rate;
sess.bw_download_rate_max = tunable_download_max_rate;
s_ip_count_hash = hash_alloc(256, hash_func); //地址与连接数
s_pid_ip_hash = hash_alloc(256, hash_func); //进程与ip
signal(SIGCHLD, handle_sigchld);
int listenfd = tcp_server(tunable_listen_address, tunable_listen_port); //启动一个服务器(创建一个套接字(接口))
int conn;
pid_t pid;
struct sockaddr_in addr;
while (1)
{
conn = accept_timeout(listenfd, &addr, 0); //接受客户端的连接(生成一个新的套接字conn)
if (conn == -1) //判断连接是否成功 没有成功conn就会等于-1
ERR_EXIT("accept_tinmeout");
unsigned int ip = addr.sin_addr.s_addr;
++s_children; //连接成功,创建一个子进程
sess.num_clients = s_children; //设置当前连接数
sess.num_this_ip = handle_ip_count(&ip);
pid = fork(); //获得连接/连接成功后 创建一个进程
if (pid == -1)
{
--s_children;
ERR_EXIT("fork");
}
if (pid == 0) //若为子进程就川建一个会话
{
close(listenfd);
sess.ctrl_fd = conn;
check_limits(&sess);
signal(SIGCHLD, SIG_IGN);
begin_session(&sess); //启动一个会话
}
else //若不是子进程就关闭套接字
{
hash_add_entry(s_pid_ip_hash, &pid, sizeof(pid),
&ip, sizeof(unsigned int));
close(conn);
}
}
return 0;
}
void check_limits(session_t *sess)
{
if (tunable_max_clients > 0 && sess->num_clients > tunable_max_clients)
{
ftp_reply(sess, FTP_TOO_MANY_USERS,
"There are too many connected users, please try later.");
exit(EXIT_FAILURE); //会发送过来的一个信号 -- 子进程向父进程发送一个信号
}
if (tunable_max_per_ip > 0 && sess->num_this_ip > tunable_max_per_ip)
{
ftp_reply(sess, FTP_IP_LIMIT,
"There are too many connections from your internet address.");
exit(EXIT_FAILURE); //会发送过来的一个信号 -- 子进程向父进程发送一个信号
}
}
void handle_sigchld(int sig) //父进程的信号处理程序
{
// 当一个客户端退出的时候,那么该客户端对应ip的连接数要减1,
// 处理过程是这样的,首先是客户端退出的时候,
// 父进程需要知道这个客户端的ip,这可以通过在s_pid_ip_hash查找得到,
pid_t pid;
while ((pid = waitpid(-1, NULL, WNOHANG)) > 0)
/*
当正常返回的时候,waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
*/
{
--s_children;
unsigned int *ip = hash_lookup_entry(s_pid_ip_hash, &pid, sizeof(pid));
if (ip == NULL)
{
continue;
}
drop_ip_count(ip);
hash_free_entry(s_pid_ip_hash, &pid, sizeof(pid));
}
}
unsigned int hash_func(unsigned int buckets, void *key)
{
unsigned int *number = (unsigned int*)key;
return (*number) % buckets; //返回一个哈希地址--pid存放的哈希地址
}
unsigned int handle_ip_count(void *ip)
{
// 当一个客户登录的时候,要在s_ip_count_hash更新这个表中的对应表项,
// 即该ip对应的连接数要加1,如果这个表项还不存在,要在表中添加一条记录,
// 并且将ip对应的连接数置1。
unsigned int count;
unsigned int *p_count = (unsigned int *)hash_lookup_entry(s_ip_count_hash,
ip, sizeof(unsigned int));
if (p_count == NULL)
{
count = 1;
hash_add_entry(s_ip_count_hash, ip, sizeof(unsigned int),
&count, sizeof(unsigned int));
}
else
{
count = *p_count;
++count;
*p_count = count;
}
return count;
}
void drop_ip_count(void *ip)
{
// 得到了ip进而我们就可以在s_ip_count_hash表中找到对应的连接数,进而进行减1操作。
unsigned int count;
unsigned int *p_count = (unsigned int *)hash_lookup_entry(s_ip_count_hash,
ip, sizeof(unsigned int));
if (p_count == NULL)
{
return;
}
count = *p_count;
if (count <= 0)
{
return;
}
--count;
*p_count = count;
if (count == 0)
{
hash_free_entry(s_ip_count_hash, ip, sizeof(unsigned int));
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。