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