resolver.c 3.81 KB
Newer Older
pdw's avatar
iftop  
pdw committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * resolver.c:
 *
 */

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>

#include "ns_hash.h"
chris's avatar
""    
chris committed
17
#include "iftop.h"
pdw's avatar
iftop  
pdw committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

#define RESOLVE_QUEUE_LENGTH 20

struct in_addr resolve_queue[RESOLVE_QUEUE_LENGTH];

pthread_cond_t resolver_queue_cond;
pthread_mutex_t resolver_queue_mutex;

hash_type* ns_hash;

int head;
int tail;

void resolver_worker(void* ptr) {
    struct timespec delay;
chris's avatar
""    
chris committed
33
/*    int thread_number = *(int*)ptr;*/
pdw's avatar
iftop  
pdw committed
34
35
    delay.tv_sec = 0;
    delay.tv_nsec = 500;
36
    pthread_mutex_lock(&resolver_queue_mutex);
chris's avatar
""    
chris committed
37
    sethostent(1);
pdw's avatar
iftop  
pdw committed
38
39
    while(1) {
        /* Wait until we are told that an address has been added to the 
chris's avatar
""    
chris committed
40
         * queue. */
pdw's avatar
iftop  
pdw committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        pthread_cond_wait(&resolver_queue_cond, &resolver_queue_mutex);

        /* Keep resolving until the queue is empty */
        while(head != tail) {
            struct in_addr addr = resolve_queue[tail];
            struct hostent hostbuf, *hp;
            size_t hstbuflen;
            char *tmphstbuf;
            int res;
            int herr;

            /* mutex always locked at this point */

            tail = (tail + 1) % RESOLVE_QUEUE_LENGTH;

56
57
            pthread_mutex_unlock(&resolver_queue_mutex);

pdw's avatar
iftop  
pdw committed
58
59
            hstbuflen = 1024;
            /* Allocate buffer, remember to free it to avoid memory leakage.  */            
chris's avatar
""    
chris committed
60
            tmphstbuf = xmalloc (hstbuflen);
pdw's avatar
iftop  
pdw committed
61

chris's avatar
""    
chris committed
62
            while ((res = gethostbyaddr_r ((char*)&addr, sizeof(addr), AF_INET,
pdw's avatar
iftop  
pdw committed
63
64
65
66
67
68
69
70
71
72
                                           &hostbuf, tmphstbuf, hstbuflen,
                                           &hp, &herr)) == ERANGE) {
                /* Enlarge the buffer.  */
                hstbuflen *= 2;
                tmphstbuf = realloc (tmphstbuf, hstbuflen);
              }

            /*
             * Store the result in ns_hash
             */
73
            pthread_mutex_lock(&resolver_queue_mutex);
pdw's avatar
iftop  
pdw committed
74
75
76
77
78
79
80
81
82
83
84

            /*  Check for errors.  */
            if (res || hp == NULL) {
                /* failed */
                /* Leave the unresolved IP in the hash */
            }
            else {
                /* success */
                char* hostname;
                if(hash_find(ns_hash, &addr, (void**)&hostname) == HASH_STATUS_OK) {
                    hash_delete(ns_hash, &addr);
chris's avatar
""    
chris committed
85
                    xfree(hostname);
pdw's avatar
iftop  
pdw committed
86
87
88
89
90
                }
                hostname = strdup(hp->h_name);
                hash_insert(ns_hash, &addr, (void*)hostname);

            }
chris's avatar
""    
chris committed
91
            xfree(tmphstbuf);
pdw's avatar
iftop  
pdw committed
92
93
94
95
96
        }
    }
}

void resolver_initialise() {
97
98
    int* n;
    int i;
pdw's avatar
iftop  
pdw committed
99
100
101
102
103
104
105
106
    pthread_t thread;
    head = tail = 0;

    ns_hash = ns_hash_create();
    
    pthread_mutex_init(&resolver_queue_mutex, NULL);
    pthread_cond_init(&resolver_queue_cond, NULL);

107
    for(i = 0; i < 2; i++) {
chris's avatar
""    
chris committed
108
        n = (int*)xmalloc(sizeof *n);
109
110
111
        *n = i;
        pthread_create(&thread, NULL, (void*)&resolver_worker, (void*)n);
    }
pdw's avatar
iftop  
pdw committed
112
113
114
115
116

}

void resolve(struct in_addr* addr, char* result, int buflen) {
    char* hostname;
117
    int added = 0;
pdw's avatar
iftop  
pdw committed
118

119
    pthread_mutex_lock(&resolver_queue_mutex);
pdw's avatar
iftop  
pdw committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133

    if(hash_find(ns_hash, addr, (void**)&hostname) == HASH_STATUS_OK) {
        /* Found => already resolved, or on the queue */
    }
    else {
        hostname = strdup(inet_ntoa(*addr));
        hash_insert(ns_hash, addr, hostname);

        if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) {
            /* queue full */
        }
        else {
            resolve_queue[head] = *addr;
            head = (head + 1) % RESOLVE_QUEUE_LENGTH;
134
            added = 1;
pdw's avatar
iftop  
pdw committed
135
136
        }
    }
137
138
139
140
141
    pthread_mutex_unlock(&resolver_queue_mutex);

    if(added == 1) {
        pthread_cond_signal(&resolver_queue_cond);
    }
pdw's avatar
iftop  
pdw committed
142
143
144
145
146
147

    if(result != NULL && buflen > 1) {
        strncpy(result, hostname, buflen - 1);
        result[buflen - 1] = '\0';
    }
}