I wrote a PPPoE multicast client, when the client received an account password, it would use a thread and occupied a socket for the session phase, but when I created the 16th thread, an error occurred: No such device.At the same time, I used the fork to occupy the session socket, but even a socket could not be used in this way. In the first connection, there would be an error: no such device. I really did not understand it, and I could not find relevant information,this is my if.c:
#include "main.h"
/****************************************************************
* %FUNCTION: openInterFace
* %ARGUMENTS:
* ifname -- name of interface
* type -- 0x8863 or 0x8864, protocol type
* %RETURNS:
* sock fd
* %DESCRIPTION:
* Open the promisc mode and bind the fd on interface
* *************************************************************/
int
openInterFace(const char* ifname, uint16_t type)
{
int fd;
if ((fd = socket(AF_PACKET, SOCK_RAW, htons(type))) < 0)
{
perror("socket");
exit(EXIT_FAILURE);
}
// set broadcast option
int optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
// init flags
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
perror("ioctl get flag");
close(fd);
exit(EXIT_FAILURE);
}
// change flags to promisc
ifr.ifr_flags |= IFF_PROMISC;
// set the if flag
if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
perror("ioctl set flag");
close(fd);
exit(EXIT_FAILURE);
}
// init sockfd and bind to interface sa
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons(type);
sa.sll_ifindex = if_nametoindex(ifname);
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
perror("bind");
exit(EXIT_FAILURE);
}
return fd;
}
/****************************************************************
* %FUNCTION: get_udp_hardware_ipv4
* %ARGUMENTS:
* ethname -- the hardware name witch ipv4 you wanna get
* %RETURNS:
* sockaddr_in
* %DESCRIPTION:
* Get the ip for bind
* *************************************************************/
struct sockaddr_in *
get_udp_hardware_ipv4(char *ethname)
{
struct ifaddrs *addrs, *tmp;
struct sockaddr_in *rtv = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in));
if (rtv == NULL)
{
perror("calloc");
exit(EXIT_FAILURE);
}
// 获取所有网络接口信息
if (getifaddrs(&addrs) == -1)
{
perror ("getifaddrs");
exit(EXIT_FAILURE);
}
for (tmp = addrs; tmp != NULL; tmp = tmp->ifa_next)
{
if (tmp->ifa_addr == NULL) continue;
if (tmp->ifa_addr->sa_family == AF_INET && !strcmp(ethname, tmp->ifa_name))
{
memcpy(rtv, tmp->ifa_addr, sizeof(struct sockaddr_in));
return rtv;
}
}
perror("eth name no found!\n");
exit(EXIT_FAILURE);
}
/****************************************************************
* %FUNCTION: get_udp_hardware_ipv4
* %ARGUMENTS:
* mac -- the mac pointer you want set value
* %RETURNS:
* Nothing
* %DESCRIPTION:
* Produce random mac
* *************************************************************/
void set_rand_mac(uint8_t *mac)
{
FILE *f;
f = fopen("/dev/urandom", "r");
if (f == NULL)
{
perror("Error opening /dev/urandom");
exit(EXIT_FAILURE);
}
if (fread(mac, sizeof(uint8_t), ETH_ALEN, f) != ETH_ALEN)
{
perror("Error in read /dev/urandom");
exit(EXIT_FAILURE);
}
fclose(f);
mac[0] &= 0xFE;
mac[0] |= 0x02;
return;
}
and this is my main.c
int
main(int argc, char **argv)
{
ifname = "ens33";
//-----------------------------test-----------------------------------
// discoverySocket = openInterFace(ifname, PPPOE_DISCOVERY);
// sessionSocket = openInterFace(ifname, PPPOE_SESSION);
//-----------------------------test-----------------------------------
int sockFD = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in *ipv4StructP = get_udp_hardware_ipv4(ifname);
ipv4StructP->sin_port = htons(9000);
if (bind(sockFD, (struct sockaddr *)ipv4StructP, sizeof(struct sockaddr_in)) < 0)
{
perror("bind udp");
exit(EXIT_FAILURE);
}
free(ipv4StructP);
ipv4StructP = NULL;
uint8_t buf[100] = {'\0'};
while (1)
{
if (recvfrom(sockFD, buf, sizeof(buf), 0, NULL, NULL))
{
// has recv the user data
Passwd_User pu;
memset(&pu, 0, sizeof(pu));
int flag = 0;
size_t plen = 0;
size_t ulen = 0;
for (int i = 0; i < strlen(buf); i++)
{
if (buf[i] == '\n')
{
flag++;
continue;
}
if (flag) pu.password[plen++] = buf[i];
else pu.user[ulen++] = buf[i];
}
// printf("usr = %s password = %s\n", pu.user, pu.password);
pthread_t pct;
if (pthread_create(&pct, NULL, PPPoE_connect, &pu) != 0)
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
pthread_detach(pct);
// if (fork() == 0)
// {
// setsid();
// uint8_t mac[6] = {'\0'};
// set_rand_mac(mac);
// struct timeval tv;
// gettimeofday(&tv, NULL);
// srand(tv.tv_usec);
// Connection conn;
// memset(&conn, 0, sizeof(conn));
// for(int i = 0; i < ETH_ALEN; i++)
// conn.myEth[i] = mac[i];
// conn.user = pu.user;
// conn.password = pu.password;
// conn.state = PPPOE_DISCOVERY;
// conn.hostUniq = rand() % 65536;
// conn.ifname = malloc(strlen(ifname) + 1); memcpy(conn.ifname, ifname, strlen(ifname));
// conn.discoverySocket = openInterFace(conn.ifname, conn.state);
// //-----------------------------test-----------------------------------
// // conn.discoverySocket = discoverySocket;
// // conn.sessionSocket = sessionSocket;
// //-----------------------------test-----------------------------------
// printf("User : %s\nPassword : %s\nMac : %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
// conn.user,
// conn.password,
// conn.myEth[0], conn.myEth[1], conn.myEth[2], conn.myEth[3], conn.myEth[4], conn.myEth[5]);
// printf("================ User Password Mac have load ================\n");
// discovery(&conn);
// if(conn.state == PPPOE_SESSION)
// {
// conn.sessionSocket = openInterFace(conn.ifname, conn.state);
// session(&conn);
// free(conn.ifname);
// } else {
// perror("seems discovery has wrong");
// exit(EXIT_FAILURE);
// }
// }
}
}
I don't think there is a problem with the way I use it, because the first 15 are OK, but the 16th one will have this problem. I thought whether it is because the maximum number of sockets used is 15, but I checked the data and used ulimit -Sn to find that the maximum value is 1024, which makes me even less understand