resolver.c 3.85 KB
Newer Older
pdw's avatar
iftop  
pdw committed
1
2
3
4
5
/*
 * resolver.c:
 *
 */

pdw's avatar
pdw committed
6
#include <sys/types.h>
pdw's avatar
iftop  
pdw committed
7
#include <sys/socket.h>
pdw's avatar
pdw committed
8
#include <netinet/in.h>
pdw's avatar
iftop  
pdw committed
9
10
11
12
13
14
15
16
17
#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
18
#include "iftop.h"
pdw's avatar
iftop  
pdw committed
19

pdw's avatar
pdw committed
20
21
#include "threadprof.h"

pdw's avatar
iftop  
pdw committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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
36
/*    int thread_number = *(int*)ptr;*/
pdw's avatar
iftop  
pdw committed
37
38
    delay.tv_sec = 0;
    delay.tv_nsec = 500;
39
    pthread_mutex_lock(&resolver_queue_mutex);
chris's avatar
""    
chris committed
40
    sethostent(1);
pdw's avatar
iftop  
pdw committed
41
42
    while(1) {
        /* Wait until we are told that an address has been added to the 
chris's avatar
""    
chris committed
43
         * queue. */
pdw's avatar
iftop  
pdw committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
        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;

59
60
            pthread_mutex_unlock(&resolver_queue_mutex);

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

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

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

            /*  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
88
                    xfree(hostname);
pdw's avatar
iftop  
pdw committed
89
90
91
92
93
                }
                hostname = strdup(hp->h_name);
                hash_insert(ns_hash, &addr, (void*)hostname);

            }
chris's avatar
""    
chris committed
94
            xfree(tmphstbuf);
pdw's avatar
iftop  
pdw committed
95
96
97
98
99
        }
    }
}

void resolver_initialise() {
100
101
    int* n;
    int i;
pdw's avatar
iftop  
pdw committed
102
103
104
105
106
107
108
109
    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);

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

}

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

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

    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;
137
            added = 1;
pdw's avatar
iftop  
pdw committed
138
139
        }
    }
140
141
142
143
144
    pthread_mutex_unlock(&resolver_queue_mutex);

    if(added == 1) {
        pthread_cond_signal(&resolver_queue_cond);
    }
pdw's avatar
iftop  
pdw committed
145
146
147
148
149
150

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