使用 Mingw 构建 libevhtp

Posted

技术标签:

【中文标题】使用 Mingw 构建 libevhtp【英文标题】:Building libevhtp using Mingw 【发布时间】:2019-08-21 06:11:38 【问题描述】:

我正在使用 mingw 在 Windows 上构建 libevhtp,我使用 cmake 和 mingw 生成了 Makefile。调用“make”时出错-

fatal error: arpa/inet.h: No such file or directory

这是给出错误的 log.c。我检查了mingw 并且不包含 arpa/inet.h 并且安装程序不提供任何提供 arpa/inet.h 的库。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/queue.h>
#include "evhtp/evhtp.h"
#include "evhtp/log.h"

typedef enum 
    HTP_LOG_OP_USERAGENT = 1,
    HTP_LOG_OP_PATH,
    HTP_LOG_OP_RHOST,
    HTP_LOG_OP_METHOD,
    HTP_LOG_OP_TIMESTAMP,
    HTP_LOG_OP_PROTO,
    HTP_LOG_OP_STATUS,
    HTP_LOG_OP_REFERRER,
    HTP_LOG_OP_HOST,
    HTP_LOG_OP_HEADER,
    HTP_LOG_OP_PRINTABLE
 htp_log_op_type;


struct 
    char          * fmt_;
    htp_log_op_type type_;
 op_type_strmap_[] = 
     "$ua",     HTP_LOG_OP_USERAGENT ,
     "$path",   HTP_LOG_OP_PATH      ,
     "$rhost",  HTP_LOG_OP_RHOST     ,
     "$meth",   HTP_LOG_OP_METHOD    ,
     "$ts",     HTP_LOG_OP_TIMESTAMP ,
     "$proto",  HTP_LOG_OP_PROTO     ,
     "$status", HTP_LOG_OP_STATUS    ,
     "$ref",    HTP_LOG_OP_REFERRER  ,
     "$host",   HTP_LOG_OP_HOST      ,
     "$hdr::",  HTP_LOG_OP_HEADER    ,
     NULL,      HTP_LOG_OP_PRINTABLE 
;


#define HTP_LOG_OP_TAGSZ 1024

struct htp_log_op 
    htp_log_op_type type;
    size_t          len;
    char            tag[HTP_LOG_OP_TAGSZ];

    TAILQ_ENTRY(htp_log_op) next;
;

TAILQ_HEAD(htp_log_format, htp_log_op);

htp_log_op_type
htp_log_str_to_op_type_(const char * fmt, int * arglen)

    int i;

    for (i = 0; op_type_strmap_[i].fmt_; i++) 
        const char    * fmt_  = op_type_strmap_[i].fmt_;
        htp_log_op_type type_ = op_type_strmap_[i].type_;

        if (!strncasecmp(fmt_, fmt, strlen(fmt_))) 
            *arglen = strlen(fmt_);

            return type_;
        
    

    return 0;


static struct htp_log_format *
htp_log_format_new_(void)

    struct htp_log_format * format;

    format = calloc(1, sizeof(*format));
    TAILQ_INIT(format);

    return format;


static struct htp_log_op *
htp_log_op_new_(htp_log_op_type type)

    struct htp_log_op * op;

    op       = calloc(1, sizeof(*op));
    op->type = type;

    return op;


/**
 * @brief [debug] print the psuedo-stack
 *
 * @param stack
 */
static void
dump_(struct htp_log_format * format)

    struct htp_log_op * op;

    TAILQ_FOREACH(op, format, next) 
        switch (op->type) 
            case HTP_LOG_OP_USERAGENT:
                printf("$ua");
                break;
            case HTP_LOG_OP_PATH:
                printf("$path");
                break;
            case HTP_LOG_OP_METHOD:
                printf("$meth");
                break;
            case HTP_LOG_OP_TIMESTAMP:
                printf("$ts");
                break;
            case HTP_LOG_OP_REFERRER:
                printf("$ref");
                break;
            case HTP_LOG_OP_RHOST:
                printf("$rhost");
                break;
            case HTP_LOG_OP_STATUS:
                printf("$status");
                break;
            case HTP_LOG_OP_HOST:
                printf("$host");
                break;
            case HTP_LOG_OP_HEADER:
                printf("$hdr::");
                break;
            case HTP_LOG_OP_PROTO:
                printf("$proto");
                break;
            case HTP_LOG_OP_PRINTABLE:
                printf("%s", op->tag);
                break;
         /* switch */
    

    printf("\n");
 /* log_format_dump_ */

static void
htp_log_format_addchar_(struct htp_log_format * format, const char c)

    struct htp_log_op * op;

    if (TAILQ_EMPTY(format)) 
        /* the format op stack is empty, we want to allocate a new one */
        op = NULL;
     else 
        /* reuse the last format op, appending the character */
        op = TAILQ_LAST(format, htp_log_format);
    

    if (op == NULL || op->type != HTP_LOG_OP_PRINTABLE) 
        /* the last op in the format stack was not a type of PRINTABLE or
         * NULL, so allocate a new one.
         */
        op = htp_log_op_new_(HTP_LOG_OP_PRINTABLE);

        /* insert the newly allocated stack_ent into the stack */
        TAILQ_INSERT_TAIL(format, op, next);
    

    /* append the character to the stack_ent */
    op->tag[op->len++] = c;
    op->tag[op->len]   = '\0';


#define IS_FMTVAR(X) (*X == '$' && *(X + 1) != '$')

/**
 * @brief using an input string, create a stack of information that will be
 *        logged.
 *
 * @param fmt
 *
 * @return
 */
static struct htp_log_format *
htp_log_format_compile_(const char * strfmt)

    const char            * strp;
    struct htp_log_format * format;

    format = htp_log_format_new_();

    for (strp = strfmt; *strp != '\0'; strp++) 
        struct htp_log_op * op;

        /* if the character is a format variable ($var),
         * then create a new stack entry, and insert it
         * into the stack. Otherwise append the character
         * to the last stack entry
         */
        if (IS_FMTVAR(strp)) 
            int arglen;

            op    = htp_log_op_new_(htp_log_str_to_op_type_(strp, &arglen));
            strp += arglen - 1;

            TAILQ_INSERT_TAIL(format, op, next);
         else 
            htp_log_format_addchar_(format, *strp);
        
    

    return format;


void *
evhtp_log_new(const char * fmtstr)

    return htp_log_format_compile_(fmtstr);


void
evhtp_log_request_f(void * format_p, evhtp_request_t * request, FILE * fp)

    struct htp_log_format * format = format_p;
    struct htp_log_op     * op;
    struct timeval          tv;
    struct tm             * tm;
    struct sockaddr_in    * sin;
    char                    tmp[64];

    TAILQ_FOREACH(op, format, next) 
        const char * logstr = NULL;

        switch (op->type) 
            case HTP_LOG_OP_USERAGENT:
                logstr = evhtp_header_find(request->headers_in, "user-agent");

                break;
            case HTP_LOG_OP_PATH:
                if (request->uri && request->uri->path && request->uri->path->full) 
                    logstr = request->uri->path->full;
                

                break;
            case HTP_LOG_OP_METHOD:
                if (request->conn->parser) 
                    logstr = htparser_get_methodstr(request->conn->parser);
                

                break;
            case HTP_LOG_OP_TIMESTAMP:
                event_base_gettimeofday_cached(request->conn->evbase, &tv);

                tm     = localtime(&tv.tv_sec);
                strftime(tmp, sizeof(tmp), "%d/%b/%Y:%X %z", tm);
                logstr = tmp;

                break;
            case HTP_LOG_OP_REFERRER:
                logstr = evhtp_header_find(request->headers_in, "referer");

                break;
            case HTP_LOG_OP_RHOST:
                sin    = (struct sockaddr_in *)request->conn->saddr;

                evutil_inet_ntop(AF_INET, &sin->sin_addr, tmp, sizeof(tmp));
                logstr = tmp;

                break;
            case HTP_LOG_OP_STATUS:
                fprintf(fp, "%d", evhtp_request_status(request));

                continue;
            case HTP_LOG_OP_HOST:
                logstr =
                    request->htp->server_name ? : evhtp_header_find(request->headers_in, "host");

                break;
            case HTP_LOG_OP_PROTO:
                logstr = evhtp_request_get_proto(request) == EVHTP_PROTO_11 ? "1.1" : "1.0";

                break;
            case HTP_LOG_OP_HEADER:
            /* not implemented yet - fallthrough */
            case HTP_LOG_OP_PRINTABLE:
                logstr = op->tag;

                break;
         /* switch */

        fputs(logstr ? : "-", fp);
    

    fputc('\n', fp);
 /* evhtp_log_request_f */

任何帮助将不胜感激。这是libevhtp的github链接-https://github.com/criticalstack/libevhtp

【问题讨论】:

【参考方案1】:

arpa/inet.h 是 POSIX 标头,win32 API 不支持它。 MinGW 标头只是本机 win32 标头的重新实现,不提供额外的 POSIX 兼容性。在 Windows 上,您必须使用 winsock2.h

您可以尝试使用 Cygwin,它包含更多来自 Linux 的内容。安装 Cygwin 需要花费大量时间,并且无法保证结果。

编辑

我发现这个article 正在编译1.2.11n 版本,这显然是可行的,因为没有log.c

我还发现在evhtp.c1.2.11n 和当前版本中导入了arpa/inet.h

#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <signal.h>
#include <strings.h>
#include <inttypes.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#else
#define WINVER 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

这是一个条件导入。我相信他们忘记在log.c 中添加条件导入。我建议您打开一个问题,要求使log.cevhtp.c 一样跨平台

【讨论】:

感谢@vx3r 抽出宝贵时间。我在 log.c 中添加了 #ifndef WIN32 #include #else #define WINVER 0x0501 #include #include #endif 在添加这个之后我收到错误为“ c:\mingw\include\winsock2.h:49:2: error: #error "不支持在 之后包含 。" #error "在 之后包含 > 不受支持。"" 如前所述,我在 libevhtp 上提出了这个问题 您还必须编写条件代码来处理与arpa/inet.h for linux 和winsock2.h for windows 的逻辑。让开发团队处理问题 如前所述,我使用 cygwin 构建了 libevhtp,但生成的文件是 libevhtp.a 但不是 dll 知道如何实现这一目标

以上是关于使用 Mingw 构建 libevhtp的主要内容,如果未能解决你的问题,请参考以下文章

使用 minGW 构建 crypto562

如何在 Windows 中使用 MinGW 构建 OpenSSL? [关闭]

如何使用 MinGW 构建 Boost 1.55?

使用 MinGW 构建 vim

在代码块中使用 mingw gcc 构建 64 位 exe

如何在 Windows 上使用 MINGW 构建 clang?