7c33c1afbfd3d6191ebc1543378b1e34bf8e221f
[silc.git] / lib / silccore / silcprotocol.c
1 /*
2
3   silcprotocol.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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 /*
24  * $Id$
25  * $Log$
26  * Revision 1.3  2000/07/20 10:17:25  priikone
27  *      Added dynamic protocol registering/unregistering support.  The
28  *      patch was provided by cras.
29  *
30  * Revision 1.2  2000/07/05 06:06:35  priikone
31  *      Global cosmetic change.
32  *
33  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
34  *      Imported from internal CVS/Added Log headers.
35  *
36  *
37  */
38
39 #include "silcincludes.h"
40 #include "silcprotocol.h"
41
42 /* Dynamically registered protocols */
43 SilcProtocolObject *silc_protocol_list = NULL;
44
45 /* Dynamically registers new protocol. The protocol is added into protocol
46    list and can be unregistered with silc_protocol_unregister. */
47
48 void silc_protocol_register(SilcProtocolType type,
49                             SilcProtocolCallback callback)
50 {
51   SilcProtocolObject *new;
52
53   new = silc_calloc(1, sizeof(*new));
54   new->type = type;
55   new->callback = callback;
56
57   if (!silc_protocol_list)
58     silc_protocol_list = new;
59   else {
60     new->next = silc_protocol_list;
61     silc_protocol_list = new;
62   }
63 }
64
65 /* Unregisters protocol. The unregistering is done by both protocol type
66    and the protocol callback. */
67
68 void silc_protocol_unregister(SilcProtocolType type,
69                               SilcProtocolCallback callback)
70 {
71   SilcProtocolObject *protocol, *prev;
72
73   protocol = silc_protocol_list;
74   prev = NULL;
75   while (protocol && (protocol->type != type && 
76                       protocol->callback != callback)) {
77     prev = protocol;
78     protocol = protocol->next;
79   }
80
81   if (protocol) {
82     if (prev)
83       prev->next = protocol->next;
84     else
85       silc_protocol_list = protocol->next;
86
87     silc_free(protocol);
88   }
89 }
90
91 /* Allocates a new protocol object. The new allocated and initialized 
92    protocol is returned to the new_protocol argument. The argument context
93    is the context to be sent as argument for the protocol. The callback
94    argument is the function to be called _after_ the protocol has finished. */
95
96 void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
97                          void *context, SilcProtocolFinalCallback callback)
98 {
99   SilcProtocolObject *protocol;
100
101   SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
102
103   protocol = silc_protocol_list;
104   while (protocol && protocol->type != type)
105     protocol = protocol->next;
106
107   if (!protocol) {
108     SILC_LOG_ERROR(("Requested protocol does not exists"));
109     return;
110   }
111
112   *new_protocol = silc_calloc(1, sizeof(**new_protocol));
113   (*new_protocol)->protocol = protocol;
114   (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
115   (*new_protocol)->context = context;
116   (*new_protocol)->execute = silc_protocol_execute;
117   (*new_protocol)->execute_final = silc_protocol_execute_final;
118   (*new_protocol)->final_callback = callback;
119 }
120
121 /* Free's a protocol object. */
122
123 void silc_protocol_free(SilcProtocol protocol)
124 {
125   if (protocol)
126     silc_free(protocol);
127 }
128
129 /* Executes next state of the protocol. The state must be set before
130    calling this function. */
131
132 void silc_protocol_execute(void *qptr, int type,
133                            void *context, int fd,
134                            long secs, long usecs)
135 {
136   SilcProtocol protocol = (SilcProtocol)context;
137
138   SILC_LOG_DEBUG(("Start"));
139
140   if (secs + usecs) 
141     silc_task_register(qptr, fd, protocol->protocol->callback, context, 
142                        secs, usecs, 
143                        SILC_TASK_TIMEOUT,
144                        SILC_TASK_PRI_NORMAL);
145   else
146     protocol->protocol->callback(qptr, 0, context, fd);
147 }
148
149 /* Executes the final callback of the protocol. */
150
151 void silc_protocol_execute_final(void *qptr, int type,
152                                  void *context, int fd)
153 {
154   SilcProtocol protocol = (SilcProtocol)context;
155  
156   SILC_LOG_DEBUG(("Start, state=%d", protocol->state));
157
158   protocol->final_callback(qptr, 0, context, fd);
159 }