Socket:When I use over 15 socket , perror will tell:no such device

25 views Asked by At

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

0

There are 0 answers