Browse code

eXtended JABber module

Daniel-Constantin Mierla authored on 16/10/2002 14:12:42
Showing 20 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,492 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * JABBER module
4
+ *
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+
30
+
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <stdlib.h>
34
+#include <sys/types.h>
35
+#include <sys/ipc.h>
36
+#include <unistd.h>
37
+#include <fcntl.h>
38
+
39
+#include "../../sr_module.h"
40
+#include "../../error.h"
41
+#include "../../ut.h"
42
+#include "../../mem/shm_mem.h"
43
+#include "../../mem/mem.h"
44
+#include "../../globals.h"
45
+#include "../../parser/parse_uri.h"
46
+
47
+#include "../im/im_load.h"
48
+#include "../tm/tm_load.h"
49
+
50
+#include "xjab_worker.h"
51
+#include "xjab_util.h"
52
+#include "../../db/db.h"
53
+
54
+/** TM bind */
55
+struct tm_binds tmb;
56
+/** IM binds */
57
+struct im_binds imb;
58
+
59
+/** workers list */
60
+xj_wlist jwl = NULL;
61
+
62
+/** Structure that represents database connection */
63
+db_con_t** db_con;
64
+
65
+/** parameters */
66
+
67
+char *db_url   = "sql://root@127.0.0.1/sip_jab";
68
+char *db_table = "jusers";
69
+
70
+int nrw = 2;
71
+int max_jobs = 10;
72
+
73
+char *contact = "-";
74
+char *jaddress = "127.0.0.1";
75
+int jport = 5222;
76
+
77
+char *jaliases = NULL;
78
+
79
+int delay_time = 90;
80
+int sleep_time = 20;
81
+int cache_time = 600;
82
+
83
+int **pipes = NULL;
84
+
85
+static int mod_init(void);
86
+static int child_init(int rank);
87
+static int jab_send_message(struct sip_msg*, char*, char* );
88
+
89
+void destroy(void);
90
+
91
+struct module_exports exports= {
92
+	"jabber",
93
+	(char*[]){
94
+		"jab_send_message"
95
+	},
96
+	(cmd_function[]){
97
+		jab_send_message
98
+	},
99
+	(int[]){
100
+		0
101
+	},
102
+	(fixup_function[]){
103
+		0
104
+	},
105
+	1,
106
+
107
+	(char*[]) {   /* Module parameter names */
108
+		"contact",
109
+		"db_url",
110
+		"jaddress",
111
+		"aliases",
112
+		"jport",
113
+		"workers",
114
+		"max_jobs",
115
+		"cache_time",
116
+		"delay_time",
117
+		"sleep_time"
118
+	},
119
+	(modparam_t[]) {   /* Module parameter types */
120
+		STR_PARAM,
121
+		STR_PARAM,
122
+		STR_PARAM,
123
+		STR_PARAM,
124
+		INT_PARAM,
125
+		INT_PARAM,
126
+		INT_PARAM,
127
+		INT_PARAM,
128
+		INT_PARAM,
129
+		INT_PARAM
130
+	},
131
+	(void*[]) {   /* Module parameter variable pointers */
132
+		&contact,
133
+		&db_url,
134
+		&jaddress,
135
+		&jaliases,
136
+		&jport,
137
+		&nrw,
138
+		&max_jobs,
139
+		&cache_time,
140
+		&delay_time,
141
+		&sleep_time
142
+	},
143
+	10,      /* Number of module paramers */
144
+	
145
+	mod_init,   /* module initialization function */
146
+	(response_function) 0,
147
+	(destroy_function) destroy,
148
+	0,
149
+	child_init  /* per-child init function */
150
+};
151
+
152
+/**
153
+ * init module function
154
+ */
155
+static int mod_init(void)
156
+{
157
+	load_tm_f load_tm;
158
+	load_im_f load_im;
159
+	int  i;
160
+
161
+	DBG("XJAB:mod_init: initializing ...\n");
162
+
163
+	/* import mysql functions */
164
+	if (bind_dbmod())
165
+	{
166
+		DBG("XJAB:mod_init: error - database module not found\n");
167
+		return -1;
168
+	}
169
+	db_con = (db_con_t**)shm_malloc(nrw*sizeof(db_con_t*));
170
+	if (db_con == NULL)
171
+	{
172
+		DBG("XJAB:mod_init: Error while allocating db_con's\n");
173
+		return -1;
174
+	}
175
+
176
+	/* import the TM auto-loading function */
177
+	if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT))) {
178
+		LOG(L_ERR, "ERROR: xjab:mod_init: can't import load_tm\n");
179
+		return -1;
180
+	}
181
+	/* let the auto-loading function load all TM stuff */
182
+	if (load_tm( &tmb )==-1)
183
+		return -1;
184
+
185
+	/** import the IM auto-loading function */
186
+	if ( !(load_im=(load_im_f)find_export("load_im", 1))) 
187
+	{
188
+		LOG(L_ERR, "ERROR: sms: global_init: cannot import load_im\n");
189
+		return -1;
190
+	}
191
+	/* let the auto-loading function load all IM stuff */
192
+	if (load_im( &imb )==-1)
193
+		return -1;
194
+	
195
+	pipes = (int**)pkg_malloc(nrw*sizeof(int*));
196
+	if (pipes == NULL)
197
+	{
198
+		DBG("XJAB:mod_init: Error while allocating pipes\n");
199
+		return -1;
200
+	}
201
+	
202
+	for(i=0; i<nrw; i++)
203
+	{
204
+		pipes[i] = (int*)pkg_malloc(2*sizeof(int));
205
+		if (!pipes[i])
206
+		{
207
+			DBG("XJAB:mod_init: Error while allocating pipes\n");
208
+			return -1;
209
+		}
210
+	}
211
+	
212
+	for(i=0; i<nrw; i++)
213
+	{
214
+		db_con[i] = db_init(db_url);
215
+		if (!db_con[i])
216
+		{
217
+			DBG("XJAB:mod_init: Error while connecting database\n");
218
+			return -1;
219
+		}
220
+		else
221
+		{
222
+			db_use_table(db_con[i], db_table);
223
+			DBG("XJAB:mod_init: Database connection opened successfuly\n");
224
+		}
225
+	}
226
+
227
+	
228
+	/** creating the pipees */
229
+	
230
+	for(i=0;i<nrw;i++)
231
+	{
232
+		/* create the pipe*/
233
+		if (pipe(pipes[i])==-1) {
234
+			DBG("XJAB:mod_init: error - cannot create pipe!\n");
235
+			return -1;
236
+		}
237
+		DBG("XJAB:mod_init: pipe[%d] = <%d>-<%d>\n", i, pipes[i][0],
238
+			pipes[i][1]);
239
+	}
240
+	
241
+	if((jwl = xj_wlist_init(pipes, nrw, max_jobs)) == NULL)
242
+	{
243
+		DBG("XJAB:mod_init: error initializing workers list\n");
244
+		return -1;
245
+	}
246
+	
247
+	if(xj_wlist_init_contact(jwl, contact) < 0)
248
+	{
249
+		DBG("XJAB:mod_init: error initializing workers list properties\n");
250
+		return -1;
251
+	}
252
+
253
+	if(xj_wlist_set_aliases(jwl, jaliases) < 0)
254
+	{
255
+		DBG("XJAB:mod_init: error setting aliases\n");
256
+		return -1;
257
+	}
258
+	
259
+	DBG("XJAB:mod_init: initialized ...\n");	
260
+	return 0;
261
+}
262
+
263
+/*
264
+ * Initialize childs
265
+ */
266
+static int child_init(int rank)
267
+{
268
+	int i;
269
+	int *pids = NULL;
270
+	
271
+	DBG("XJAB:child_init: initializing child <%d>\n", rank);
272
+	if(rank == 0)
273
+	{
274
+		pids = (int*)pkg_malloc(nrw*sizeof(int));
275
+		if (pids == NULL)
276
+		{
277
+			DBG("XJAB:child_init: error while allocating pid's\n");
278
+			return -1;
279
+		}
280
+		/** launching the workers */
281
+		for(i=0;i<nrw;i++)
282
+		{
283
+			if ( (pids[i]=fork())<0 )
284
+			{
285
+				DBG("XJAB:child_init: error - cannot launch worker\n");
286
+				return -1;
287
+			}
288
+			if (pids[i] == 0)
289
+			{
290
+				close(pipes[i][1]);
291
+				xj_worker_process(jwl, jaddress, jport, pipes[i][0], max_jobs,
292
+					cache_time,	sleep_time, delay_time, db_con[i]);
293
+				exit(0);
294
+			}
295
+		}
296
+	
297
+		if(xj_wlist_set_pids(jwl, pids, nrw) < 0)
298
+		{
299
+			DBG("XJAB:child_init: error setting pid's\n");
300
+			return -1;
301
+		}
302
+		if(pids)
303
+			pkg_free(pids);
304
+	}
305
+	
306
+	if(pipes)
307
+	{
308
+		for(i=0;i<nrw;i++)
309
+			close(pipes[i][0]);
310
+	}
311
+	return 0;
312
+}
313
+
314
+/**
315
+ * send the SIP message through Jabber
316
+ */
317
+static int jab_send_message(struct sip_msg *msg, char* foo1, char * foo2)
318
+{
319
+	str body, dst, /*host, user,*/ *p;
320
+	xj_sipmsg jsmsg;
321
+	struct to_body to, from;
322
+	struct sip_uri _uri;
323
+	int pipe, fl;
324
+
325
+	// extract message body - after that whole SIP MESSAGE is parsed
326
+	if ( imb.im_extract_body(msg,&body)==-1 )
327
+	{
328
+		LOG(L_ERR,"ERROR:XJAB:xjab_send_message: cannot extract body"
329
+				" from sip msg!\n");
330
+		goto error;
331
+	}
332
+	// check for FROM header
333
+	if(msg->from != NULL)
334
+	{
335
+		memset( &from , 0, sizeof(from) );
336
+		parse_to(msg->from->body.s, msg->from->body.s + msg->from->body.len+1,
337
+						&from);
338
+		if(from.error == PARSE_OK)
339
+			DBG("XJAB: xjab_send_message: From parsed OK.\n");
340
+		else
341
+		{
342
+			DBG("XJAB: xjab_send_message: From NOT parsed\n");
343
+			goto error;
344
+		}
345
+	}
346
+	else
347
+	{
348
+		DBG("XJAB: xjab_send_message: cannot find FROM HEADER!\n");
349
+		goto error;
350
+	}
351
+	// get the communication pipe with the worker
352
+	if((pipe = xj_wlist_get(jwl, &from.uri, &p)) < 0)
353
+	{
354
+		DBG("XJAB: xjab_send_message: cannot find pipe of the worker!\n");
355
+		goto error;
356
+	}
357
+	
358
+	// determination of destination
359
+	dst.len = 0;
360
+	if( msg->new_uri.len > 0 )
361
+	{
362
+		DBG("XJAB: xjab_send_message: using NEW URI for destination\n");
363
+		dst.s = msg->new_uri.s;
364
+		dst.len = msg->new_uri.len;
365
+	} else if ( msg->first_line.u.request.uri.len > 0 )
366
+	{
367
+		DBG("XJAB: xjab_send_message: parsing URI from first line\n");
368
+		if(parse_uri(msg->first_line.u.request.uri.s,
369
+					msg->first_line.u.request.uri.len, &_uri) < 0)
370
+		{
371
+			DBG("XJAB: xjab_send_message: ERROR parsing URI from first line\n");
372
+			goto error;
373
+		}
374
+		if(_uri.user.len > 0)
375
+		{
376
+			DBG("XJAB: xjab_send_message: using URI for destination\n");
377
+			dst.s = msg->first_line.u.request.uri.s;
378
+			dst.len = msg->first_line.u.request.uri.len;
379
+		}
380
+		free_uri(&_uri);
381
+	}
382
+	if(dst.len == 0 && msg->to != NULL)
383
+	{
384
+		memset( &to , 0, sizeof(to) );
385
+		parse_to(msg->to->body.s, msg->to->body.s + msg->to->body.len + 1,
386
+				&to);
387
+		if(to.uri.len > 0) // to.error == PARSE_OK)
388
+		{
389
+			DBG("XJAB: xjab_send_message: TO parsed OK <%.*s>.\n",
390
+				to.uri.len, to.uri.s);
391
+			dst.s = to.uri.s;
392
+			dst.len = to.uri.len;
393
+		}
394
+		else
395
+		{
396
+			DBG("XJAB: xjab_send_message: TO NOT parsed\n");
397
+			goto error;
398
+		}
399
+	}
400
+	if(dst.len == 0)
401
+	{
402
+		DBG("XJAB: xjab_send_message: destination not found in SIP message\n");
403
+		goto error;
404
+	}
405
+	
406
+	/** skip 'sip:' in destination address */
407
+	if(dst.s[0]=='s' && dst.s[1]=='i' && dst.s[2]=='p')
408
+	{
409
+		dst.s += 3;
410
+		dst.len -= 3;
411
+		fl = 1;
412
+		while(*dst.s == ' ' || *dst.s == '\t' || *dst.s == ':')
413
+		{
414
+			dst.s++;
415
+			dst.len--;
416
+			fl = 0;
417
+		}
418
+		if(fl)
419
+		{
420
+			dst.s -= 3;
421
+			dst.len += 3;
422
+		}
423
+		
424
+		DBG("XJAB: xjab_send_message: DESTINATION corrected <%.*s>.\n", 
425
+				dst.len, dst.s);
426
+	}
427
+	
428
+	//putting the SIP message parts in share memory to be accessible by workers
429
+    jsmsg = (xj_sipmsg)shm_malloc(sizeof(t_xj_sipmsg));
430
+    if(jsmsg == NULL)
431
+    	return -1;
432
+	jsmsg->to.len = dst.len;
433
+	jsmsg->to.s = (char*)shm_malloc(jsmsg->to.len+1);
434
+	if(jsmsg->to.s == NULL)
435
+	{
436
+		shm_free(jsmsg);
437
+		goto error;
438
+	}
439
+	strncpy(jsmsg->to.s, dst.s, jsmsg->to.len);
440
+	
441
+	jsmsg->msg.len = body.len;
442
+	jsmsg->msg.s = (char*)shm_malloc(jsmsg->msg.len+1);
443
+	if(jsmsg->msg.s == NULL)
444
+	{
445
+		shm_free(jsmsg->to.s);
446
+		shm_free(jsmsg);
447
+		goto error;
448
+	}
449
+	strncpy(jsmsg->msg.s, body.s, jsmsg->msg.len);
450
+	
451
+	jsmsg->from = p;
452
+	
453
+	DBG("XJAB: xjab_send_message:%d: sending <%p> to worker through <%d>\n",
454
+			getpid(), jsmsg, pipe);
455
+	// sending the SHM pointer of SIP message to the worker
456
+	if(write(pipe, &jsmsg, sizeof(jsmsg)) != sizeof(jsmsg))
457
+	{
458
+		DBG("XJAB: xjab_send_message: error when writting to worker pipe!\n");
459
+		goto error;
460
+	}
461
+	
462
+	return 1;
463
+error:
464
+	return -1;
465
+}
466
+
467
+/**
468
+ * destroy function of module
469
+ */
470
+void destroy(void)
471
+{
472
+	int i;
473
+	DBG("XJAB: Unloading module ...\n");
474
+	if(pipes)
475
+	{
476
+		for(i = 0; i < nrw; i++)
477
+			pkg_free(pipes[i]);
478
+		pkg_free(pipes);
479
+	}
480
+	// cleaning MySQL connections
481
+	if(db_con != NULL)
482
+	{
483
+		for(i = 0; i<nrw; i++)
484
+			db_close(db_con[i]);
485
+		shm_free(db_con);
486
+	}
487
+			
488
+	xj_wlist_free(jwl);
489
+	DBG("XJAB: Unloaded\n");
490
+}
491
+
0 492
new file mode 100644
... ...
@@ -0,0 +1,160 @@
0
+/* 
1
+ * $Id$
2
+ *
3
+ *
4
+ * Copyright (C) 2001-2003 Fhg Fokus
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+
29
+#include <errno.h>
30
+
31
+#include "lock.h"
32
+#include "../../dprint.h"
33
+
34
+
35
+#ifdef FAST_LOCK
36
+#include "../../mem/shm_mem.h"
37
+#endif
38
+
39
+
40
+#ifndef FAST_LOCK
41
+
42
+
43
+
44
+/* return -1 if semget failed, -2 if semctl failed */
45
+static int init_semaphore_set( int size )
46
+{
47
+	int new_semaphore, i;
48
+
49
+	new_semaphore=semget ( IPC_PRIVATE, size, IPC_CREAT | IPC_PERMISSIONS );
50
+	if (new_semaphore==-1) {
51
+		DBG("DEBUG: init_semaphore_set(%d):  failure to allocate a"
52
+					" semaphore: %s\n", size, strerror(errno));
53
+		return -1;
54
+	}
55
+	for (i=0; i<size; i++) {
56
+		union semun {
57
+			int val;
58
+			struct semid_ds *buf;
59
+			ushort *array;
60
+		} argument;
61
+		/* binary lock */
62
+		argument.val = +1;
63
+		if (semctl( new_semaphore, i , SETVAL , argument )==-1) {
64
+			DBG("DEBUG: init_semaphore_set:  failure to "
65
+				"initialize a semaphore: %s\n", strerror(errno));
66
+			if (semctl( entry_semaphore, 0 , IPC_RMID , 0 )==-1)
67
+				DBG("DEBUG: init_semaphore_set:  failure to release"
68
+					" a semaphore\n");
69
+			return -2;
70
+		}
71
+	}
72
+	return new_semaphore;
73
+}
74
+
75
+
76
+
77
+int change_semaphore( smart_lock *s  , int val )
78
+{
79
+	struct sembuf pbuf;
80
+	int r;
81
+
82
+	pbuf.sem_num = s->semaphore_index ;
83
+	pbuf.sem_op =val;
84
+	pbuf.sem_flg = 0;
85
+
86
+tryagain:
87
+	r=semop( s->semaphore_set, &pbuf ,  1 /* just 1 op */ );
88
+
89
+	if (r==-1) {
90
+		if (errno==EINTR) {
91
+			DBG("signal received in a semaphore\n");
92
+			goto tryagain;
93
+		} else {
94
+			LOG(L_CRIT, "ERROR: change_semaphore_pike(%x, %x, 1) : %s\n",
95
+					s->semaphore_set, &pbuf,
96
+					strerror(errno));
97
+		}
98
+	}
99
+	return r;
100
+}
101
+#endif  /* !FAST_LOCK*/
102
+
103
+
104
+
105
+/* creats NR locks; return 0 if error
106
+*/
107
+smart_lock* create_semaphores(int nr)
108
+{
109
+	int        i;
110
+	smart_lock  *lock_set;
111
+#ifndef FAST_LOCK
112
+	int        sem_set;
113
+#endif
114
+
115
+	lock_set = (smart_lock*)shm_malloc(nr*sizeof(smart_lock));
116
+	if (lock_set==0){
117
+		LOG(L_CRIT, "ERROR: pike_create_semaphores: out of pkg mem\n");
118
+		goto error;
119
+	}
120
+#ifdef FAST_LOCK
121
+	for(i=0;i<nr;i++) 
122
+		init_lock(lock_set[i]);
123
+#else
124
+	if ((sem_set=init_semaphore_set(nr))<0) {
125
+		LOG(L_CRIT, "ERROR: pike_create_semaphores: semaphores "
126
+			"initialization failure: %s\n",strerror(errno));
127
+		goto error;
128
+	}
129
+
130
+	for (i=0; i<nr; i++) {
131
+		lock_set[i].semaphore_set = sem_set;
132
+		lock_set[i].semaphore_index = i;
133
+	}
134
+#endif
135
+	return lock_set;
136
+error:
137
+	return 0;
138
+}
139
+
140
+
141
+
142
+void destroy_semaphores(smart_lock *sem_set)
143
+{
144
+#ifdef FAST_LOCK
145
+	/* must check if someone uses them, for now just leave them allocated*/
146
+	LOG(L_INFO, "INFO: lock_cleanup:  clean-up still not implemented"
147
+		" properly \n");
148
+#else
149
+	LOG(L_INFO, "INFO: lock_cleanup:  clean-up still not implemented"
150
+		" properly (no sibling check)\n");
151
+	/* sibling double-check missing here; install a signal handler */
152
+
153
+	if (sem_set && semctl( sem_set[0].entry_semaphore,0,IPC_RMID,0)==-1)
154
+		LOG(L_ERR, "ERROR: lock_cleanup, entry_semaphore cleanup failed\n");
155
+#endif
156
+	shm_free((void*)sem_set);
157
+	sem_set = 0;
158
+}
159
+
0 160
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+/* 
1
+ * $Id$
2
+ *
3
+ *
4
+ * Copyright (C) 2001-2003 Fhg Fokus
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+
29
+#ifndef _SMART_LOCK_H_
30
+#define _SMART_LOCK_H_
31
+
32
+#include <sys/types.h>
33
+#include <sys/ipc.h>
34
+#include <sys/sem.h>
35
+#include "../../dprint.h"
36
+#ifdef  FAST_LOCK
37
+#include "../../fastlock.h"
38
+#endif
39
+
40
+
41
+
42
+#ifdef FAST_LOCK
43
+#define smart_lock fl_lock_t
44
+#else
45
+typedef struct _smart_lock{
46
+	int semaphore_set;
47
+	int semaphore_index;
48
+} smart_lock;
49
+#endif
50
+
51
+
52
+
53
+#ifndef FAST_LOCK
54
+int change_semaphore( smart_lock *s  , int val );
55
+#endif
56
+
57
+smart_lock* create_semaphores(int nr);
58
+void destroy_semaphores(smart_lock *sem_set);
59
+
60
+
61
+
62
+/* lock semaphore s */
63
+static inline int s_lock( smart_lock *s )
64
+{
65
+#ifdef FAST_LOCK
66
+	get_lock(s);
67
+	return 0;
68
+#else
69
+	return change_semaphore( s, -1 );
70
+#endif
71
+}
72
+
73
+
74
+/* ulock semaphore */
75
+static inline int s_unlock( smart_lock *s )
76
+{
77
+#ifdef FAST_LOCK
78
+	release_lock(s);
79
+	return 0;
80
+#else
81
+	return change_semaphore( s, +1 );
82
+#endif
83
+}
84
+
85
+/* lock semaphore s */
86
+static inline int s_lock_at(smart_lock *s, int i)
87
+{
88
+	DBG("JABBER: s_lock_at: <%d>\n", i);
89
+#ifdef FAST_LOCK
90
+	get_lock(&s[i]);
91
+	return 0;
92
+#else
93
+	return change_semaphore( &s[i], -1 );
94
+#endif
95
+}
96
+
97
+
98
+/* ulock semaphore */
99
+static inline int s_unlock_at(smart_lock *s, int i)
100
+{
101
+	DBG("JABBER: s_unlock_at: <%d>\n", i);
102
+#ifdef FAST_LOCK
103
+	release_lock(&s[i]);
104
+	return 0;
105
+#else
106
+	return change_semaphore( &s[i], +1 );
107
+#endif
108
+}
109
+
110
+#endif
0 111
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+/* 
1
+ * $Id$
2
+ *
3
+ *
4
+ * Copyright (C) 2001-2003 Fhg Fokus
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+
28
+
29
+
30
+/***************************************************************************
31
+                          mdefines.h  -  description
32
+                             -------------------
33
+    author               : Daniel-Constantin MIERLA
34
+    email                : mierla@fokus.fhg.de
35
+    organization         : FhI FOKUS, BERLIN
36
+ ***************************************************************************/
37
+
38
+#ifndef _mdefines_h_
39
+#define _mdefines_h_
40
+
41
+#define _M_PRINTF	printf
42
+#define _M_CALLOC 	calloc
43
+#define _M_REALLOC	realloc
44
+
45
+#define _M_MALLOC 	pkg_malloc
46
+#define _M_FREE		pkg_free
47
+
48
+#define _M_SHM_MALLOC 	shm_malloc
49
+#define _M_SHM_FREE		shm_free
50
+
51
+#endif
0 52
new file mode 100644
... ...
@@ -0,0 +1,263 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ * 
17
+ *  Gabber
18
+ *  Copyright (C) 1999-2000 Dave Smith & Julian Missig
19
+ *
20
+ */
21
+
22
+
23
+
24
+/* 
25
+   Implements the Secure Hash Algorithm (SHA1)
26
+
27
+   Copyright (C) 1999 Scott G. Miller
28
+
29
+   Released under the terms of the GNU General Public License v2
30
+   see file COPYING for details
31
+
32
+   Credits: 
33
+      Robert Klep <robert@ilse.nl>  -- Expansion function fix 
34
+	  Thomas "temas" Muldowney <temas@box5.net>:
35
+	  		-- shahash() for string fun
36
+			-- Will add the int32 stuff in a few
37
+	  		
38
+   ---
39
+   FIXME: This source takes int to be a 32 bit integer.  This
40
+   may vary from system to system.  I'd use autoconf if I was familiar
41
+   with it.  Anyone want to help me out?
42
+*/
43
+
44
+//#include <config.h>
45
+
46
+#include <stdio.h>
47
+#include <stdlib.h>
48
+#include <fcntl.h>
49
+#include <string.h>
50
+
51
+#ifndef MACOS
52
+#  include <sys/stat.h>
53
+#  include <sys/types.h>
54
+#endif
55
+#ifndef WIN32
56
+#  include <unistd.h>
57
+#  define INT64 long long
58
+#else
59
+#  define snprintf _snprintf
60
+#  define INT64 __int64
61
+#endif
62
+
63
+#define switch_endianness(x) (x<<24 & 0xff000000) | \
64
+                             (x<<8  & 0x00ff0000) | \
65
+                             (x>>8  & 0x0000ff00) | \
66
+                             (x>>24 & 0x000000ff)
67
+
68
+/* Initial hash values */
69
+#define Ai 0x67452301 
70
+#define Bi 0xefcdab89
71
+#define Ci 0x98badcfe
72
+#define Di 0x10325476
73
+#define Ei 0xc3d2e1f0
74
+
75
+/* SHA1 round constants */
76
+#define K1 0x5a827999
77
+#define K2 0x6ed9eba1
78
+#define K3 0x8f1bbcdc 
79
+#define K4 0xca62c1d6
80
+
81
+/* Round functions.  Note that f2() is used in both rounds 2 and 4 */
82
+#define f1(B,C,D) ((B & C) | ((~B) & D))
83
+#define f2(B,C,D) (B ^ C ^ D)
84
+#define f3(B,C,D) ((B & C) | (B & D) | (C & D))
85
+
86
+/* left circular shift functions (rotate left) */
87
+#define rol1(x) ((x<<1) | ((x>>31) & 1))
88
+#define rol5(A) ((A<<5) | ((A>>27) & 0x1f))
89
+#define rol30(B) ((B<<30) | ((B>>2) & 0x3fffffff))
90
+
91
+/*
92
+  Hashes 'data', which should be a pointer to 512 bits of data (sixteen
93
+  32 bit ints), into the ongoing 160 bit hash value (five 32 bit ints)
94
+  'hash'
95
+*/
96
+int 
97
+sha_hash(int *data, int *hash)  
98
+{
99
+  int W[80];
100
+  unsigned int A=hash[0], B=hash[1], C=hash[2], D=hash[3], E=hash[4];
101
+  unsigned int t, x, TEMP;
102
+
103
+  for (t=0; t<16; t++) 
104
+    {
105
+#ifndef WORDS_BIGENDIAN
106
+      W[t]=switch_endianness(data[t]);
107
+#else 
108
+      W[t]=data[t];
109
+#endif
110
+    }
111
+
112
+
113
+  /* SHA1 Data expansion */
114
+  for (t=16; t<80; t++) 
115
+    {
116
+      x=W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
117
+      W[t]=rol1(x);
118
+    }
119
+
120
+  /* SHA1 main loop (t=0 to 79) 
121
+   This is broken down into four subloops in order to use
122
+   the correct round function and constant */
123
+  for (t=0; t<20; t++) 
124
+    {
125
+      TEMP=rol5(A) + f1(B,C,D) + E + W[t] + K1;
126
+      E=D;
127
+      D=C;
128
+      C=rol30(B);
129
+      B=A;
130
+      A=TEMP;
131
+    }
132
+  for (; t<40; t++) 
133
+    {
134
+      TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K2;
135
+      E=D;
136
+      D=C;
137
+      C=rol30(B);
138
+      B=A;
139
+      A=TEMP;
140
+    }
141
+  for (; t<60; t++) 
142
+    {
143
+      TEMP=rol5(A) + f3(B,C,D) + E + W[t] + K3;
144
+      E=D;
145
+      D=C;
146
+      C=rol30(B);
147
+      B=A;
148
+      A=TEMP;
149
+    }
150
+  for (; t<80; t++) 
151
+    {
152
+      TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K4;
153
+      E=D;
154
+      D=C;
155
+      C=rol30(B);
156
+      B=A;
157
+      A=TEMP;
158
+    }
159
+  hash[0]+=A; 
160
+  hash[1]+=B;
161
+  hash[2]+=C;
162
+  hash[3]+=D;
163
+  hash[4]+=E;
164
+  return 0;
165
+}
166
+
167
+/*
168
+  Takes a pointer to a 160 bit block of data (five 32 bit ints) and
169
+  intializes it to the start constants of the SHA1 algorithm.  This
170
+  must be called before using hash in the call to sha_hash
171
+*/
172
+int 
173
+sha_init(int *hash) 
174
+{
175
+  hash[0]=Ai;
176
+  hash[1]=Bi;
177
+  hash[2]=Ci;
178
+  hash[3]=Di;
179
+  hash[4]=Ei;
180
+  return 0;
181
+}
182
+
183
+int strprintsha(char *dest, int *hashval) 
184
+{
185
+	int x;
186
+	char *hashstr = dest;
187
+	for (x=0; x<5; x++) 
188
+	{
189
+		snprintf(hashstr, 9, "%08x", hashval[x]);
190
+		hashstr+=8;
191
+	}
192
+	/*old way */
193
+	//snprintf(hashstr++, 1, "\0");
194
+	/*new way - by bogdan*/
195
+	*hashstr = 0;
196
+
197
+	return 0;
198
+}
199
+
200
+char *shahash(const char *str) 
201
+{
202
+	char read_buffer[65];
203
+	//int read_buffer[64];
204
+	int c=1, i;
205
+       
206
+	INT64 length=0;
207
+
208
+	int strsz;
209
+	static char final[40];
210
+	int *hashval;
211
+
212
+	hashval = (int *)malloc(20);
213
+
214
+	sha_init(hashval);
215
+
216
+	strsz = strlen(str);
217
+
218
+	if(strsz == 0) 
219
+	{
220
+	     memset(read_buffer, 0, 65);
221
+	     read_buffer[0] = 0x80;
222
+	     sha_hash((int *)read_buffer, hashval);
223
+	}
224
+
225
+	while (strsz>0) 
226
+	{
227
+		memset(read_buffer, 0, 65);
228
+		strncpy((char*)read_buffer, str, 64);
229
+		c = strlen((char *)read_buffer);
230
+		length+=c;
231
+		strsz-=c;
232
+		if (strsz<=0) 
233
+		{
234
+			length<<=3;	
235
+			read_buffer[c]=(char)0x80;
236
+			for (i=c+1; i<64; i++) 
237
+				read_buffer[i]=0;
238
+			if (c>55) 
239
+			{
240
+				/* we need to do an entire new block */
241
+				sha_hash((int *)read_buffer, hashval);
242
+				for (i=0; i<14; i++) 
243
+					((int*)read_buffer)[i]=0;
244
+			}      
245
+#ifndef WORDS_BIGENDIAN
246
+			for (i=0; i<8; i++) 
247
+			{
248
+				read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff;
249
+			}
250
+#else	
251
+			memcpy(read_buffer+56, &length, 8);
252
+#endif
253
+		}
254
+		
255
+		sha_hash((int *)read_buffer, hashval);
256
+		str+=64;
257
+	}
258
+
259
+	strprintsha((char *)final, hashval);
260
+	free(hashval);
261
+	return (char *)final;
262
+}
0 263
new file mode 100644
... ...
@@ -0,0 +1,1418 @@
0
+/*
1
+ * tree234.c: reasonably generic counted 2-3-4 tree routines.
2
+ * 
3
+ * This file is copyright 1999-2001 Simon Tatham.
4
+ * 
5
+ * Permission is hereby granted, free of charge, to any person
6
+ * obtaining a copy of this software and associated documentation
7
+ * files (the "Software"), to deal in the Software without
8
+ * restriction, including without limitation the rights to use,
9
+ * copy, modify, merge, publish, distribute, sublicense, and/or
10
+ * sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following
12
+ * conditions:
13
+ * 
14
+ * The above copyright notice and this permission notice shall be
15
+ * included in all copies or substantial portions of the Software.
16
+ * 
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
21
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
22
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ */
27
+
28
+
29
+#include <stdio.h>
30
+#include <stdlib.h>
31
+#include <assert.h>
32
+
33
+#include "tree234.h"
34
+#include "../../mem/shm_mem.h"
35
+
36
+//#define smalloc malloc
37
+//#define sfree free
38
+#define smalloc shm_malloc
39
+#define sfree 	shm_free
40
+
41
+#define mknew(typ) ( (typ *) smalloc (sizeof (typ)) )
42
+
43
+#ifdef TEST
44
+#define LOG123(x) (printf x)
45
+#else
46
+#define LOG123(x)
47
+#endif
48
+
49
+typedef struct node234_Tag node234;
50
+
51
+struct tree234_Tag {
52
+    node234 *root;
53
+    cmpfn234 cmp;
54
+};
55
+
56
+struct node234_Tag {
57
+    node234 *parent;
58
+    node234 *kids[4];
59
+    int counts[4];
60
+    void *elems[3];
61
+};
62
+
63
+/*
64
+ * Create a 2-3-4 tree.
65
+ */
66
+tree234 *newtree234(cmpfn234 cmp) {
67
+    tree234 *ret = mknew(tree234);
68
+    LOG123(("created tree %p\n", ret));
69
+    ret->root = NULL;
70
+    ret->cmp = cmp;
71
+    return ret;
72
+}
73
+
74
+/*
75
+ * Free a 2-3-4 tree (not including freeing the elements).
76
+ */
77
+static void freenode234(node234 *n) {
78
+    if (!n)
79
+	return;
80
+    freenode234(n->kids[0]);
81
+    freenode234(n->kids[1]);
82
+    freenode234(n->kids[2]);
83
+    freenode234(n->kids[3]);
84
+    sfree(n);
85
+}
86
+void freetree234(tree234 *t)
87
+{
88
+    if(t == NULL)
89
+    	return;
90
+    freenode234(t->root);
91
+    sfree(t);
92
+}
93
+
94
+/*
95
+ * Free a 2-3-4 tree (including freeing the elements with 'fn' function).
96
+ */
97
+static void free2node234(node234 *n, freefn fn )
98
+{
99
+    if (!n)
100
+	return;
101
+    free2node234(n->kids[0], fn);
102
+    free2node234(n->kids[1], fn);
103
+    free2node234(n->kids[2], fn);
104
+    free2node234(n->kids[3], fn);
105
+    fn(n->elems[0]);
106
+    fn(n->elems[1]);
107
+    fn(n->elems[2]);
108
+    sfree(n);
109
+}
110
+void free2tree234(tree234 *t, freefn fn)
111
+{
112
+    if(t == NULL)
113
+    	return;
114
+    free2node234(t->root, fn);
115
+    sfree(t);
116
+}
117
+
118
+
119
+/*
120
+ * Internal function to count a node.
121
+ */
122
+static int countnode234(node234 *n) {
123
+    int count = 0;
124
+    int i;
125
+    if (!n)
126
+	return 0;
127
+    for (i = 0; i < 4; i++)
128
+	count += n->counts[i];
129
+    for (i = 0; i < 3; i++)
130
+	if (n->elems[i])
131
+	    count++;
132
+    return count;
133
+}
134
+
135
+/*
136
+ * Count the elements in a tree.
137
+ */
138
+int count234(tree234 *t) {
139
+    if (t->root)
140
+	return countnode234(t->root);
141
+    else
142
+	return 0;
143
+}
144
+
145
+/*
146
+ * Add an element e to a 2-3-4 tree t. Returns e on success, or if
147
+ * an existing element compares equal, returns that.
148
+ */
149
+static void *add234_internal(tree234 *t, void *e, int index) {
150
+    node234 *n, **np, *left, *right;
151
+    void *orig_e = e;
152
+    int c, lcount, rcount;
153
+
154
+    LOG123(("adding node %p to tree %p\n", e, t));
155
+    if (t->root == NULL) {
156
+	t->root = mknew(node234);
157
+	t->root->elems[1] = t->root->elems[2] = NULL;
158
+	t->root->kids[0] = t->root->kids[1] = NULL;
159
+	t->root->kids[2] = t->root->kids[3] = NULL;
160
+	t->root->counts[0] = t->root->counts[1] = 0;
161
+	t->root->counts[2] = t->root->counts[3] = 0;
162
+	t->root->parent = NULL;
163
+	t->root->elems[0] = e;
164
+	LOG123(("  created root %p\n", t->root));
165
+	return orig_e;
166
+    }
167
+
168
+    np = &t->root;
169
+    while (*np) {
170
+	int childnum;
171
+	n = *np;
172
+	LOG123(("  node %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n",
173
+	     n,
174
+	     n->kids[0], n->counts[0], n->elems[0],
175
+	     n->kids[1], n->counts[1], n->elems[1],
176
+	     n->kids[2], n->counts[2], n->elems[2],
177
+	     n->kids[3], n->counts[3]));
178
+	if (index >= 0) {
179
+	    if (!n->kids[0]) {
180
+		/*
181
+		 * Leaf node. We want to insert at kid position
182
+		 * equal to the index:
183
+		 * 
184
+		 *   0 A 1 B 2 C 3
185
+		 */
186
+		childnum = index;
187
+	    } else {
188
+		/*
189
+		 * Internal node. We always descend through it (add
190
+		 * always starts at the bottom, never in the
191
+		 * middle).
192
+		 */
193
+		do { /* this is a do ... while (0) to allow `break' */
194
+		    if (index <= n->counts[0]) {
195
+			childnum = 0;
196
+			break;
197
+		    }
198
+		    index -= n->counts[0] + 1;
199
+		    if (index <= n->counts[1]) {
200
+			childnum = 1;
201
+			break;
202
+		    }
203
+		    index -= n->counts[1] + 1;
204
+		    if (index <= n->counts[2]) {
205
+			childnum = 2;
206
+			break;
207
+		    }
208
+		    index -= n->counts[2] + 1;
209
+		    if (index <= n->counts[3]) {
210
+			childnum = 3;
211
+			break;
212
+		    }
213
+		    return NULL;       /* error: index out of range */
214
+		} while (0);
215
+	    }
216
+	} else {
217
+	    if ((c = t->cmp(e, n->elems[0])) < 0)
218
+		childnum = 0;
219
+	    else if (c == 0)
220
+		return n->elems[0];	       /* already exists */
221
+	    else if (n->elems[1] == NULL || (c = t->cmp(e, n->elems[1])) < 0)
222
+		childnum = 1;
223
+	    else if (c == 0)
224
+		return n->elems[1];	       /* already exists */
225
+	    else if (n->elems[2] == NULL || (c = t->cmp(e, n->elems[2])) < 0)
226
+		childnum = 2;
227
+	    else if (c == 0)
228
+		return n->elems[2];	       /* already exists */
229
+	    else
230
+		childnum = 3;
231
+	}
232
+	np = &n->kids[childnum];
233
+	LOG123(("  moving to child %d (%p)\n", childnum, *np));
234
+    }
235
+
236
+    /*
237
+     * We need to insert the new element in n at position np.
238
+     */
239
+    left = NULL;  lcount = 0;
240
+    right = NULL; rcount = 0;
241
+    while (n) {
242
+	LOG123(("  at %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n",
243
+	     n,
244
+	     n->kids[0], n->counts[0], n->elems[0],
245
+	     n->kids[1], n->counts[1], n->elems[1],
246
+	     n->kids[2], n->counts[2], n->elems[2],
247
+	     n->kids[3], n->counts[3]));
248
+	LOG123(("  need to insert %p/%d [%p] %p/%d at position %d\n",
249
+	     left, lcount, e, right, rcount, np - n->kids));
250
+	if (n->elems[1] == NULL) {
251
+	    /*
252
+	     * Insert in a 2-node; simple.
253
+	     */
254
+	    if (np == &n->kids[0]) {
255
+		LOG123(("  inserting on left of 2-node\n"));
256
+		n->kids[2] = n->kids[1];     n->counts[2] = n->counts[1];
257
+		n->elems[1] = n->elems[0];
258
+		n->kids[1] = right;          n->counts[1] = rcount;
259
+		n->elems[0] = e;
260
+		n->kids[0] = left;           n->counts[0] = lcount;
261
+	    } else { /* np == &n->kids[1] */
262
+		LOG123(("  inserting on right of 2-node\n"));
263
+		n->kids[2] = right;          n->counts[2] = rcount;
264
+		n->elems[1] = e;
265
+		n->kids[1] = left;           n->counts[1] = lcount;
266
+	    }
267
+	    if (n->kids[0]) n->kids[0]->parent = n;
268
+	    if (n->kids[1]) n->kids[1]->parent = n;
269
+	    if (n->kids[2]) n->kids[2]->parent = n;
270
+	    LOG123(("  done\n"));
271
+	    break;
272
+	} else if (n->elems[2] == NULL) {
273
+	    /*
274
+	     * Insert in a 3-node; simple.
275
+	     */
276
+	    if (np == &n->kids[0]) {
277
+		LOG123(("  inserting on left of 3-node\n"));
278
+		n->kids[3] = n->kids[2];    n->counts[3] = n->counts[2];
279
+		n->elems[2] = n->elems[1];
280
+		n->kids[2] = n->kids[1];    n->counts[2] = n->counts[1];
281
+		n->elems[1] = n->elems[0];
282
+		n->kids[1] = right;         n->counts[1] = rcount;
283
+		n->elems[0] = e;
284
+		n->kids[0] = left;          n->counts[0] = lcount;
285
+	    } else if (np == &n->kids[1]) {
286
+		LOG123(("  inserting in middle of 3-node\n"));
287
+		n->kids[3] = n->kids[2];    n->counts[3] = n->counts[2];
288
+		n->elems[2] = n->elems[1];
289
+		n->kids[2] = right;         n->counts[2] = rcount;
290
+		n->elems[1] = e;
291
+		n->kids[1] = left;          n->counts[1] = lcount;
292
+	    } else { /* np == &n->kids[2] */
293
+		LOG123(("  inserting on right of 3-node\n"));
294
+		n->kids[3] = right;         n->counts[3] = rcount;
295
+		n->elems[2] = e;
296
+		n->kids[2] = left;          n->counts[2] = lcount;
297
+	    }
298
+	    if (n->kids[0]) n->kids[0]->parent = n;
299
+	    if (n->kids[1]) n->kids[1]->parent = n;
300
+	    if (n->kids[2]) n->kids[2]->parent = n;
301
+	    if (n->kids[3]) n->kids[3]->parent = n;
302
+	    LOG123(("  done\n"));
303
+	    break;
304
+	} else {
305
+	    node234 *m = mknew(node234);
306
+	    m->parent = n->parent;
307
+	    LOG123(("  splitting a 4-node; created new node %p\n", m));
308
+	    /*
309
+	     * Insert in a 4-node; split into a 2-node and a
310
+	     * 3-node, and move focus up a level.
311
+	     * 
312
+	     * I don't think it matters which way round we put the
313
+	     * 2 and the 3. For simplicity, we'll put the 3 first
314
+	     * always.
315
+	     */
316
+	    if (np == &n->kids[0]) {
317
+		m->kids[0] = left;          m->counts[0] = lcount;
318
+		m->elems[0] = e;
319
+		m->kids[1] = right;         m->counts[1] = rcount;
320
+		m->elems[1] = n->elems[0];
321
+		m->kids[2] = n->kids[1];    m->counts[2] = n->counts[1];
322
+		e = n->elems[1];
323
+		n->kids[0] = n->kids[2];    n->counts[0] = n->counts[2];
324
+		n->elems[0] = n->elems[2];
325
+		n->kids[1] = n->kids[3];    n->counts[1] = n->counts[3];
326
+	    } else if (np == &n->kids[1]) {
327
+		m->kids[0] = n->kids[0];    m->counts[0] = n->counts[0];
328
+		m->elems[0] = n->elems[0];
329
+		m->kids[1] = left;          m->counts[1] = lcount;
330
+		m->elems[1] = e;
331