67a6640aaa2ebd116100d2afa0cb54533233400c
[silc.git] / lib / silcutil / silcprotocol.c
1 /*
2
3   silcprotocol.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program 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   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * Created: Tue Nov 25 19:25:33 GMT+0200 1997
22  */
23 /* $Id$ */
24
25 #include "silcincludes.h"
26
27 /* Dynamically registered protocols */
28 SilcProtocolObject *silc_protocol_list = NULL;
29
30 /* Dynamically registers new protocol. The protocol is added into protocol
31    list and can be unregistered with silc_protocol_unregister. */
32
33 void silc_protocol_register(SilcProtocolType type,
34                             SilcProtocolCallback callback)
35 {
36   SilcProtocolObject *proto_new;
37
38   proto_new = silc_calloc(1, sizeof(*proto_new));
39   proto_new->type = type;
40   proto_new->callback = callback;
41
42   if (!silc_protocol_list)
43     silc_protocol_list = proto_new;
44   else {
45     proto_new->next = silc_protocol_list;
46     silc_protocol_list = proto_new;
47   }
48 }
49
50 /* Unregisters protocol. The unregistering is done by both protocol type
51    and the protocol callback. */
52
53 void silc_protocol_unregister(SilcProtocolType type,
54                               SilcProtocolCallback callback)
55 {
56   SilcProtocolObject *protocol, *prev;
57
58   protocol = silc_protocol_list;
59   prev = NULL;
60   while (protocol && (protocol->type != type && 
61                       protocol->callback != callback)) {
62     prev = protocol;
63     protocol = protocol->next;
64   }
65
66   if (protocol) {
67     if (prev)
68       prev->next = protocol->next;
69     else
70       silc_protocol_list = protocol->next;
71
72     silc_free(protocol);
73   }
74 }
75
76 /* Allocates a new protocol object. The new allocated and initialized 
77    protocol is returned to the new_protocol argument. The argument context
78    is the context to be sent as argument for the protocol. The callback
79    argument is the function to be called _after_ the protocol has finished. */
80
81 void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
82                          void *context, SilcProtocolFinalCallback callback)
83 {
84   SilcProtocolObject *protocol;
85
86   SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
87
88   protocol = silc_protocol_list;
89   while (protocol && protocol->type != type)
90     protocol = protocol->next;
91
92   if (!protocol) {
93     SILC_LOG_ERROR(("Requested protocol does not exists"));
94     *new_protocol = NULL;
95     return;
96   }
97
98   *new_protocol = silc_calloc(1, sizeof(**new_protocol));
99   (*new_protocol)->protocol = protocol;
100   (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
101   (*new_protocol)->context = context;
102   (*new_protocol)->final_callback = callback;
103 }
104
105 /* Frees a protocol object. */
106
107 void silc_protocol_free(SilcProtocol protocol)
108 {
109   if (protocol)
110     silc_free(protocol);
111 }
112
113 /* Executes next state of the protocol. The state must be set before
114    calling this function. */
115
116 void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
117                            long secs, long usecs)
118 {
119   if (secs + usecs) 
120     silc_schedule_task_add(schedule, 0, 
121                            protocol->protocol->callback, (void *)protocol, 
122                            secs, usecs, 
123                            SILC_TASK_TIMEOUT,
124                            SILC_TASK_PRI_NORMAL);
125   else
126     protocol->protocol->callback(schedule, silc_schedule_get_context(schedule),
127                                  0, 0, (void *)protocol);
128 }
129
130 /* Executes the final callback of the protocol. */
131
132 void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule)
133 {
134   protocol->final_callback(schedule, silc_schedule_get_context(schedule),
135                            0, 0, (void *)protocol);
136 }
137
138 /* Cancels the execution of the next state of the protocol. */
139
140 void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule)
141 {
142   silc_schedule_task_del_by_context(schedule, protocol);
143 }