-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathnetradix.go
155 lines (127 loc) · 3.76 KB
/
netradix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package netradix
/*
#include "radix.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void
free_node_payload(radix_node_t *node, void *cbctx)
{
free(node->data);
}
void
destroy(radix_tree_t *tree)
{
Destroy_Radix(tree, free_node_payload, NULL);
}
radix_node_t*
make_node(radix_tree_t *tree, char *addr, const char **errmsg)
{
radix_node_t *node;
void *p;
prefix_t prefix;
p = prefix_pton(addr, -1, &prefix, errmsg);
if (p == NULL) {
return NULL;
}
node = radix_lookup(tree, &prefix);
return node;
}
*/
import "C"
import (
"errors"
"unsafe"
)
type NetRadixTree struct {
tree *C.radix_tree_t
}
// NewNetRadixTree creates new NetRadixTree structure.
// Return tuple in which the first element specifies tree structure and the second
// element specifies error object or nil if no error has occured.
func NewNetRadixTree() (*NetRadixTree, error) {
tree := &NetRadixTree{C.New_Radix()}
if tree == nil {
return nil, errors.New("couldn't create radix tree")
}
return tree, nil
}
// Close destroys radix tree.
func (rtree *NetRadixTree) Close() {
C.destroy(rtree.tree)
}
// Add adds network or subnet specification and user defined payload string to the radix tree.
// If no mask width is specified, the longest possible mask is assumed,
// i.e. 32 bits for IPv4 network and 128 bits for IPv6 network.
// On success, returns nil, otherwise returns error object.
func (rtree *NetRadixTree) Add(addr, udata string) error {
cstr := C.CString(addr)
defer C.free(unsafe.Pointer(cstr))
var errmsg *C.char
node := C.make_node(rtree.tree, cstr, &errmsg)
if node == nil {
return errors.New(C.GoString(errmsg))
}
node.data = unsafe.Pointer(C.CString(udata))
return nil
}
// SearchBest searches radix tree to find a matching node using usual subnetting rules
// for the address specified. If no mask width is specified, the longest possible mask
// for this type of address (IPv4 or IPv6) is assumed.
// Returns triple in which the first element indicates success of a search,
// the second element returns user payload (or empty string if not found)
// and the third element returns error object in case such an error occured or nil otherwise.
func (rtree *NetRadixTree) SearchBest(addr string) (found bool, udata string, err error) {
var prefix C.prefix_t
e := rtree.fillPrefix(&prefix, addr)
if e != nil {
return false, "", e
}
node := C.radix_search_best(rtree.tree, &prefix)
if node != nil {
return true, C.GoString((*C.char)(node.data)), nil
}
return false, "", nil
}
// SearchExact searches radix tree to find a matching node. Its semantics are the same as in SearchBest()
// method except that the addr must match a node exactly.
func (rtree *NetRadixTree) SearchExact(addr string) (found bool, udata string, err error) {
var prefix C.prefix_t
e := rtree.fillPrefix(&prefix, addr)
if e != nil {
return false, "", e
}
node := C.radix_search_exact(rtree.tree, &prefix)
if node != nil {
return true, C.GoString((*C.char)(node.data)), nil
}
return false, "", nil
}
// Remove deletes a node which exactly matches the address given.
// If no errors occured returns nil or error object otherwise.
func (rtree *NetRadixTree) Remove(addr string) error {
var prefix C.prefix_t
err := rtree.fillPrefix(&prefix, addr)
if err != nil {
return err
}
node := C.radix_search_exact(rtree.tree, &prefix)
if node != nil {
C.free(unsafe.Pointer(node.data))
C.radix_remove(rtree.tree, node)
}
return nil
}
func (rtree *NetRadixTree) fillPrefix(prefix *C.prefix_t, addr string) error {
cstr := C.CString(addr)
defer C.free(unsafe.Pointer(cstr))
var errmsg *C.char
ptr := C.prefix_pton(cstr, -1, prefix, &errmsg)
if ptr == nil {
return errors.New(C.GoString(errmsg))
}
return nil
}