X
X
xverizex2020-02-28 20:12:47
linux
xverizex, 2020-02-28 20:12:47

Epoll returns an event with file descriptor 0, although it worked before, what could be wrong?

the code used to work. I do not know, maybe something has changed in the kernel. The code worked three days ago. but yesterday it stopped working. events returns a null file descriptor, although it shouldn't. here is the server code. everything is written here.

/*
 * server.c - server for game.
 * author: Naidolinskii Dmitrii
 *******************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "db.h"
#include "config.h"
#include "events.h"

/* сокет сервера */
static int sockfd;
extern struct conf conf;
struct sockaddr_in in_server;
int epollfd, nfds;
#define AUTH_ADMIN            0
#define AUTH_GAMER            1
char sym[2] = { '!', '1' };

#define DEFAULT_SIZE_POLL        65535
#define DEFAULT_SIZE_DATA         1024

struct epoll_event ev, events[DEFAULT_SIZE_POLL];

static void *thread_control_clients ( void *data ) {

  while ( 1 ) {
    nfds = epoll_wait ( epollfd, events, DEFAULT_SIZE_POLL, -1 );
    printf ( "nfds: %d\n", nfds );
    if ( nfds == 0 ) continue;
    if ( nfds == -1 ) {
      perror ( "poll" );
      exit ( EXIT_FAILURE );
    }
    for ( int i = 0; i < nfds; i++ ) {
      char data[DEFAULT_SIZE_DATA + 1];
      printf ( "read ( %d )\n", events[i].data.fd );
      int ret = read ( events[i].data.fd, data, DEFAULT_SIZE_DATA );
      printf ( "ret: %d\n", ret );
      if ( ret <= 0 ) {
        char *byte = (char *) events[i].data.ptr;
        if ( byte ) {
          if ( *byte == sym[AUTH_GAMER] ) db_offline_user ( events[i].data.fd );
          if ( events[i].data.ptr ) free ( events[i].data.ptr );
        }
        epoll_ctl ( epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i] );
        /* здесь отправить другому игроку о том что игрок вышел из боя, если проводится бой. */
        continue;
      }
      switch ( data[0] ) {
        case '!':
          {
            int ret = db_register_admin ( &data[1] );
            switch ( ret ) {
              case EVENT_EVENT_FALSE:
                /* можно вывести сообщение об ошибке */
                write ( events[i].data.fd, "false", 6 );
                epoll_ctl ( epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i] );
                close ( events[i].data.fd );
                break;
              default:
                {
                  events[i].data.ptr = &sym[AUTH_ADMIN];
                  write ( events[i].data.fd, "!", 2 );
                }
                break;
            }
          }
          break;
        case '0':
          {
            int ret = db_registration ( &data[1], events[i].data.fd );
            switch ( ret ) {
              case EVENT_USER_IS_ONLINE:
                /* отправить сообщение что пользователь онлайн
                 * оборвать соединение */
                epoll_ctl ( epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i] );
                close ( events[i].data.fd );
                printf ( "пользователь уже есть в игре %d\n", events[i].data.fd );
                continue;
                break;
              case EVENT_EVENT_FALSE:
                /* неправильные данные */
                printf ( "неправильные данные.\n" );
                epoll_ctl ( epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i] );
                close ( events[i].data.fd );
                break;
              default:
                {
                  events[i].data.ptr = &sym[AUTH_GAMER];
                  write ( events[i].data.fd, "1", 2 );
                }
                break;
            }
          }
          break;
      }
    }
  }
}

/* создание потока */
void create_thread ( ) {
  epollfd = epoll_create1 ( 0 );
  if ( epollfd == -1 ) {
    perror ( "epoll_create" );
    exit ( EXIT_FAILURE );
  }

  pthread_t t;
  pthread_create ( &t, NULL, thread_control_clients, NULL );
}

void wait_client ( ) {
  socklen_t soss = sizeof ( in_server );
  int client = accept ( sockfd, ( struct sockaddr * ) &in_server, &soss );
  if ( client == -1 ) return;
  printf ( "%d подключен.\n", client );
#if 0
  int ret = fcntl ( client, F_SETFD, ( fcntl ( client, F_GETFD ) | O_NONBLOCK ) );
  if ( ret == -1 ) {
    perror ( "fcntl" );
  }
#endif
  ev.events = EPOLLIN;
  ev.data.fd = client;
  ev.data.ptr = NULL;
  if ( epoll_ctl ( epollfd, EPOLL_CTL_ADD, client, &ev ) == -1 ) {
    perror ( "epoll_ctl" );
    exit ( EXIT_FAILURE );
  }
}

/* конфигурация сокета */
void configure_socket ( ) {
   sockfd = socket ( AF_INET, SOCK_STREAM, 0 );
   if ( sockfd == -1 ) {
     perror ( "socket" );
     exit ( EXIT_FAILURE );
   } 

   int ret;
   {
    int opt = 1;
   	ret = setsockopt ( sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof ( opt ) );
    if ( ret == -1 ) {
      perror ( "sock opt SO_REUSEPORT" );
      exit ( EXIT_FAILURE );
    }
   }

   in_server.sin_family = AF_INET;
   in_server.sin_port = htons ( conf.port );
   inet_aton ( "127.0.0.1", &in_server.sin_addr );
  // in_server.sin_addr.s_addr = 0;
   ret = bind ( sockfd, ( struct sockaddr *) &in_server, sizeof ( in_server ) );
   if ( ret == -1 ) {
     perror ( "bind" );
     exit ( EXIT_FAILURE );
   }
   ret = listen ( sockfd, conf.listen );
   if ( ret == -1 ) {
     perror ( "listen" );
     exit ( EXIT_FAILURE );
   }

}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
X
xverizex, 2020-02-28
@xverizex

Ah, I figured out what the problem is. turns out to be in events fd and ptr is a union, and therefore when I specified ptr = NULL, I nullified fd. it is now clear. Damn, I made code based on ptr, I thought it was an additional convenience. OK.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question