[Ruixin micro Rockchip Linux platform] SoftAp requirements implementation process code implementation

Posted by Kaylub on Wed, 19 Jan 2022 09:59:04 +0100

Recently, the upper layer has a requirement to start the SoftAp hotspot. If all the implementation processes are recorded.

Link to this article:< [Ruixin micro Rockchip Linux platform] SoftAp requirements implementation (1) process code implementation>

Links to this series of articles:

  1. <[Ruixin micro Rockchip Linux platform] SoftAp requirements implementation (1) process code implementation>
  2. Implementation of SoftAp requirements of [Ruixin micro Rockchip Linux platform] (2) modify SSID and password according to transmission parameters

1, SoftAp start command

In fact, these can be achieved by using commands,

  1. The open command is as follows:
    iw phy0 interface add wlan1 type managed
    ifconfig wlan1 up
    ifconfig wlan1 192.168.50.1 netmask 255.255.255.0
    route add default gw 192.168.50.1 wlan1
    dnsmasq -C /data/bin/dnsmasq_softap.conf --interface=wlan1
    hostapd /data/bin/hostapd.conf -t -B

  2. The closing command is as follows:
    kill -15 dnsmasq
    kill -15 hostapd
    route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1
    ifconfig wlan1 down
    iw dev wlan1 del

  3. Other command configuration


2, SoftAp start command encapsulation implementation process

According to the requirements of the upper layer, encapsulate these commands into libraries and executable programs.
For this requirement, I choose to package it into executable program.

2.1 add system time before log

It mainly uses macro control to rewrite the printf function, so that get will be called before printing each log sentence_ cur_ Time gets the current system time, accurate to ms.

#include <time.h>

static char *get_cur_time(void){
	static char s[50]={0};
	char s_ms[10]={0};
	time_t t;
	struct tm *ltime;
	struct timeval tv; 
	
	time(&t);
	ltime = localtime(&t);
	gettimeofday(&tv,NULL);  //tv.tv_sec * 1000 + tv.tv_usec / 1000;  
	
	strftime(s, 50, "%Y-%m-%d %H:%M:%S", ltime);
	sprintf(s_ms, ".%03d", tv.tv_usec / 1000);
	strcat(s, s_ms);
	
	return s;
}

#define printf_t(fmt, ...) printf("[%s][Dongle_Soft_ap] "fmt, get_cur_time(), ##__VA_ARGS__)

2.2 check whether the process is running process_is_alive()

This is relatively simple. It mainly counts the number of processes through ps -A | grep dnsmasq | wc -l. if the number is greater than 1, it indicates that the current process is running.
This function returns the number of processes running.

int process_is_alive(const char *process)
{
	FILE *fp = NULL;
	int pid = 0;
	char buff_tmp[100]={0};

	sprintf(buff_tmp, "ps -A | grep %s | wc -l", process);
	fp = popen(buff_tmp, "r");
	if(fp){
		memset(buff_tmp, 0, 100);
		fgets(buff_tmp, sizeof(buff_tmp)-1, fp);
		pclose(fp);
		if(buff_tmp != NULL){
			pid = atoi(buff_tmp);
			return pid;
		}
	}	
	return -1;
}

2.3 kill process_ process()

Get the output information of the command through popen to parse the process number of the process, and then kill it.
Generally speaking, it is recommended to use kill -15 to kill the process. It will wait for the process to release relevant resources, which is not easy to solve the problem of resource leakage.

void kill_process(const char *process, int level)
{
	FILE *fp = NULL;
	int pid = 0;
	char buff_tmp[100]={0}, *p_buff=NULL, *p_buff1=NULL;

	sprintf(buff_tmp, "ps -A | grep %s", process);

	fp = popen(buff_tmp, "r");
	if(fp){
		memset(buff_tmp, 0, 100);
		while(fgets(buff_tmp, sizeof(buff_tmp)-1, fp) >0){
			p_buff = buff_tmp;
			while(p_buff!=NULL && *p_buff!='\0' && *p_buff==' ') p_buff++;
			p_buff1 = p_buff;
			while(p_buff1!=NULL && *p_buff1!='\0' && *p_buff1!=' ') p_buff1++;
			*p_buff1 = '\0';
			pid = atoi(p_buff);
			if( kill(pid, level) == 0)		// kill(pid, 15)
				printf_t("===>Kill backstage%s process(%d)(-%d) success\n",process,  pid, level);
		}
		pclose(fp);
	}
}

2.4 cycle to monitor the running status of relevant processes

In the main function, the main work is to start the hostapdf process, and then cycle to monitor the survival status of the hostapd and dnsmasq processes,
As long as any one of the processes has an exception, it will pay attention to the softap hotspot and release relevant resources.

int main(int argc, char *argv[]){

	// 1. Kill the existing dnsmasq and hostapd before startup
	kill_all_process();
	usleep(200000);
	// 2. Start hostapd
	system("iw phy0 interface add wlan1 type managed");
	system("ifconfig wlan1 up");
	sleep(1);
	system("ifconfig wlan1 192.168.50.1 netmask 255.255.255.0");
	system("route add default gw  192.168.50.1 wlan1");
	printf_t("===>Run command: dnsmasq -C /data/bin/dnsmasq_softap.conf  --interface=wlan1\n");
	system("dnsmasq -C /data/bin/dnsmasq_softap.conf  --interface=wlan1");
	printf_t("===>Run command: hostapd /data/bin/hostapd.conf -t -B\n");
	system("hostapd /data/bin/hostapd.conf -t -B");
		
	printf_t("===>Start cycle monitoring dnsmasq and hostapd -------\n");
	while(keep_alive == 1){
		sleep(1);
		
		if( process_is_alive("dnsmasq") == 0){
			printf_t("===>dnsmasq Process exception, start shutdown hostap\n");
			break;
		}
		if( process_is_alive("hostapd") == 0){
			printf_t("===>hostapd Process exception, start shutdown hostap\n");
			break;
		}
	}

	// 3. Restore the initial state
	kill_all_process();
	printf_t("===>route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1\n");
	system("route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1");
	printf_t("===>ifconfig wlan1 down\n");
	system("ifconfig wlan1 down");
	system("iw dev wlan1 del");
	
	printf_t("End of program operation-------------\n");

	return 0;
}

2.5 add exception handling function

Add a global variable keep_alive is used to confirm whether the current process needs to exit actively.

In the main function, register SIGINT, SIGABRT, SIGTERM and SIGKILL signals and bind the function sig_handler,
When the process is running and receives any of the four signals, it will enter sig_handler function, keep_ Live clears 0, ends the loop monitoring in the main function and releases relevant resources.

void sig_handler( int sig )
{
    if ( sig == SIGINT ||  sig == SIGABRT ||  sig == SIGTERM ||  sig == SIGKILL)
    {
        keep_alive = 0;
		printf_t("===>Stop signal received, keep_alive=%d\n", keep_alive);
    }
}

int main(int argc, char *argv[]){
	// Register exception handler
	signal( SIGINT, sig_handler );
	signal( SIGABRT, sig_handler );
	signal( SIGTERM, sig_handler );
	signal( SIGKILL, sig_handler );
}

3, Dnsmasq Conf file configuration

user=root
# listen-address=127.0.0.1

except-interface=usb0

#interface=p2p-wlan0-0
# dhcp-option=p2p-wlan0-0,1,255.255.225.0     #Specify mask
# dhcp-option=p2p-wlan0-0,3,192.168.50.1     #Specify gateway
# dhcp-option=p2p-wlan0-0,6,192.168.50.1     #Specify dns
dhcp-range=192.168.50.2,192.168.50.51

# log-queries
# log-facility=/data/dnsmasq.log

4, Hostapd Conf file configuration

interface=wlan0
ctrl_interface=/var/run/hostapd
driver=nl80211
ssid=soft-ap

auth_algs=1
wpa=2
wpa_passphrase=12345678
wpa_key_mgmt=WPA-PSK
#wpa_pairwise=TKIP
rsn_pairwise=CCMP

# 5G 149 
channel=149
hw_mode=a
ieee80211ac=1
ignore_broadcast_ssid=0

# 2.4G  6
#channel=6
#hw_mode=g
#ieee80211n=1
#ignore_broadcast_ssid=0

5, Complete code

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

static int keep_alive = 1;

static char *get_cur_time(void){
	static char s[50]={0};
	char s_ms[10]={0};
	time_t t;
	struct tm *ltime;
	struct timeval tv; 
	
	time(&t);
	ltime = localtime(&t);
	gettimeofday(&tv,NULL);  //tv.tv_sec * 1000 + tv.tv_usec / 1000;  
	
	strftime(s, 50, "%Y-%m-%d %H:%M:%S", ltime);
	sprintf(s_ms, ".%03d", tv.tv_usec / 1000);
	strcat(s, s_ms);
	
	return s;
}
#define printf_t(fmt, ...) printf("[%s][Dongle_Soft_ap] "fmt, get_cur_time(), ##__VA_ARGS__)

void sig_handler( int sig )
{
    if ( sig == SIGINT ||  sig == SIGABRT ||  sig == SIGTERM ||  sig == SIGKILL)
    {
        keep_alive = 0;
		printf_t("===>Stop signal received, keep_alive=%d\n", keep_alive);
    }
}

int process_is_alive(const char *process)
{
	FILE *fp = NULL;
	int pid = 0;
	char buff_tmp[100]={0};

	sprintf(buff_tmp, "ps -A | grep %s | wc -l", process);
	fp = popen(buff_tmp, "r");
	if(fp){
		memset(buff_tmp, 0, 100);
		fgets(buff_tmp, sizeof(buff_tmp)-1, fp);
		pclose(fp);
		if(buff_tmp != NULL){
			pid = atoi(buff_tmp);
			return pid;
		}
	}	
	return -1;
}

void kill_process(const char *process, int level)
{
	FILE *fp = NULL;
	int pid = 0;
	char buff_tmp[100]={0}, *p_buff=NULL, *p_buff1=NULL;

	sprintf(buff_tmp, "ps -A | grep %s", process);

	fp = popen(buff_tmp, "r");
	if(fp){
		memset(buff_tmp, 0, 100);
		while(fgets(buff_tmp, sizeof(buff_tmp)-1, fp) >0){
			p_buff = buff_tmp;
			while(p_buff!=NULL && *p_buff!='\0' && *p_buff==' ') p_buff++;
			p_buff1 = p_buff;
			while(p_buff1!=NULL && *p_buff1!='\0' && *p_buff1!=' ') p_buff1++;
			*p_buff1 = '\0';
			pid = atoi(p_buff);
			if( kill(pid, level) == 0)		// kill(pid, 15)
				printf_t("===>Kill backstage%s process(%d)(-%d) success\n",process,  pid, level);
		}
		pclose(fp);
	}
}

void kill_all_process(void)
{
	if( process_is_alive("dnsmasq") >= 1){
		kill_process("dnsmasq", 15);     // kill -15
		usleep(10000);		//Check again after 10ms for success
		if( process_is_alive("dnsmasq") >= 1){
			kill_process("dnsmasq", 9); // Violent shutdown kill -9
		}
	}
	if( process_is_alive("hostapd") >= 1){
		kill_process("hostapd", 15);     // kill -15
		sleep(1);		//After 1ms, re check whether the focus is successful
		if( process_is_alive("hostapd") >= 1){
			kill_process("hostapd", 9); // Violent shutdown kill -9
		}
	}
}


int main(int argc, char *argv[]){
	// Register exception handler
	signal( SIGINT, sig_handler );
	signal( SIGABRT, sig_handler );
	signal( SIGTERM, sig_handler );
	signal( SIGKILL, sig_handler );

	// 1. Kill the existing dnsmasq and hostapd before startup
	kill_all_process();
	usleep(200000);
	// 2. Start hostapd
	system("iw phy0 interface add wlan1 type managed");
	system("ifconfig wlan1 up");
	sleep(1);
	system("ifconfig wlan1 192.168.50.1 netmask 255.255.255.0");
	system("route add default gw  192.168.50.1 wlan1");
	printf_t("===>Run command: dnsmasq -C /data/bin/dnsmasq_softap.conf  --interface=wlan1\n");
	system("dnsmasq -C /data/bin/dnsmasq_softap.conf  --interface=wlan1");
	printf_t("===>Run command: hostapd /data/bin/hostapd.conf -t -B\n");
	system("hostapd /data/bin/hostapd.conf -t -B");
		
	printf_t("===>Start cycle monitoring dnsmasq and hostapd -------\n");
	while(keep_alive == 1){
		sleep(1);
		
		if( process_is_alive("dnsmasq") == 0){
			printf_t("===>dnsmasq Process exception, start shutdown hostap\n");
			break;
		}
		if( process_is_alive("hostapd") == 0){
			printf_t("===>hostapd Process exception, start shutdown hostap\n");
			break;
		}
	}

	// 3. Restore the initial state
	kill_all_process();
	printf_t("===>route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1\n");
	system("route del -net 192.168.50.0 netmask 255.255.255.0 dev wlan1");
	printf_t("===>ifconfig wlan1 down\n");
	system("ifconfig wlan1 down");
	system("iw dev wlan1 del");
	
	printf_t("End of program operation-------------\n");

	return 0;
}