Miniftp Project Learning Notes Packaging Parameter Configuration Module

Posted by meir4u on Fri, 16 Aug 2019 15:37:01 +0200

Links to the original text: https://www.cnblogs.com/webor2006/p/4509729.html

Last time, we encapsulated the string tool module. This time, we mainly encapsulated the parameter configuration module. There are many configuration-related options in FTP. It is impossible to hard-code them into the code. Instead, we should configure them into the configuration file, such as the configuration file of vsftpd as follows:

 

For miniftpd, all the parameter configurations are as follows:

 

The above variables should correspond to the corresponding configuration items one by one, so three tables need to be defined to correspond one by one:

Table of Correspondence Relations between Configuration Items and Configuration Item Variables in Configuration Files

static struct parseconf_bool_setting

{

  const char *p_setting_name;

  int *p_variable;

}

parseconf_bool_array[] =

{

       { "pasv_enable", &tunable_pasv_enable },

       { "port_enable", &tunable_port_enable },

       { NULL, NULL }

};

 

static struct parseconf_uint_setting

{

       const char *p_setting_name;

       unsigned int *p_variable;

}

parseconf_uint_array[] =

{

       { "listen_port", &tunable_listen_port },

       { "max_clients", &tunable_max_clients },

       { "max_per_ip", &tunable_max_per_ip },

       { "accept_timeout", &tunable_accept_timeout },

       { "connect_timeout", &tunable_connect_timeout },

       { "idle_session_timeout", &tunable_idle_session_timeout },

       { "data_connection_timeout", &tunable_data_connection_timeout },

       { "local_umask", &tunable_local_umask },

       { "upload_max_rate", &tunable_upload_max_rate },

       { "download_max_rate", &tunable_download_max_rate },

       { NULL, NULL }

};

static struct parseconf_str_setting

{

       const char *p_setting_name;

       const char **p_variable;

}

parseconf_str_array[] =

{

       { "listen_address", &tunable_listen_address },

{NULL, NULL}// The last NULL is for traversal purposes

};

The following defines two functions that operate on the configuration file:

function

Explain

void parseconf_load_file(const char *path);

Loading configuration files

void parseconf_load_setting(const char *setting);

Loading configuration items to corresponding variables

First, create a new configuration file module text:

tunable.h: Declare its variables:

//Configuration File Module
#ifndef _TUNABLE_H_
#define _TUNABLE_H_

extern int tunable_pasv_enable;
extern int tunable_port_enable;
extern unsigned int tunable_listen_port;
extern unsigned int tunable_max_clients;
extern unsigned int tunable_max_per_ip;
extern unsigned int tunable_accept_timeout;
extern unsigned int tunable_connect_timeout;
extern unsigned int tunable_idle_session_timeout;
extern unsigned int tunable_data_connection_timeout;
extern unsigned int tunable_local_umask;
extern unsigned int tunable_upload_max_rate;
extern unsigned int tunable_download_max_rate;
extern const char *tunable_listen_address;


#endif /* _TUNABLE_H_ */

 tunable.c:

//Configuration File Module
#include "tunable.h"

int tunable_pasv_enable = 1;	//Whether to turn on passive mode
int tunable_port_enable = 1;	//Whether to turn on active mode
unsigned int tunable_listen_port = 21;	//FTP Server Port
unsigned int tunable_max_clients = 2000;	//maximum connection
unsigned int tunable_max_per_ip = 50;	//Maximum number of connections per ip
unsigned int tunable_accept_timeout = 60;	//Accept timeout
unsigned int tunable_connect_timeout = 60;	//Connect timeout
unsigned int tunable_idle_session_timeout = 300;	//Control connection timeout
unsigned int tunable_data_connection_timeout = 300;	//Data connection timeout
unsigned int tunable_local_umask = 077;	//Mask
unsigned int tunable_upload_max_rate = 0;	//Maximum upload speed
unsigned int tunable_download_max_rate = 0;	//Maximum download speed
const char *tunable_listen_address;	//FTP Server IP Address

In addition, create a new configuration file:

 

Next, two interfaces are exposed to parse files and configuration items:

function

Explain

void parseconf_load_file(const char *path);

Loading configuration files

void parseconf_load_setting(const char *setting);

Loading configuration items to corresponding variables

Create a new parsing module to do the above parsing work:

parseconf.h:

//Resolution of files and configuration items

#ifndef _PARSECONF_H_
#define _PARSECONF_H_

void parseconf_load_file(const char *path);
void parseconf_load_setting(const char *setting);

#endif /* _PARSE_CONF_H_ */

 parseconf.c:

#include "parseconf.h"
#include "common.h"
#include "tunable.h"

void parseconf_load_file(const char *path){
    
}

void parseconf_load_setting(const char *setting){
    
}

The following two functions are implemented:

 

In addition, since a line of characters read by the fgets function contains'\ n', it needs to be removed, using the existing method we encapsulated before:

 

 

Next, we implement the parsing function of the command line. Before formal parsing, we need to define the relationship table between the configuration item and the configuration item variable in the configuration file with code, as follows:

#include "parseconf.h"
#include "common.h"
#include "tunable.h"

static struct parseconf_bool_setting
{
  const char *p_setting_name;
  int *p_variable;
}
parseconf_bool_array[] =
{
    { "pasv_enable", &tunable_pasv_enable },
    { "port_enable", &tunable_port_enable },
    { NULL, NULL }
};

static struct parseconf_uint_setting
{
    const char *p_setting_name;
    unsigned int *p_variable;
}
parseconf_uint_array[] =
{
    { "listen_port", &tunable_listen_port },
    { "max_clients", &tunable_max_clients },
    { "max_per_ip", &tunable_max_per_ip },
    { "accept_timeout", &tunable_accept_timeout },
    { "connect_timeout", &tunable_connect_timeout },
    { "idle_session_timeout", &tunable_idle_session_timeout },
    { "data_connection_timeout", &tunable_data_connection_timeout },
    { "local_umask", &tunable_local_umask },
    { "upload_max_rate", &tunable_upload_max_rate },
    { "download_max_rate", &tunable_download_max_rate },
    { NULL, NULL }
};

static struct parseconf_str_setting
{
    const char *p_setting_name;
    const char **p_variable;
}
parseconf_str_array[] =
{
    { "listen_address", &tunable_listen_address },
    { NULL, NULL }
};

void parseconf_load_file(const char *path){
    FILE *fp = fopen(path, "r");
    if (fp == NULL)
        ERR_EXIT("fopen");

    char setting_line[1024] = {0};
    while (fgets(setting_line, sizeof(setting_line), fp) != NULL)
    {
        if (strlen(setting_line) == 0
            || setting_line[0] == '#'
            || str_all_space(setting_line))
            continue;

        str_trim_crlf(setting_line);
        parseconf_load_setting(setting_line);
        memset(setting_line, 0, sizeof(setting_line));
    }

    fclose(fp);
}

void parseconf_load_setting(const char *setting){
    
}

 

Each variable is from the global variable tunable.c.

It can be seen that there are three types of parameters, the following one for parsing. For a configuration of "pasv_enable=YES", it may be written as "pasv_enable=YES", so first remove the left grids:

Then you need to separate key=pasv_enable; value=YES, where you can use the previously encapsulated ready-made commands:

 

But it is also possible that the user does not configure value, such as "pasv_enable=", so this is illegal and should be judged:

Next, you need to search for the key in the configuration table variable above, and if you find it, assign its value to the configuration variable as follows:

 

If it is not found, it means that the current configuration item is not a string type, at this time, we have to continue to search for other types of configuration items, as follows:

 

For Boolean types, there are several forms:

AA=YES

AA=yes

AA=TRUE

AA=1

So, first of all, value is capitalized:

When the boolean type configuration item is not found, it needs to be searched in unsigned shaping. Among them, unsigned shaping has two forms: one is octal, starting with 0, such as "local_umask=077"; the other is decimal, such as "listen_port=21", so it needs to be judged. The code is basically similar:

 

The following is to compile and run. Before compiling and running, you need to add new modules to Makefile:

 

 

 

 

See above has passed normally, that still can not see whether these configuration information is read properly, so the next need to write a test program to verify:

 

Compile and run:

 

 

Compile and run again:

 

Next, you can apply some configuration items:

 

Compile and run:

 

Connect with FTP client:

 

So the code becomes configurable, and the file name of the configuration file can be macro:

 

The macro is used directly when loading:

 

 

 

Topics: ftp vsftpd Makefile