Мой увлиб по умолчанию l oop неожиданно завершает работу - почему? - PullRequest
0 голосов
/ 06 января 2020

Я разрабатываю программу, которая следит за UDP-портом для пакета «обнаружения». Когда он получает пакет, он передает пакет отправителю и затем должен ждать дальнейших команд от отправителя.

Это реализовано с использованием uvlib (на основе документации uvlib, пример здесь: http://docs.libuv.org/en/v1.x/guide/networking.html#udp). Я инициализирую сокет получения (для ожидания пакета обнаружения) и широковещательный сокет (для ответа на обнаружение). Когда поступают данные UDP, запускается обратный вызов on_UDP_read. В этом обратном вызове я получаю IP-адрес и порт вызывающего абонента и отправляю эхо-пакет.

Все это прекрасно работает (отправляющая система получает эхо-пакет); проблема в том, что основной l oop (uv_run (l oop, UV_RUN_DEFAULT) должен продолжать работать после ответа ... однако он завершается с нулевым кодом возврата. Я не могу просто запустить его снова в (kludge) l oop, потому что тогда отправляющая система каждый раз выбирает новый порт (стандартное поведение UDP), поэтому я не могу (позже) отправить массовые данные, которые я хочу отправить.

Вопрос: почему основной l oop останавливается, как если бы я выполнил команду uv_stop?

Мне интересно, есть ли проблемы с использованием памяти. Буфер отправки распределяется в функции следующим образом: const uv_buf_t a []. (Может быть, это нужно сделать с помощью mallo c ??)

Вот программа:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <uv.h>
#include <string.h>
#include<arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
#include <math.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include "de_signals.h"

#define BUFFERLEN 65    // Maximum length of buffer
#define PORT 1024   // Port to watch

uv_loop_t *loop;
uv_udp_t send_socket;
uv_udp_t recv_socket;

//sem_t mutex;
//pthread_t t1;

int sockfd;  // socket definition for UDP
struct sockaddr_in servaddr; 

static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
  buf->base = malloc(suggested_size);
  buf->len = suggested_size;
}

//struct sockaddr_in si_DE, si_main;

void on_UDP_send(uv_udp_send_t* req, int status)
{
  printf("UDP send complete, status = %d\n", status);
  // the following is supposed to free the send buffer, but causes a segmentation fault
  //free(req);
  return;
}

void on_UDP_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) {
    puts("UDP data detected");
    if (nread < 0) {
        fprintf(stderr, "Read error %s\n", uv_err_name(nread));
        uv_close((uv_handle_t*) req, NULL);
        free(buf->base);
        return;
    }

    char sender[17] = { 0 };
    uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
    fprintf(stderr, "Recv from %s\n", sender);

    struct sockaddr_in *sin = (struct sockaddr_in *) addr;
    char ip[INET_ADDRSTRLEN];
    uint16_t port;
    port = htons (sin->sin_port);
    printf("port = %d \n",port);

    int sentBytes;
    char replybuf[60];

    uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
    fprintf(stderr, "Recv from %s\n", sender);
    for(int i=0;i<nread;i++){fprintf(stderr,"%02X ",buf->base[i]);}
    fprintf(stderr,"\n");

    puts("create discovery reply buf");
    char b[60];
    for(int i=0;i<60;i++) {b[i] = 0;}
    if((buf->base[0] & 0xFF) == 0xEF && (buf->base[1] & 0xFF) == 0xFE) {
    fprintf(stderr,"discovery packet detected\n");
    b[0] = 0xEF;
    b[1] = 0xFE;
    b[2] = 0x02;
    }
    if((buf->base[0] & 0xFF) == 0x53 && (buf->base[1] & 0xFF) == 0x3F) {
    fprintf(stderr, "STATUS INQUIRY detected\n");
    b[0] = 0x4F;
        b[1] = 0x4B;
    port = 1024; // temporary, until we have a better way
    sleep(1); // let LH get socket open
    }


////////////// reply ///////////////

    uv_udp_send_t send_req;

    puts("create discovery reply buf");

    const uv_buf_t a[]={{.base = b, .len=60}};

    for(int i=0;i<60;i++){fprintf(stderr,"%02X ",a[0].base[i]);}; 
    fprintf(stderr,"\n");

    puts("ready to send");


// Here we reply to sender, using sender's IP and port

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    struct hostent* hptr = gethostbyname(sender);
    if(!hptr) puts ("gethostbyname error");
    servaddr.sin_addr.s_addr =     //INADDR_ANY; 
    ((struct in_addr*) hptr->h_addr_list[0])->s_addr;

    uv_udp_send(&send_req, &send_socket, a, 1, (const struct sockaddr *)&servaddr,
     on_UDP_send);


   puts("reply issued");

   // free(buf->base);
    uv_udp_recv_stop(req);   // ???
    puts("returning from processing UDP packet");
    return;
}

/////////////////////////////////////////////////////////////////////////////////
int main() {
 int retcode;
 //while(1==1)  // this is a kludgy extra loop until we find out why uv_run halts.
 //{



  puts("starting");
    loop = uv_default_loop();

    uv_udp_init(loop, &recv_socket);
    struct sockaddr_in recv_addr;
    uv_ip4_addr("0.0.0.0", 1024, &recv_addr);
    uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR);
    uv_udp_recv_start(&recv_socket, alloc_buffer, on_UDP_read);

    uv_udp_init(loop, &send_socket);
    struct sockaddr_in broadcast_addr;
    uv_ip4_addr("0.0.0.0", 0, &broadcast_addr);
    uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0);
    uv_udp_set_broadcast(&send_socket, 1); puts("wait for UDP handshake\n");

  // Creating socket file descriptor for UDP
  if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
        perror("socket creation failed"); 
        exit(EXIT_FAILURE); 
      }


  puts("start main loop");
  retcode = uv_run(loop, UV_RUN_DEFAULT);

  fprintf(stderr,"Return code from uv_run loop = %d \n",retcode);
 //}
 puts("out of main loop");
  return retcode;
}

1 Ответ

0 голосов
/ 08 января 2020

Я понял часть этого. Прежде всего, «uvlib» - это не название пакета; "libuv" есть. Во-вторых, причина выхода l oop заключается в том, что в конце процедуры обратного вызова on_read есть инструкция uv_udp_recv_stop (req). libuv завершается, когда больше нет работы.

ОСТАВАЮЩАЯСЯ ПРОБЛЕМА: если вы удалите инструкцию uv_udp_recv_stop (req) с мыслью, что, возможно, из-за этого l oop будет работать (как и должно быть), сбой программы с ошибкой сегментации. Я сообщил об этом команде libuv (используя отчеты о проблемах Github), и они не помогли, потому что они не несут никакой ответственности за правильность примеров программ, размещенных в их хранилище libuv в github. Интересно, что когда вы устанавливаете libuv и запускаете проверку (т.е. запускаете свои тесты), все тесты, связанные с многоадресной передачей UDP, не проходят. Это наводит меня на мысль, что пакет libuv действительно имеет некоторые ошибки в области UDP; Я сообщил об этом, но, думаю, у команды libuv больше жарить sh.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...