Assert that the client count is positive prior to decrementing it.
[silc.git] / lib / silcserver / server_util.c
1 /*
2
3   server_util.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcserver.h"
23 #include "server_internal.h"
24 #include <assert.h>
25
26 /* Return next available command identifier. */
27
28 SilcUInt16 silc_server_cmd_ident(SilcServer server)
29 {
30   SilcUInt16 cmd_ident;
31
32   silc_mutex_lock(server->lock);
33   cmd_ident = ++server->cmd_ident;
34   silc_mutex_unlock(server->lock);
35
36   return cmd_ident;
37 }
38
39 /* XXX locking */
40
41 SilcBool silc_server_check_watcher_list(SilcServer server,
42                                     SilcClientEntry client,
43                                     const char *new_nick,
44                                     SilcNotifyType notify)
45 {
46   return TRUE;
47 }
48
49 /* This function is used to send the notify packets and motd to the
50    incoming client connection. */
51
52 void silc_server_send_welcome(SilcServerAccept ac, SilcClientEntry client)
53 {
54   SilcServer server = ac->thread->server;
55   SilcPacketStream stream = client->stream;
56
57   SILC_LOG_DEBUG(("Send welcome notifys"));
58
59   /* Send some nice info to the client */
60   SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
61                           ("Welcome to the SILC Network %s",
62                            client->username));
63   SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
64                           ("Your host is %s, running version %s",
65                            server->server_name, SILC_DIST_VERSION_STRING));
66
67   if (server->server_type == SILC_ROUTER) {
68     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
69                             ("There are %d clients, %d servers and %d "
70                              "routers in SILC Network",
71                              server->stat.clients, server->stat.servers,
72                              server->stat.routers));
73   } else {
74     if (server->stat.clients && server->stat.servers + 1)
75       SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
76                               ("There are %d clients, %d servers and %d "
77                                "routers in SILC Network",
78                                server->stat.clients, server->stat.servers,
79                                (server->standalone ? 0 :
80                                 !server->stat.routers ? 1 :
81                                 server->stat.routers)));
82   }
83
84   if (server->stat.cell_clients && server->stat.cell_servers + 1)
85     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
86                             ("There are %d clients on %d servers in our cell",
87                              server->stat.cell_clients,
88                              server->stat.cell_servers));
89   if (server->server_type == SILC_ROUTER) {
90     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
91                             ("I have %d clients, %d channels, %d servers and "
92                              "%d routers",
93                              server->stat.my_clients,
94                              server->stat.my_channels,
95                              server->stat.my_servers,
96                              server->stat.my_routers));
97   } else {
98     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
99                             ("I have %d clients and %d channels formed",
100                              server->stat.my_clients,
101                              server->stat.my_channels));
102   }
103
104   if (server->stat.server_ops || server->stat.router_ops)
105     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
106                             ("There are %d server operators and %d router "
107                              "operators online",
108                              server->stat.server_ops,
109                              server->stat.router_ops));
110   if (server->stat.my_router_ops + server->stat.my_server_ops)
111     SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
112                             ("I have %d operators online",
113                              server->stat.my_router_ops +
114                              server->stat.my_server_ops));
115
116   SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
117                           ("Your connection is secured with %s cipher, "
118                            "key length %d bits",
119                            silc_cipher_get_name(ac->prop->cipher),
120                            silc_cipher_get_key_len(ac->prop->cipher)));
121   SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
122                           ("Your current nickname is %s",
123                            client->nickname));
124
125   /* Send motd */
126   silc_server_send_motd(server, stream);
127 }
128
129 /* Creates new Client ID. */
130
131 SilcBool silc_server_create_client_id(SilcServer server, char *nickname,
132                                       SilcClientID *new_id)
133 {
134   unsigned char hash[16];
135   SilcBool finding = FALSE;
136
137   SILC_LOG_DEBUG(("Creating new Client ID"));
138
139   /* Create hash of the nickname (it's already checked as valid identifier
140      string). */
141   silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
142
143   /* Create the ID */
144   memset(new_id, 0, sizeof(*new_id));
145   memcpy(new_id->ip.data, server->id.ip.data, server->id.ip.data_len);
146   new_id->ip.data_len = server->id.ip.data_len;
147   new_id->rnd = silc_rng_get_byte(server->rng);
148   memcpy(new_id->hash, hash, CLIENTID_HASH_LEN);
149
150   /* Assure that the ID does not exist already */
151   while (1) {
152     if (!silc_server_find_client_by_id(server, new_id, FALSE, NULL))
153       break;
154
155     /* The ID exists, start increasing the rnd from 0 until we find a
156        ID that does not exist. If we wrap and it still exists then we
157        will return FALSE and the caller must send some other nickname
158        since this cannot be used anymore. */
159     new_id->rnd++;
160
161     if (finding && new_id->rnd == 0)
162       return FALSE;
163
164     if (!finding) {
165       new_id->rnd = 0;
166       finding = TRUE;
167     }
168   }
169
170   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_CLIENT)));
171
172   return TRUE;
173 }
174
175 /* Creates a Server ID. */
176
177 SilcBool silc_server_create_server_id(SilcServer server,
178                                       const char *ip, SilcUInt16 port,
179                                       SilcServerID *new_id)
180 {
181   SILC_LOG_DEBUG(("Creating new Server ID"));
182
183   if (!new_id)
184     return FALSE;
185
186   /* Create the ID */
187
188   if (!silc_net_addr2bin(ip, new_id->ip.data, sizeof(new_id->ip.data)))
189     return FALSE;
190
191   new_id->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
192   new_id->port = SILC_SWAB_16(port);
193   new_id->rnd = silc_rng_get_rn16(server->rng);
194
195   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_SERVER)));
196
197   return TRUE;
198 }
199
200 /* Checks whether the `server_id' is valid.  It must be based to the
201    IP address provided in the `remote' socket connection. */
202
203 SilcBool silc_server_check_server_id(const char *ip_address,
204                                      SilcServerID *server_id)
205 {
206   unsigned char ip[16];
207
208   if (!silc_net_addr2bin(ip_address, ip, sizeof(ip)))
209     return FALSE;
210
211   if (silc_net_is_ip4(ip_address)) {
212     if (!memcmp(server_id->ip.data, ip, 4))
213       return TRUE;
214   } else {
215     if (!memcmp(server_id->ip.data, ip, 16))
216       return TRUE;
217   }
218
219   return FALSE;
220 }