将带有动态数组的结构复制到c中的缓冲区中

时间:2013-04-26 15:54:19

标签: c pointers struct dns packing

我想使用套接字API手动为dns服务器构建一个dns查询(它是项目的一部分,无法更改)。所以我想复制一个结构,如:

typedef struct {         
    uint16_t dns_id;  /* identification number */       
    uint16_t dns_flags; /* DNS flags */        
    uint16_t dns_qdc; /* number of question entries */      
    uint16_t dns_anc; /* number of answer entries */  
    uint16_t dns_nsc; /* number of authority entries */      
    uint16_t dns_arc; /* number of resource entries */
    unsigned char *host;
    unsigned short qtype;
    unsigned short qclass;     
} DNS_QUERY;


DNS_QUERY* dns_query = (DNS_QUERY *) malloc(sizeof(DNS_QUERY)); 

进入缓冲区,如:

char* dns_buf = malloc(500);

但是当我这样做时,没有任何东西被复制到缓冲区中。当我向* host元素输入不同的字符串时,sizeof(dns_query)保持不变。当我使用

memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));

它输出如下:

dns_buf:
strlen(dns_buf)= 0

当我使用for循环打印它时:

for (i = 0 ; i<strlen(dns_buf) ; i++){
        printf("%c", dns_buf[i]);   
    }

它不会输出任何内容

当我使用指针而不是memcpy时,例如:

dns_buf = dns_query;

它提供相同的输出。有人可以告诉我应该做什么吗?

这是整个代码:

int udp_connect(char *hostname, char *dns_name, char buf[]){

    int sockfd;
    int num_bytes;
    struct sockaddr_in servaddr;
    char str[INET_ADDRSTRLEN];
    struct hostent *hptr; /* For gethostbyname() */
    char **pptr; /* For inet_ntop() */
    char* dns_buf, recv_buf = NULL; 
    int len = 0;
    int i = 0;
    static unsigned short id = 0; /* For the query ID */

    /* Allocating memory for structs */
    DNS_QUERY* dns_query = malloc(sizeof(DNS_QUERY)); 
    /* QUESTION *dns_question = malloc(sizeof(QUESTION));*/
    recv_buf = malloc(MAXDATASIZE);

    if((hptr = gethostbyname(dns_name)) == NULL){
        perror("Error in gethostbyname()\n");
        exit(1);
    }

    if ((pptr = hptr->h_addr_list) != NULL) { /* (hptr->h_addrtype == AF_INET) && */
        printf("The address is: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
    } else {
        perror("Error in inet_ntop() \n");
    }

    memset(&servaddr, 0, sizeof (servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(DNS_PORT);
    inet_pton(AF_INET, str, &servaddr.sin_addr);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
        perror("Error while making a socket");
        return -1;
    }   

    /* Setting hostname into the name segment of the query */
    ChangetoDnsNameFormat(hostname);
    dns_query->host = hostname;
    printf("\ndns_query->host: %s\n", dns_query->host);


    /* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */    

    /* setting up the header */
    dns_query->dns_id = htons(id); /* id */
    dns_query->dns_flags = htons(0x10); /* 0000000100000000 recursion is desired*/  
    dns_query->dns_qdc = htons(0x01); /* We have one question */
    dns_query->dns_anc = htons(0x00);
    dns_query->dns_nsc = htons(0x00);
    dns_query->dns_arc = htons(0x00);

    dns_query->qtype = htons(1); /* For IPv4 */
    dns_query->qclass = htons(1); /* For internet */

    len = sizeof(DNS_QUERY) + strlen(hostname); /* Calculating the length to use it in sendto() */

    dns_buf = malloc(len);

    dns_buf = dns_query;
    /* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */

    for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
            printf("%02X", dns_buf[i]);   
    }

    /* to check if the same as dns_query, use the following print also */
    for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
            printf("%02X", dns_query[i]);   
        }
    print("\n");

    /* Sending the datagram to the dns server */
    printf("\n--------------------\nSending datagram: \n%s\n", dns_buf);
    if ((num_bytes = sendto(sockfd, dns_buf, len, 0, (struct sockaddr *) &servaddr, sizeof(servaddr))) == -1){
        perror("Error in sendto");
        exit(1);
    }

    /* Receiving the datagram from the dns server */
    printf("Receiving datagram...\n");
    num_bytes = recvfrom(sockfd, recv_buf, MAXDATASIZE, 0, NULL, NULL);
    printf("Received %i bytes of datagram...\n", num_bytes);

    printf("dns_buf in udp connect: %s\n", recv_buf);

    id = id + 1;

    free(dns_query);
    freeaddrinfo((struct addrinfo *) &servaddr);
    close(sockfd);

    return sockfd;
}
/******************************************************************************/
void ChangetoDnsNameFormat(char *hostname)
{
    int walker=0;
    int i;
    int counter = 0;
    char tmp[40];

    strcat(hostname, "$"); /* For having a $ at the end of the dns name format */   

    for(i=0 ; i< (int) strlen((char*)hostname) ; i++)
    {
        if(hostname[i]=='.')
        {
            tmp[walker] = (char) counter + 48;
            /*printf("%s\n", tmp);*/

            for( ; walker < i ; walker++)
            {
                tmp[walker + 1] = hostname[walker];
            }

            walker++;
            counter = -1;
        }else if(hostname[i]=='$'){

            tmp[walker] = (char) counter + 47;
            /*printf("%s\n", tmp);*/

            for( ; walker < i ; walker++)
            {
                tmp[walker + 1] = hostname[walker];
            }

            walker++;
            counter = -1;
        }
        counter++;
    }
    walker--;
    tmp[walker] = '\0'; /* Terminate the string */

    strcat(tmp, "0"); /* For having a 0 at the end of the dns name format */

    strcpy(hostname, tmp);
}

2 个答案:

答案 0 :(得分:1)

dns_buf不是字符串(以null charcter结尾)。

它是一个指针(作为char *)到一个内存空间,内存可以在开头包含0作为值,这就是为什么当你使用strlen(dns_buf)时你得到它= 0这意味着dns_buf中的fisrt元素为0

查看您可以使用的dns_buf内容:

for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
        printf("%02X", dns_buf[i]);   
    }
print("\n");

// to check if the same as dns_query, use the following print also
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
        printf("%02X", dns_query[i]);   
    }
print("\n");

答案 1 :(得分:1)

struct不包含字符host的数组,而是指向第一个元素的指针。

这意味着,虽然您正在复制整个结构,但只需将指针复制到主机中包含的数据(然后指向相同的字符串)。你要做的是:

DNS_QUERY *dns_buf = malloc(sizeof(DNS_QUERY));
memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));
dns_buf.host = "yourmodifiedhost";