1 
2 /*-
3  *
4  * New BSD License 2006
5  *
6  * Copyright (c) 2006, Jorgen Lundman
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are
11  * met:
12  *
13  * 1 Redistributions of source code must retain the above copyright
14  *   notice, this list of conditions and the following disclaimer.
15  * 2 Redistributions in binary form must reproduce the above
16  *   copyright notice, this list of conditions and the following
17  *   disclaimer in the documentation and/or other materials provided
18  *   with the distribution.
19  * 3 Neither the name of the stuff nor the names of its contributors
20  *   may be used to endorse or promote products derived from this
21  *   software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36 
37 // $Id: connections.c,v 1.13 2006/06/30 01:22:58 lundman Exp $
38 // Temporary connection space holder
39 // Jorgen Lundman November 5th, 1999
40 
41 
42 // As we get new connections, we need a few values and information to be
43 // stored with them. This is an example on how this could be achieved.
44 // Currently it is a simple linked list of nodes, one for each connection.
45 // Eventually, this with belong to a high connection database information
46 // module.
47 
48 // This module is more complicated to the casual reader than it really needs
49 // to be, but that is so that it can be as modular as possible.
50 // Although if you really want to achieve this, the linked list would have
51 // just nodes of "next" and "data" (void *) totally hiding data from this
52 // layer, as well as, hiding the implementation from the data-layer.
53 
54 #include <stdio.h>        // for defn of NULL
55 #include <stdlib.h>       // malloc
56 #include <string.h>       // memset
57 #include <time.h>
58 
59 #include "connections.h"
60 //#include "misc.h"
61 
62 // The start to the linked list, it's static as only we may touch it.
63 THREAD_SAFE static connection_t *connections_head = NULL;
64 
65 
66 // The main buffer size variable, so that we can change it on load.
67 unsigned int buffer_size = BUFFER_SIZE_DEFAULT;
68 
69 
70 
71 #include "lion.h" // Only for DEBUG define!!
72 
73 
74 
75 //
76 // Allocate and return a fresh Connection Holder.
77 //
78 // IN:  void
79 // OUT: pointer to a new node, added to the main linked list.
80 //
connections_new(void)81 connection_t *connections_new(void)
82 {
83   connection_t *result;
84 
85   //	printf("  head is at %p pointing to %p\n", &connections_head, connections_head);
86 
87   result = (connection_t *) malloc(sizeof (connection_t));
88 
89   if (!result) {
90 
91     perror("connections_new: malloc:");
92     exit(1);       // FIXME.
93 
94   }
95 
96 #ifdef DEBUG_VERBOSE
97   printf("Allocated new Connection %p\n", result);
98 #endif
99 
100   // clear it
101   memset(result, 0, sizeof(*result));
102 
103 
104   // Add it to linked list
105   result->next = connections_head;
106   connections_head = result;
107 
108 
109   // Allocate input buffer
110   result->buffer = (char *) malloc(buffer_size);
111 
112   if (!result->buffer) {
113 
114     perror("connections_new: buffer area malloc:");
115     exit(1);       // FIXME.
116 
117   }
118 
119 
120   // Allocate output buffer
121   result->obuffer = (char *) malloc(buffer_size);
122 
123   if (!result->obuffer) {
124 
125     perror("connections_new: buffer area malloc:");
126     exit(1);       // FIXME.
127 
128   }
129 
130   // Clear the buffers to avoid UMR
131   memset(result->buffer, 0, buffer_size);
132   memset(result->obuffer, 0, buffer_size);
133 
134   result->inbuffer_size = buffer_size;
135   result->outbuffer_size = buffer_size;
136 
137 
138   result->return_code = -1;  // -1 == unknown
139 
140 
141   // That's all, return it.
142   return result;
143 
144 }
145 
146 
147 //
148 // Free a connection node, and remove it from the linked list.
149 //
150 // IN:  connection ptr to be freed
151 // OUT: void
152 //
connections_free(connection_t * node)153 void connections_free(connection_t *node)
154 {
155   connection_t *runner, *prev;
156 
157   /* assert(!node); */
158   if (node->trace)
159 	  fprintf(trace_file, "%p: connections_free (node released)\n", node);
160 
161   if (node->trace)
162 	  lion_disable_trace(node);
163 
164 
165   // Free the buffer if it was allocated
166 
167   if (node->buffer) {
168 
169     free( node->buffer );
170     node->buffer = NULL;
171 
172   }
173 
174   if (node->obuffer) {
175 
176     free( node->obuffer );
177     node->obuffer = NULL;
178 
179   }
180 
181 #ifdef DEBUG_VERBOSE
182   printf("[releasing input/output buffers size %d / %d]\n",
183 		 node->inbuffer_size,
184 		 node->outbuffer_size);
185 #endif
186 
187 
188   for (prev = NULL, runner = connections_head;
189        runner;
190        prev = runner, runner = runner->next) {
191 
192 
193 	  if (runner == node) {  // This is the one to remove
194 
195 		  if (!prev) {
196 
197 			  // If no previous node, then it's at the start of the list
198 
199 			  connections_head = runner->next;
200 
201 		  } else {
202 
203 			  // In the middle somewhere
204 
205 			  prev->next = runner->next;
206 
207 		  }
208 
209 		  break;  // Stop spinning in the for-loop.
210 
211 	  } // if runner == node
212 
213   } // for
214 
215 
216 #ifdef DEBUG_VERBOSE
217   printf("Releasing %p\n", node);
218 #endif
219 
220 #ifdef DEBUG
221   memset(node, -1, sizeof(*node));
222 #endif
223 
224 
225   // Release it
226   free( node );
227 
228 }
229 
230 
231 
232 
233 
234 //
235 // Find a particular node, or, iterate the list.
236 //
237 // IN:  comparison function, expected to return 0 on match
238 // IN:  two optional arguments that are simply passed on
239 // OUT: pointer to matching node, or NULL if end reached
240 //
connections_find(int (* compare)(connection_t *,void *,void *),void * optarg1,void * optarg2)241 connection_t *connections_find( int (*compare)(connection_t *, void *, void *),
242 				void *optarg1, void *optarg2)
243 {
244   connection_t *runner;
245 
246   for (runner = connections_head; runner; runner = runner->next) {
247 
248     if (!compare(runner, optarg1, optarg2)) {
249 
250       // Found it, apparently
251       return runner;
252 
253     }
254 
255   }
256 
257   // Didn't find it
258   return NULL;
259 
260 }
261 
262 
263 
264 
265 
connections_dupe(connection_t * dst,connection_t * src)266 void connections_dupe(connection_t *dst, connection_t *src)
267 {
268 	// Copy over anything we need.
269 #define NODE_DUPE(X) dst->X = src->X
270 	NODE_DUPE(type);
271 	NODE_DUPE(socket);
272 	NODE_DUPE(status);
273 	NODE_DUPE(binary);
274 	NODE_DUPE(disable_read);
275 	NODE_DUPE(user_data);
276 	NODE_DUPE(rate_in);
277 	NODE_DUPE(rate_out);
278 	NODE_DUPE(time_start);
279 	NODE_DUPE(event_handler);
280 #ifdef WIN32
281 	NODE_DUPE(mutex);
282 	NODE_DUPE(file_socket);
283 	NODE_DUPE(start_address);
284 #endif
285 	// More to come
286 #undef NODE_DUPE
287 }
288 
289 
connections_cycle(void)290 void connections_cycle( void )
291 {
292 	connection_t *runner;
293 
294 	for (runner = connections_head; runner; runner = runner->next) {
295 
296 		if (!runner->next) {  // Last node.
297 
298 			if ( connections_head != runner ) { // Not the only thing in list.
299 
300 				// Find the last node, assign it to have a ->next pointing to
301 				// the first node in the list.
302 				runner->next = connections_head;
303 
304 				// Then we need to save the first node's ->next to re assign
305 				runner = connections_head->next;
306 
307 				// Set first node (now last) ->next to be NULL, EOL.
308 				connections_head->next = NULL;
309 
310 				// Re-assign the front of the list to point to 2nd node.
311 				connections_head = runner;
312 
313 				// and stop
314 				return;
315 
316 			}
317 
318 		}
319 
320 	}
321 
322 }
323