internal-connections.c 11 KB
Newer Older
Linus Tolke's avatar
Linus Tolke committed
1
/*
2
 * $Id: internal-connections.c,v 0.61 2003/08/14 23:01:41 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-1994, 1996-2002  Lysator Academic Computer Association.
Linus Tolke's avatar
Linus Tolke committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 1, or (at your option) 
 * any later version.
 * 
 * LysKOM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
Per Cederqvist's avatar
Per Cederqvist committed
25
26
27
28
29
30
/*
 * internal-connections.c
 *
 * Abstract routines on the data type Connection.
 */

David Byers's avatar
David Byers committed
31
32
33
34
35

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

Per Cederqvist's avatar
Per Cederqvist committed
36
#include <stdio.h>
37
#include "timewrap.h"
Per Cederqvist's avatar
Per Cederqvist committed
38
#include <setjmp.h>
Per Cederqvist's avatar
Per Cederqvist committed
39
#include <sys/types.h>
40
#include <assert.h>
Per Cederqvist's avatar
Per Cederqvist committed
41

Per Cederqvist's avatar
Per Cederqvist committed
42
#include "exp.h"
Per Cederqvist's avatar
Per Cederqvist committed
43
44
#include "s-string.h"
#include "kom-types.h"
Per Cederqvist's avatar
Per Cederqvist committed
45
#include "com.h"
46
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
48
#include "connections.h"
#include "internal-connections.h"
David Byers's avatar
David Byers committed
49
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
50
51
#include "server/smalloc.h"
#include "lyskomd.h"
52
#include "log.h"
53
#include "async.h"
54
#include "kom-memory.h"
55
#include "server-time.h"
56
#include "timeval-util.h"
57
#include "stats.h"
Per Cederqvist's avatar
Per Cederqvist committed
58

59
60
61
62
/* We don't need the defensive checks in this file.  They have been
   tested enough the last few years.  They also consume a lot of CPU. */
#define NDEFENSIVE_CHECKS 1

Per Cederqvist's avatar
Per Cederqvist committed
63
INTERNAL  Connection  *all_connections   = NULL;
64
INTERNAL  Session_no   no_of_connection_attempts = 0;
Per Cederqvist's avatar
Per Cederqvist committed
65
66
67
68
69

/* Used in get_conn_by_number to speed things up. */

INTERNAL  Connection  *last_conn = NULL;

70
71
static int  no_of_allocated_connections = 0;

72
73
74
static void
init_connection(Connection *conn)
{
75
    static const enum async default_want_async[] = ASYNC_DEFAULT_MESSAGES;
76
77
    int i;
    
78
79
80
81
    conn->prev = NULL;
    conn->next = NULL;
    conn->pers_no = 0;
    conn->person = NULL;
82
83
    conn->connect_time = timeval_ctor(0, 0);
    conn->login_time = timeval_ctor(0, 0);
84
85
86
87
88
89
90
    conn->cwc = 0;
    conn->what_am_i_doing = EMPTY_STRING;
    conn->ena_level = 0;
    conn->username = EMPTY_STRING;
    conn->ident_user = EMPTY_STRING;
    conn->client_name = EMPTY_STRING;
    conn->client_version = EMPTY_STRING;
91
92
93
94
95
96
97
98
    conn->flags.invisible = FALSE;
    conn->flags.user_active_used = FALSE;
    conn->flags.user_absent = FALSE;
    conn->flags.reserved3 = FALSE;
    conn->flags.reserved4 = FALSE;
    conn->flags.reserved5 = FALSE;
    conn->flags.reserved6 = FALSE;
    conn->flags.reserved7 = FALSE;
99
    conn->username_valid = FALSE;
100
101
    conn->dns_done = FALSE;
    conn->blocked_by_dns = FALSE;
102
    conn->isc_session = NULL;
103
104
    conn->remote_ip = EMPTY_STRING;
    conn->peer = NULL;
105
106
107
108
    conn->protocol = '\0';
    conn->parse_pos = 0;
    conn->fnc_parse_pos = 0;
    conn->array_parse_pos = 0;
109
    conn->array_parse_index = 0;
David Byers's avatar
David Byers committed
110
    conn->array_parse_parsed_length = 0;
111
112
    conn->struct_parse_pos = 0;
    conn->string_parse_pos = 0;
David Byers's avatar
David Byers committed
113
114
115
    conn->hunt_parse_pos = 0;
    conn->array_hunt_num = 0;
    conn->array_hunt_depth = 0;
116
117
    conn->ref_no = 0;
    conn->function = call_fnc_login_old;
118
    conn->function_index = 0;
119
120
121
    conn->num_list.length = 0;
    conn->num_list.data = NULL;

122
123
124
125
    conn->num0 = 0;
    conn->num1 = 0;
    conn->num2 = 0;
    conn->num3 = 0;
126
    conn->num4 = 0;
127
128
129
    conn->c_string0 = EMPTY_STRING;
    conn->c_string1 = EMPTY_STRING;
    conn->string0 = EMPTY_STRING;
David Byers's avatar
David Byers committed
130
131
    conn->misc_info_list.no_of_misc = 0;
    conn->misc_info_list.misc = NULL;
132
133
    conn->aux_item_list.items = NULL;
    conn->aux_item_list.length = 0;
134
135
    conn->aux_item.data = EMPTY_STRING;
    conn->dummy_aux_item.data = EMPTY_STRING;
136
    conn->c_local_text_no_p = NULL;
137
138
    conn->read_range_list.ranges = NULL;
    conn->read_range_list.length = 0;
139
140
141
142
    init_priv_bits(&conn->priv_bits);
    init_conf_type(&conn->conf_type);
    init_membership_type(&conn->membership_type);
    init_struct_tm(&conn->time);
143

144
145
146
147
148
149
    conn->info.pers_pres_conf = 0;
    conn->info.conf_pres_conf = 0;
    conn->info.motd_conf = 0;
    conn->info.kom_news_conf = 0;
    conn->info.motd_of_lyskom = 0;
    conn->info.version = 0;
150
151
152
    conn->info.highest_aux_no = 0;
    conn->info.aux_item_list.length = 0;
    conn->info.aux_item_list.items = NULL;
153

154
155
156
157
158
159
160
161
162
163
164
165
    init_personal_flags(&conn->pers_flags);
    conn->unparsed = EMPTY_STRING;
    conn->first_to_parse = 0;
    conn->more_to_parse = FALSE;
    conn->kill_pending = FALSE;
    conn->penalty = 0;
    conn->penalty_generation = 0;

    conn->queue_next = NULL;
    conn->queue_prev = NULL;
    conn->on_queue = FALSE;

166
167
168
    conn->schedule.priority = 0;
    conn->schedule.weight = 1;

169
170
    conn->active_time = current_time;
    conn->session_no = 0;
171
172

    for (i = 0; i < ay_dummy_last; i++)
173
        conn->want_async[i] = FALSE;
174
175
    
    for (i = 0;
David Byers's avatar
David Byers committed
176
         (size_t)i < sizeof(default_want_async)/sizeof(*default_want_async);
177
         i++)
178
        conn->want_async[default_want_async[i]] = TRUE;
179
180
181
}

static Connection *
Per Cederqvist's avatar
Per Cederqvist committed
182
183
184
185
186
alloc_connection(void)
{
    Connection *res;
    
    res = smalloc ( sizeof(Connection) );
187
    init_connection(res);
188
    ++no_of_allocated_connections;
Per Cederqvist's avatar
Per Cederqvist committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    return res;
}

EXPORT  Connection *
new_client(void)
{
    Connection		*c;

    c = alloc_connection();

    if (all_connections != NULL)
    {
	all_connections->prev->next = c;
	c->prev = all_connections->prev;
	all_connections->prev = c;
	c->next = all_connections;
    }
    else
    {
	c->prev = c;
	c->next = c;
    }

    all_connections = c;
    
    c->session_no = ++no_of_connection_attempts;
215
    c->protocol = '\0';      /* Reserved to mean 'no protocol specified yet' */
Per Cederqvist's avatar
Per Cederqvist committed
216
217
    c->unparsed = EMPTY_STRING;
    c->first_to_parse = 0;
218
    c->kill_pending = FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
219
    c->more_to_parse = TRUE;
220
    c->active_time = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
221
222
    c->pers_no = 0;
    c->person = NULL;
223
224
    c->connect_time = current_time;
    c->login_time = current_time;
Per Cederqvist's avatar
Per Cederqvist committed
225
226
227
228
    c->cwc = 0;
    c->what_am_i_doing = EMPTY_STRING;
    c->ena_level = 0;
    c->username = EMPTY_STRING;
229
    c->ident_user = EMPTY_STRING;
230
231
    c->client_name = EMPTY_STRING;
    c->client_version = EMPTY_STRING;
232
233
234
235
236
237
238
239
    c->flags.invisible = FALSE;
    c->flags.user_active_used = FALSE;
    c->flags.user_absent = FALSE;
    c->flags.reserved3 = FALSE;
    c->flags.reserved4 = FALSE;
    c->flags.reserved5 = FALSE;
    c->flags.reserved6 = FALSE;
    c->flags.reserved7 = FALSE;
240
    c->username_valid = FALSE;
241
242
    c->dns_done = FALSE;
    c->blocked_by_dns = FALSE;
243

Per Cederqvist's avatar
Per Cederqvist committed
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    return c;
}

/*
 * Only used from logout_client
 */
EXPORT  void
kill_client(Connection *cp)    
{
    if ( all_connections == NULL )
	restart_kom("kill_client(): No clients in all_connections list\n");
    
    if (all_connections == all_connections->next)
    {
	if (all_connections->prev != all_connections)
	    restart_kom("kill_client(): all_connections corrupt (LINK)\n");

	if (all_connections != cp)
	    restart_kom("kill_client(): all_connections corrupt (SINGLE)\n");
      
	all_connections = NULL;
    }
    else
    {
	if (cp->prev == NULL || cp->next == NULL)
	    restart_kom("kill_client(): all_connections corrupt (NULL)\n");
      
	cp->prev->next = cp->next;
	cp->next->prev = cp->prev;
	
	if (all_connections == cp)
	    all_connections = cp->next;
    }

    if ( last_conn == cp )
	last_conn = NULL;

281
282
283
    update_stat(STAT_RECV_QUEUE,
		-(s_strlen(cp->unparsed) - cp->first_to_parse));

284
285
286
    s_clear(&cp->unparsed);
    s_clear(&cp->what_am_i_doing);
    s_clear(&cp->username);
287
    s_clear(&cp->ident_user);
288
289
    s_clear(&cp->client_name);
    s_clear(&cp->client_version);
290
    s_clear(&cp->remote_ip);
291

292
    if ( cp->isc_session != NULL )
293
    {
David Byers's avatar
David Byers committed
294
295
	kom_log("kill_client(): client %ld has isc_session != NULL.\n",
                cp->session_no);
296
297
    }

298
299
    assert(cp->on_queue == FALSE);

300
301
302
    if ( !s_empty(cp->c_string0) || !s_empty(cp->c_string1)
	|| !s_empty(cp->string0) )
    {
David Byers's avatar
David Byers committed
303
	kom_log("kill_client(): unexpected string remains.\n");
304
305
    }

306
307
308
309
310
    if (cp->misc_info_list.misc != NULL)
	kom_log("kill_client(): unexpected misc_info_list remains.\n");

    if (cp->c_local_text_no_p != NULL)
	kom_log("kill_client(): unexpected local_text_no remains.\n");
311

312
313
314
315
316
317
    if (!s_empty(cp->aux_item.data))
	kom_log("kill_client(): unexpected aux_item string remains.\n");

    if (!s_empty(cp->dummy_aux_item.data))
	kom_log("kill_client(): unexpected dummy_aux_item string remains.\n");
	
318
    /* FIXME (bug 149): Check for remaining data in aux-item structures */
David Byers's avatar
David Byers committed
319

320
    sfree(cp->peer);
Per Cederqvist's avatar
Per Cederqvist committed
321
    sfree(cp);
322
    --no_of_allocated_connections;
Per Cederqvist's avatar
Per Cederqvist committed
323
324
}

325
#ifndef NDEFENSIVE_CHECKS
Per Cederqvist's avatar
Per Cederqvist committed
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

INTERNAL  void
check_conn_exists(Connection *foo)
{
    /* Check that foo really is active. */

    Connection *c = all_connections;
    Bool found = FALSE;

    do
    {
	if ( c == foo )
	    found = TRUE;

	c = c->next;
    }
    while ( c != all_connections && found == FALSE );

    if ( found == FALSE )
345
	restart_kom("%s: foo == %ld not found in all_connections.\n", 
Per Cederqvist's avatar
Per Cederqvist committed
346
347
		    "get_conn_by_number",
		    last_conn->session_no);
Per Cederqvist's avatar
Per Cederqvist committed
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
}

#endif

/*
 * Session_nos must NOT be recycled, or this code might break!
 */
EXPORT  Connection *
get_conn_by_number (Session_no session_no)
{
    Connection *end;

    if ( last_conn == NULL )
	last_conn = all_connections;
    else if ( all_connections == NULL )
    {
364
	restart_kom("get_conn_by_number(%ld): last_conn = %ld %s",
Per Cederqvist's avatar
Per Cederqvist committed
365
366
367
		    session_no,
		    last_conn->session_no,
		    "and all_connections == NULL");
Per Cederqvist's avatar
Per Cederqvist committed
368
    }
369
#ifndef NDEFENSIVE_CHECKS
Per Cederqvist's avatar
Per Cederqvist committed
370
371
372
373
374
375
    else
	check_conn_exists(last_conn);
#endif

    end = last_conn;

376
    if (session_no == 0)
David Byers's avatar
Server    
David Byers committed
377
378
379
380
381
    {
        if (active_connection == NULL)
        {
            restart_kom("get_conn_by_number: No session-no and no active connection");
        }
382
        session_no = active_connection->session_no;
David Byers's avatar
Server    
David Byers committed
383
    }
384

Per Cederqvist's avatar
Per Cederqvist committed
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
    do
    {
	if ( last_conn->session_no == session_no )
	    return last_conn;

	last_conn = last_conn->next;
    }
    while ( last_conn != end);

    return NULL;
}


EXPORT  Session_no
traverse_connections (Session_no session_no)
{
    Connection *prev = NULL;

    if ( all_connections == NULL )
	return 0;

406
407
408
409
    if (session_no == 0)
        prev = NULL;
    else
        prev = get_conn_by_number ( session_no );
Per Cederqvist's avatar
Per Cederqvist committed
410
411
412
413
414
415
416
417
418
419

    /* prev is NULL if session_no is 0, or if session_no was logged out. */

    if ( prev == NULL )
	return all_connections->session_no;
    else if ( prev->next == all_connections )
	return 0;		/* Full circle. */
    else
	return prev->next->session_no;
}
420
421
422
423

void
dump_allocated_connections(FILE *fp)
{
Per Cederqvist's avatar
Per Cederqvist committed
424
425
    fprintf(fp, "---%s:\n\tConnections:      %d\n",
	    __FILE__,
426
	    no_of_allocated_connections);
Per Cederqvist's avatar
Per Cederqvist committed
427
428
    fprintf(fp, "\tConnection attempts:	%lu\n",
	    (unsigned long)no_of_connection_attempts);
429
}
430
431
432
433
434
435
436
437

Bool
handshake_ok(struct connection *cptr,
	     enum ignored_conditions ignored)
{
    if (!cptr->dns_done && !(ignored & ignore_dns))
	return FALSE;

438
439
440
441
    if (!cptr->username_valid)
	return FALSE;

    return TRUE;
442
}