1 /* distcache, Distributed Session Caching technology
2  * Copyright (C) 2000-2003  Geoff Thorpe, and Cryptographic Appliances, Inc.
3  * Copyright (C) 2004       The Distcache.org project
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; using version 2.1 of the License. The copyright holders
8  * may elect to allow the application of later versions of the License to this
9  * software, please contact the author (geoff@distcache.org) if you wish us to
10  * review any later version released by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #define SYS_GENERATING_LIB
23 
24 #include <libsys/pre.h>
25 #include <libnal/nal.h>
26 #include "nal_internal.h"
27 #include <libsys/post.h>
28 
29 /*****************************************************/
30 /* First some global address-type registry stuff ... */
31 /*****************************************************/
32 
33 /* We make various address types automatically available by having them linked
34  * in by default. I'm simply "extern"ing a reference here to the builtin
35  * address type in proto_std.c, which will be our initial start-up list (its
36  * "next" pointer is NULL at start-up). This avoids having various functions
37  * pointing back and forth (that could get confused when exposing the
38  * "internal" API for address type providers), and it also avoids maintaining a
39  * separate table for registering address types (which would require the
40  * builtins to be registered by the application on startup and would also
41  * require cleanup on exit, both of which are undesirable). */
42 
43 extern NAL_ADDRESS_vtable builtin_sock_addr_vtable;
44 
45 /* API functions */
46 
NAL_ADDRESS_vtable_builtins(void)47 const NAL_ADDRESS_vtable *NAL_ADDRESS_vtable_builtins(void)
48 {
49 	return &builtin_sock_addr_vtable;
50 }
51 
NAL_ADDRESS_vtable_link(NAL_ADDRESS_vtable * vt)52 void NAL_ADDRESS_vtable_link(NAL_ADDRESS_vtable *vt)
53 {
54 	NAL_ADDRESS_vtable *i, *next;
55 	do {
56 		/* We do things this way so that we already have 'next' set
57 		 * as/when we NULL-terminate 'vt' for the linked-list. */
58 		next = vt->next;
59 		/* Check the existing global list doesn't have 'vt' */
60 		i = &builtin_sock_addr_vtable;
61 conflict_loop:
62 		if(strcmp(i->unique_name, vt->unique_name) == 0)
63 			/* Already got it, ignore 'vt' */
64 			continue;
65 		if(i->next) {
66 			i = i->next;
67 			goto conflict_loop;
68 		}
69 		/* Add 'vt' and null terminate */
70 		i->next = vt;
71 		vt->next = NULL;
72 	} while((vt = next) != NULL);
73 }
74 
75 /**********************************************************/
76 /* Now, on to nice (non-global) NAL_ADDRESS API stuff ... */
77 /**********************************************************/
78 
79 struct st_NAL_ADDRESS {
80 	/* Implementation (or NULL if not set) */
81 	const NAL_ADDRESS_vtable *vt;
82 	/* Implementation data */
83 	void *vt_data;
84 	/* Size of implementation data allocated */
85 	size_t vt_data_size;
86 	/* When resetting objects for reuse, this is set to allow 'vt' to be NULL */
87 	const NAL_ADDRESS_vtable *reset;
88 	/* def_buffer_size is handled directly by the API */
89 	unsigned int def_buffer_size;
90 };
91 
92 /*************************/
93 /* nal_devel.h functions */
94 /*************************/
95 
nal_address_set_vtable(NAL_ADDRESS * a,const NAL_ADDRESS_vtable * vtable)96 int nal_address_set_vtable(NAL_ADDRESS *a, const NAL_ADDRESS_vtable *vtable)
97 {
98 	/* Are we already mapped? */
99 	if(a->vt) {
100 		/* Notify the current vtable */
101 		if(a->vt->pre_close)
102 			a->vt->pre_close(a);
103 		/* Unmap the current usage */
104 		a->vt->on_reset(a);
105 		a->reset = a->vt;
106 		a->vt = NULL;
107 	}
108 	/* Do we have a mismatched reset to cleanup? */
109 	if(a->reset && (a->reset != vtable)) {
110 		a->reset->on_destroy(a);
111 		a->reset = NULL;
112 		SYS_zero_n(unsigned char, a->vt_data, a->vt_data_size);
113 	}
114 	/* Check our memory is ok (reset cases should already bypass this) */
115 	if(vtable->vtdata_size > a->vt_data_size) {
116 		assert(a->reset == NULL);
117 		if(a->vt_data)
118 			SYS_free(void, a->vt_data);
119 		a->vt_data = SYS_malloc(unsigned char, vtable->vtdata_size);
120 		if(!a->vt_data) {
121 			a->vt_data_size = 0;
122 			return 0;
123 		}
124 		a->vt_data_size = vtable->vtdata_size;
125 		SYS_zero_n(unsigned char, a->vt_data, vtable->vtdata_size);
126 	}
127 	if(vtable->on_create(a)) {
128 		a->vt = vtable;
129 		return 1;
130 	}
131 	return 0;
132 }
133 
nal_address_get_vtable(const NAL_ADDRESS * addr)134 const NAL_ADDRESS_vtable *nal_address_get_vtable(const NAL_ADDRESS *addr)
135 {
136 	return addr->vt;
137 }
138 
nal_address_get_vtdata(const NAL_ADDRESS * addr)139 void *nal_address_get_vtdata(const NAL_ADDRESS *addr)
140 {
141 	return addr->vt_data;
142 }
143 
nal_address_get_listener(const NAL_ADDRESS * addr)144 const NAL_LISTENER_vtable *nal_address_get_listener(const NAL_ADDRESS *addr)
145 {
146 	if(addr->vt) return addr->vt->create_listener(addr);
147 	return NULL;
148 }
149 
nal_address_get_connection(const NAL_ADDRESS * addr)150 const NAL_CONNECTION_vtable *nal_address_get_connection(const NAL_ADDRESS *addr)
151 {
152 	if(addr->vt) return addr->vt->create_connection(addr);
153 	return NULL;
154 }
155 
156 /*******************/
157 /* nal.h functions */
158 /*******************/
159 
NAL_ADDRESS_new(void)160 NAL_ADDRESS *NAL_ADDRESS_new(void)
161 {
162 	NAL_ADDRESS *a = SYS_malloc(NAL_ADDRESS, 1);
163 	if(a) {
164 		a->vt = NULL;
165 		a->vt_data = NULL;
166 		a->vt_data_size = 0;
167 		a->reset = NULL;
168 		a->def_buffer_size = 0;
169 	}
170 	return a;
171 }
172 
NAL_ADDRESS_free(NAL_ADDRESS * a)173 void NAL_ADDRESS_free(NAL_ADDRESS *a)
174 {
175 	if(a->vt) {
176 		if(a->vt->pre_close)
177 			a->vt->pre_close(a);
178 		a->vt->on_destroy(a);
179 	} else if(a->reset)
180 		a->reset->on_destroy(a);
181 	if(a->vt_data) SYS_free(void, a->vt_data);
182 	SYS_free(NAL_ADDRESS, a);
183 }
184 
NAL_ADDRESS_reset(NAL_ADDRESS * a)185 void NAL_ADDRESS_reset(NAL_ADDRESS *a)
186 {
187 	if(a->vt) {
188 		if(a->vt->pre_close)
189 			a->vt->pre_close(a);
190 		a->vt->on_reset(a);
191 		a->reset = a->vt;
192 		a->vt = NULL;
193 	}
194 }
195 
NAL_ADDRESS_get_def_buffer_size(const NAL_ADDRESS * addr)196 unsigned int NAL_ADDRESS_get_def_buffer_size(const NAL_ADDRESS *addr)
197 {
198 	return addr->def_buffer_size;
199 }
200 
NAL_ADDRESS_set_def_buffer_size(NAL_ADDRESS * addr,unsigned int def_buffer_size)201 int NAL_ADDRESS_set_def_buffer_size(NAL_ADDRESS *addr,
202 			unsigned int def_buffer_size)
203 {
204 	if(!nal_check_buffer_size(def_buffer_size)) return 0;
205 	addr->def_buffer_size = def_buffer_size;
206 	return 1;
207 }
208 
NAL_ADDRESS_create(NAL_ADDRESS * addr,const char * addr_string,unsigned int def_buffer_size)209 int NAL_ADDRESS_create(NAL_ADDRESS *addr, const char *addr_string,
210 			unsigned int def_buffer_size)
211 {
212 	unsigned int len;
213 	const NAL_ADDRESS_vtable *vtable = NAL_ADDRESS_vtable_builtins();
214 	if(addr->vt) return 0; /* 'addr' is in use */
215 	if(!NAL_ADDRESS_set_def_buffer_size(addr, def_buffer_size))
216 		return 0; /* 'def_buffer_size' is invalid */
217 	len = strlen(addr_string);
218 	if((len < 2) || (len > NAL_ADDRESS_MAX_STR_LEN))
219 		return 0; /* 'addr_string' can't be valid */
220 	while(vtable) {
221 		const char **pre = vtable->prefixes;
222 		while(*pre) {
223 			unsigned int pre_len = strlen(*pre);
224 			if((pre_len <= len) && (strncmp(*pre, addr_string,
225 							pre_len) == 0))
226 				goto done;
227 			pre++;
228 		}
229 		vtable = vtable->next; /* move to next address type */
230 	}
231 done:
232 	if(!vtable)
233 		return 0;
234 	if(!nal_address_set_vtable(addr, vtable) || !vtable->parse(addr, addr_string)) {
235 		NAL_ADDRESS_reset(addr);
236 		return 0;
237 	}
238 	return 1;
239 }
240 
NAL_ADDRESS_can_connect(const NAL_ADDRESS * addr)241 int NAL_ADDRESS_can_connect(const NAL_ADDRESS *addr)
242 {
243 	if(addr->vt) return addr->vt->can_connect(addr);
244 	return 0;
245 }
246 
NAL_ADDRESS_can_listen(const NAL_ADDRESS * addr)247 int NAL_ADDRESS_can_listen(const NAL_ADDRESS *addr)
248 {
249 	if(addr->vt) return addr->vt->can_listen(addr);
250 	return 0;
251 }
252 
253