fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.git] / ircd / uping.c
1 /*
2  * IRC - Internet Relay Chat, ircd/uping.c
3  * Copyright (C) 1994 Carlo Wood ( Run @ undernet.org )
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /** @file
20  * @brief UDP ping implementation.
21  * @version $Id: uping.c 1626 2006-03-14 03:45:52Z entrope $
22  */
23 #include "config.h"
24
25 #include "uping.h"
26 #include "client.h"
27 #include "ircd.h"
28 #include "ircd_alloc.h"
29 #include "ircd_events.h"
30 #include "ircd_log.h"
31 #include "ircd_osdep.h"
32 #include "ircd_string.h"
33 #include "match.h"
34 #include "msg.h"
35 #include "numeric.h"
36 #include "numnicks.h"
37 #include "s_bsd.h"    /* VirtualHost */
38 #include "s_conf.h"
39 #include "s_debug.h"
40 #include "s_misc.h"
41 #include "s_user.h"
42 #include "send.h"
43 #include "sys.h"
44
45 /* #include <assert.h> -- Now using assert in ircd_log.h */
46 #include <errno.h>
47 #include <netdb.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sys/socket.h>
52 #include <sys/time.h>
53 #include <unistd.h>
54
55 #define UPINGTIMEOUT 60   /**< Timeout waiting for ping responses */
56
57 static struct UPing* pingList = 0; /**< Linked list of UPing structs */
58 static struct Socket upingSock_v4; /**< Socket struct for IPv4 upings */
59 static struct Socket upingSock_v6; /**< Socket struct for IPv6 upings */
60
61 /** Start iteration of uping list.
62  * @return Start of uping list.
63  */
64 struct UPing* uping_begin(void)
65 {
66   return pingList;
67 }
68
69 /** Removes \a p from uping list.
70  * @param[in,out] p UPing to remove from list.
71  */
72 static void uping_erase(struct UPing* p)
73 {
74   struct UPing* it;
75   struct UPing* last = 0;
76
77   assert(0 != p);
78
79   for (it = pingList; it; last = it, it = it->next) {
80     if (p == it) {
81       if (last)
82         last->next = p->next;
83       else
84         pingList = p->next;
85       break;
86     }
87   }
88 }
89
90 /** Callback for uping listener socket.
91  * Reads a uping from the socket and respond, but not more than 10
92  * times per second.
93  * @param[in] ev I/O event for uping socket.
94  */
95 static void uping_echo_callback(struct Event* ev)
96 {
97   struct Socket      *sock;
98   struct irc_sockaddr from;
99   unsigned int       len = 0;
100   static time_t      last = 0;
101   static int         counter = 0;
102   char               buf[BUFSIZE + 1];
103
104   assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
105   sock = ev_socket(ev);
106   assert(sock == &upingSock_v4 || sock == &upingSock_v6);
107
108   Debug((DEBUG_DEBUG, "UPING: uping_echo"));
109
110   if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, BUFSIZE, &len, &from))
111     return;
112   /*
113    * count em even if we're getting flooded so we can tell we're getting
114    * flooded.
115    */
116   ++ServerStats->uping_recv;
117   if (len < 19)
118     return;
119   else if (CurrentTime != last) {
120     counter = 0;
121     last = CurrentTime;
122   } else if (++counter > 10)
123     return;
124   os_sendto_nonb(s_fd(sock), buf, len, NULL, 0, &from);
125 }
126
127 /** Initialize a UDP socket for upings.
128  * @returns 0 on success, -1 on error.
129  */
130 int uping_init(void)
131 {
132   struct irc_sockaddr from;
133   int fd;
134
135   memcpy(&from, &VirtualHost_v4, sizeof(from));
136   from.port = atoi(UDP_PORT);
137
138   fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener", AF_INET);
139   if (fd < 0)
140     return -1;
141   if (!socket_add(&upingSock_v4, uping_echo_callback, 0, SS_DATAGRAM,
142                   SOCK_EVENT_READABLE, fd)) {
143     Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
144     close(fd);
145     return -1;
146   }
147
148 #ifdef AF_INET6
149   memcpy(&from, &VirtualHost_v6, sizeof(from));
150   from.port = atoi(UDP_PORT);
151
152   fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener", AF_INET6);
153   if (fd < 0)
154     return -1;
155   if (!socket_add(&upingSock_v6, uping_echo_callback, 0, SS_DATAGRAM,
156                   SOCK_EVENT_READABLE, fd)) {
157     Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
158     close(fd);
159     return -1;
160   }
161 #endif
162
163   return 0;
164 }
165
166
167 /** Callback for socket activity on an outbound uping socket.
168  * @param[in] ev I/O event for socket.
169  */
170 static void uping_read_callback(struct Event* ev)
171 {
172   struct UPing *pptr;
173
174   assert(0 != ev_socket(ev));
175   assert(0 != s_data(ev_socket(ev)));
176
177   pptr = (struct UPing*) s_data(ev_socket(ev));
178
179   Debug((DEBUG_SEND, "uping_read_callback called, %p (%d)", pptr,
180          ev_type(ev)));
181
182   if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
183     pptr->freeable &= ~UPING_PENDING_SOCKET;
184
185     if (!pptr->freeable)
186       MyFree(pptr); /* done with it, finally */
187   } else {
188     assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
189
190     uping_read(pptr); /* read uping response */
191   }
192 }
193
194 /** Timer callback to send another outbound uping.
195  * @param[in] ev Event for uping timer.
196  */
197 static void uping_sender_callback(struct Event* ev)
198 {
199   struct UPing *pptr;
200
201   assert(0 != ev_timer(ev));
202   assert(0 != t_data(ev_timer(ev)));
203
204   pptr = (struct UPing*) t_data(ev_timer(ev));
205
206   Debug((DEBUG_SEND, "uping_sender_callback called, %p (%d)", pptr,
207          ev_type(ev)));
208
209   if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
210     pptr->freeable &= ~UPING_PENDING_SENDER;
211
212     if (!pptr->freeable)
213       MyFree(pptr); /* done with it, finally */
214   } else {
215     assert(ev_type(ev) == ET_EXPIRE);
216
217     pptr->lastsent = CurrentTime; /* store last ping time */
218     uping_send(pptr); /* send a ping */
219
220     if (pptr->sent == pptr->count) /* done sending pings, don't send more */
221       timer_del(ev_timer(ev));
222   }
223 }
224
225 /** Timer callback to stop upings.
226  * @param[in] ev Event for uping expiration.
227  */
228 static void uping_killer_callback(struct Event* ev)
229 {
230   struct UPing *pptr;
231
232   assert(0 != ev_timer(ev));
233   assert(0 != t_data(ev_timer(ev)));
234
235   pptr = (struct UPing*) t_data(ev_timer(ev));
236
237   Debug((DEBUG_SEND, "uping_killer_callback called, %p (%d)", pptr,
238          ev_type(ev)));
239
240   if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
241     pptr->freeable &= ~UPING_PENDING_KILLER;
242
243     if (!pptr->freeable)
244       MyFree(pptr); /* done with it, finally */
245   } else {
246     assert(ev_type(ev) == ET_EXPIRE);
247
248     uping_end(pptr); /* <FUDD>kill the uping, kill the uping!</FUDD> */
249   }
250 }
251
252 /** Start a uping.
253  * This sets up the timers, UPing flags, and sends a notice to the
254  * requesting client.
255  */
256 static void uping_start(struct UPing* pptr)
257 {
258   assert(0 != pptr);
259
260   timer_add(timer_init(&pptr->sender), uping_sender_callback, (void*) pptr,
261             TT_PERIODIC, 1);
262   timer_add(timer_init(&pptr->killer), uping_killer_callback, (void*) pptr,
263             TT_RELATIVE, UPINGTIMEOUT);
264   pptr->freeable |= UPING_PENDING_SENDER | UPING_PENDING_KILLER;
265
266   sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :Sending %d ping%s to %s",
267                 pptr->client, pptr->count, (pptr->count == 1) ? "" : "s",
268                 pptr->name);
269   pptr->active = 1;
270 }
271
272 /** Send a uping to another server.
273  * @param[in] pptr Descriptor for uping.
274  */
275 void uping_send(struct UPing* pptr)
276 {
277   struct timeval tv;
278   char buf[BUFSIZE + 1];
279
280   assert(0 != pptr);
281   if (pptr->sent == pptr->count)
282     return;
283   memset(buf, 0, sizeof(buf));
284
285   gettimeofday(&tv, NULL);
286   sprintf(buf, " %10lu%c%6lu", (unsigned long)tv.tv_sec, '\0', (unsigned long)tv.tv_usec);
287
288   Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
289           buf, &buf[12],
290           ircd_ntoa(&pptr->addr.addr), pptr->addr.port,
291           pptr->fd));
292
293   if (os_sendto_nonb(pptr->fd, buf, BUFSIZE, NULL, 0, &pptr->addr) != IO_SUCCESS)
294   {
295     const char* msg = strerror(errno);
296     if (!msg)
297       msg = "Unknown error";
298     if (pptr->client)
299       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: send failed: "
300                     "%s", pptr->client, msg);
301     Debug((DEBUG_DEBUG, "UPING: send_ping: sendto failed on %d: %s", pptr->fd, msg));
302     uping_end(pptr);
303     return;
304   }
305   ++pptr->sent;
306 }
307
308 /** Read the response from an outbound uping.
309  * @param[in] pptr UPing to check.
310  */
311 void uping_read(struct UPing* pptr)
312 {
313   struct irc_sockaddr sin;
314   struct timeval     tv;
315   unsigned int       len;
316   unsigned int       pingtime;
317   char*              s;
318   char               buf[BUFSIZE + 1];
319   IOResult           ior;
320
321   assert(0 != pptr);
322
323   gettimeofday(&tv, NULL);
324
325   ior = os_recvfrom_nonb(pptr->fd, buf, BUFSIZE, &len, &sin);
326   if (IO_BLOCKED == ior)
327     return;
328   else if (IO_FAILURE == ior) {
329     const char* msg = strerror(errno);
330     if (!msg)
331       msg = "Unknown error";
332     sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: receive error: "
333                   "%s", pptr->client, msg);
334     uping_end(pptr);
335     return;
336   }
337
338   if (len < 19)
339     return;                     /* Broken packet */
340
341   ++pptr->received;
342
343   buf[len] = 0;
344   pingtime = (tv.tv_sec - atol(&buf[1])) * 1000
345              + (tv.tv_usec - atol(buf + strlen(buf) + 1)) / 1000;
346
347   pptr->ms_ave += pingtime;
348   if (!pptr->ms_min || pptr->ms_min > pingtime)
349     pptr->ms_min = pingtime;
350   if (pingtime > pptr->ms_max)
351     pptr->ms_max = pingtime;
352
353   timer_chg(&pptr->killer, TT_RELATIVE, UPINGTIMEOUT);
354
355   s = pptr->buf + strlen(pptr->buf);
356   sprintf(s, " %u", pingtime);
357
358   if (pptr->received == pptr->count)
359     uping_end(pptr);
360   return;
361 }
362
363 /** Start sending upings to a server.
364  * @param[in] sptr Client requesting the upings.
365  * @param[in] aconf ConfItem containing the address to ping.
366  * @param[in] port Port number to ping.
367  * @param[in] count Number of times to ping (should be at least 20).
368  * @return Zero.
369  */
370 int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count)
371 {
372   int fd;
373   int family = 0;
374   struct UPing* pptr;
375   struct irc_sockaddr *local;
376
377   assert(0 != sptr);
378   assert(0 != aconf);
379
380   if (!irc_in_addr_valid(&aconf->address.addr)) {
381     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host lookup failed for "
382                   "%s", sptr, aconf->name);
383     return 0;
384   }
385
386   if (IsUPing(sptr))
387     uping_cancel(sptr, sptr);  /* Cancel previous ping request */
388
389   if (irc_in_addr_is_ipv4(&aconf->address.addr)) {
390     local = &VirtualHost_v4;
391     family = AF_INET;
392   } else {
393     local = &VirtualHost_v6;
394   }
395   fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket", family);
396   if (fd < 0)
397     return 0;
398
399   pptr = (struct UPing*) MyMalloc(sizeof(struct UPing));
400   assert(0 != pptr);
401   memset(pptr, 0, sizeof(struct UPing));
402
403   if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr,
404                   SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) {
405     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for "
406                   "reading", sptr);
407     close(fd);
408     MyFree(pptr);
409     return 0;
410   }
411
412   pptr->fd                  = fd;
413   memcpy(&pptr->addr.addr, &aconf->address.addr, sizeof(pptr->addr.addr));
414   pptr->addr.port           = port;
415   pptr->count               = IRCD_MIN(20, count);
416   pptr->client              = sptr;
417   pptr->freeable            = UPING_PENDING_SOCKET;
418   strcpy(pptr->name, aconf->name);
419
420   pptr->next = pingList;
421   pingList   = pptr;
422
423   SetUPing(sptr);
424   uping_start(pptr);
425   return 0;
426 }
427
428 /** Clean up a UPing structure, reporting results to the requester.
429  * @param[in,out] pptr UPing results.
430  */
431 void uping_end(struct UPing* pptr)
432 {
433   Debug((DEBUG_DEBUG, "uping_end: %p", pptr));
434
435   if (pptr->client) {
436     if (pptr->lastsent) {
437       if (0 < pptr->received) {
438         sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING %s%s",
439                       pptr->client, pptr->name, pptr->buf);
440         sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING Stats: "
441                       "sent %d recvd %d ; min/avg/max = %u/%u/%u ms",
442                       pptr->client, pptr->sent, pptr->received, pptr->ms_min,
443                       (2 * pptr->ms_ave) / (2 * pptr->received), pptr->ms_max);
444       } else
445         sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: no response "
446                       "from %s within %d seconds", pptr->client, pptr->name,
447                       UPINGTIMEOUT);
448     } else
449       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: Could not "
450                     "start ping to %s", pptr->client, pptr->name);
451   }
452
453   close(pptr->fd);
454   pptr->fd = -1;
455   uping_erase(pptr);
456   if (pptr->client)
457     ClearUPing(pptr->client);
458   if (pptr->freeable & UPING_PENDING_SOCKET)
459     socket_del(&pptr->socket);
460   if (pptr->freeable & UPING_PENDING_SENDER)
461     timer_del(&pptr->sender);
462   if (pptr->freeable & UPING_PENDING_KILLER)
463     timer_del(&pptr->killer);
464 }
465
466 /** Change notifications for any upings by \a sptr.
467  * @param[in] sptr Client to stop notifying.
468  * @param[in] acptr New client to notify (or NULL).
469  */
470 void uping_cancel(struct Client *sptr, struct Client* acptr)
471 {
472   struct UPing* ping;
473   struct UPing* ping_next;
474
475   Debug((DEBUG_DEBUG, "UPING: canceling uping for %s", cli_name(sptr)));
476   for (ping = pingList; ping; ping = ping_next) {
477     ping_next = ping->next;
478     if (sptr == ping->client) {
479       ping->client = acptr;
480       uping_end(ping);
481     }
482   }
483   ClearUPing(sptr);
484 }