ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 2881
Committed: Mon Jan 20 17:15:39 2014 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 30725 byte(s)
Log Message:
- Use the i/o subsystem to execute scheduled writes. Patch provided by Adam.

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * send.c: Functions for sending messages.
4     *
5     * Copyright (C) 2002 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26 michael 1011 #include "list.h"
27 adx 30 #include "send.h"
28     #include "channel.h"
29     #include "client.h"
30     #include "dbuf.h"
31     #include "irc_string.h"
32     #include "ircd.h"
33     #include "numeric.h"
34     #include "fdlist.h"
35     #include "s_bsd.h"
36     #include "s_serv.h"
37 michael 1309 #include "conf.h"
38     #include "log.h"
39 adx 30 #include "memory.h"
40     #include "packet.h"
41    
42    
43 michael 1078 static unsigned int current_serial = 0;
44 adx 30
45    
46     /* send_format()
47     *
48     * inputs - buffer to format into
49     * - size of the buffer
50     * - format pattern to use
51     * - var args
52     * output - number of bytes formatted output
53     * side effects - modifies sendbuf
54     */
55     static inline int
56     send_format(char *lsendbuf, int bufsize, const char *pattern, va_list args)
57     {
58     int len;
59    
60     /*
61     * from rfc1459
62     *
63     * IRC messages are always lines of characters terminated with a CR-LF
64     * (Carriage Return - Line Feed) pair, and these messages shall not
65 michael 2638 * exceed 512 characters in length, counting all characters
66 adx 30 * including the trailing CR-LF.
67     * Thus, there are 510 characters maximum allowed
68     * for the command and its parameters. There is no provision for
69     * continuation message lines. See section 7 for more details about
70     * current implementations.
71     */
72     len = vsnprintf(lsendbuf, bufsize - 1, pattern, args);
73     if (len > bufsize - 2)
74     len = bufsize - 2; /* required by some versions of vsnprintf */
75    
76     lsendbuf[len++] = '\r';
77     lsendbuf[len++] = '\n';
78 michael 1078 return len;
79 adx 30 }
80    
81     /*
82     ** send_message
83     ** Internal utility which appends given buffer to the sockets
84     ** sendq.
85     */
86     static void
87     send_message(struct Client *to, char *buf, int len)
88     {
89 michael 439 assert(!IsMe(to));
90 michael 438 assert(to != &me);
91 adx 30
92 michael 1632 if (dbuf_length(&to->localClient->buf_sendq) + len > get_sendq(&to->localClient->confs))
93 adx 30 {
94     if (IsServer(to))
95 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
96 michael 1761 "Max SendQ limit exceeded for %s: %lu > %u",
97 adx 30 get_client_name(to, HIDE_IP),
98     (unsigned long)(dbuf_length(&to->localClient->buf_sendq) + len),
99 michael 1632 get_sendq(&to->localClient->confs));
100 adx 30 if (IsClient(to))
101     SetSendQExceeded(to);
102     dead_link_on_write(to, 0);
103     return;
104     }
105 michael 2638
106 michael 1798 dbuf_put(&to->localClient->buf_sendq, buf, len);
107 adx 30
108     /*
109     ** Update statistics. The following is slightly incorrect
110     ** because it counts messages even if queued, but bytes
111     ** only really sent. Queued bytes get updated in SendQueued.
112     */
113     ++to->localClient->send.messages;
114     ++me.localClient->send.messages;
115    
116 michael 2881 send_queued_write(to);
117 adx 30 }
118    
119     /* send_message_remote()
120     *
121     * inputs - pointer to client from message is being sent
122     * - pointer to client to send to
123     * - pointer to preformatted buffer
124     * - length of input buffer
125     * output - none
126     * side effects - Despite the function name, this only sends to directly
127     * connected clients.
128     *
129     */
130     static void
131     send_message_remote(struct Client *to, struct Client *from,
132     char *buf, int len)
133     {
134 michael 2793 if (to->from)
135     to = to->from;
136    
137 adx 30 if (!MyConnect(to))
138     {
139 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
140 michael 2638 "Server send message to %s [%s] dropped from %s(Not local server)",
141     to->name, to->from->name, from->name);
142 adx 30 return;
143     }
144    
145     /* Optimize by checking if (from && to) before everything */
146     /* we set to->from up there.. */
147    
148     if (!MyClient(from) && IsClient(to) && (to == from->from))
149     {
150     if (IsServer(from))
151     {
152 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
153 adx 30 "Send message to %s [%s] dropped from %s(Fake Dir)",
154     to->name, to->from->name, from->name);
155     return;
156     }
157    
158 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
159 adx 30 "Ghosted: %s[%s@%s] from %s[%s@%s] (%s)",
160     to->name, to->username, to->host,
161     from->name, from->username, from->host,
162     to->from->name);
163    
164 michael 1474 sendto_server(NULL, CAP_TS6, NOCAPS,
165 adx 30 ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
166     me.id, to->name, me.name, to->name,
167     to->username, to->host, to->from->name);
168 michael 1474 sendto_server(NULL, NOCAPS, CAP_TS6,
169 adx 30 ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
170     me.name, to->name, me.name, to->name,
171     to->username, to->host, to->from->name);
172    
173 michael 1219 AddFlag(to, FLAGS_KILLED);
174 adx 30
175     if (IsClient(from))
176 michael 1834 sendto_one(from, form_str(ERR_GHOSTEDCLIENT),
177 adx 30 me.name, from->name, to->name, to->username,
178     to->host, to->from);
179    
180     exit_client(to, &me, "Ghosted client");
181     return;
182 michael 2638 }
183 adx 30
184     send_message(to, buf, len);
185     }
186    
187     /*
188     ** sendq_unblocked
189     ** Called when a socket is ready for writing.
190     */
191     void
192     sendq_unblocked(fde_t *fd, struct Client *client_p)
193     {
194 michael 2881 assert(fd == &client_p->localClient->fd);
195     send_queued_write(client_p);
196 adx 30 }
197    
198     /*
199     ** send_queued_write
200     ** This is called when there is a chance that some output would
201     ** be possible. This attempts to empty the send queue as far as
202     ** possible, and then if any data is left, a write is rescheduled.
203     */
204     void
205     send_queued_write(struct Client *to)
206     {
207 michael 2638 int retlen = 0;
208     struct dbuf_block *first = NULL;
209 adx 30
210     /*
211     ** Once socket is marked dead, we cannot start writing to it,
212     ** even if the error is removed...
213     */
214 michael 2881 if (IsDead(to))
215 adx 30 return; /* no use calling send() now */
216    
217     /* Next, lets try to write some data */
218     if (dbuf_length(&to->localClient->buf_sendq))
219     {
220 michael 2638 do
221     {
222 adx 30 first = to->localClient->buf_sendq.blocks.head->data;
223    
224     #ifdef HAVE_LIBCRYPTO
225     if (to->localClient->fd.ssl)
226     {
227     retlen = SSL_write(to->localClient->fd.ssl, first->data, first->size);
228    
229     /* translate openssl error codes, sigh */
230 michael 2638 if (retlen < 0)
231     {
232     switch (SSL_get_error(to->localClient->fd.ssl, retlen))
233     {
234 adx 30 case SSL_ERROR_WANT_READ:
235 michael 2638 return; /* retry later, don't register for write events */
236     case SSL_ERROR_WANT_WRITE:
237     errno = EWOULDBLOCK;
238 adx 30 case SSL_ERROR_SYSCALL:
239 michael 2638 break;
240 michael 430 case SSL_ERROR_SSL:
241     if (errno == EAGAIN)
242     break;
243 adx 30 default:
244 michael 2638 retlen = errno = 0; /* either an SSL-specific error or EOF */
245     }
246     }
247 adx 30 }
248     else
249     #endif
250     retlen = send(to->localClient->fd.fd, first->data, first->size, 0);
251    
252     if (retlen <= 0)
253     break;
254    
255     dbuf_delete(&to->localClient->buf_sendq, retlen);
256    
257     /* We have some data written .. update counters */
258     to->localClient->send.bytes += retlen;
259     me.localClient->send.bytes += retlen;
260     } while (dbuf_length(&to->localClient->buf_sendq));
261    
262     if ((retlen < 0) && (ignoreErrno(errno)))
263     {
264     /* we have a non-fatal error, reschedule a write */
265     comm_setselect(&to->localClient->fd, COMM_SELECT_WRITE,
266 michael 2654 (PF *)sendq_unblocked, to, 0);
267 adx 30 }
268     else if (retlen <= 0)
269     {
270     dead_link_on_write(to, errno);
271     return;
272     }
273     }
274     }
275    
276     /* send_queued_all()
277     *
278     * input - NONE
279     * output - NONE
280     * side effects - try to flush sendq of each client
281     */
282     void
283     send_queued_all(void)
284     {
285     dlink_node *ptr;
286    
287     /* Servers are processed first, mainly because this can generate
288     * a notice to opers, which is to be delivered by this function.
289     */
290     DLINK_FOREACH(ptr, serv_list.head)
291 michael 2638 send_queued_write(ptr->data);
292 adx 30
293     DLINK_FOREACH(ptr, unknown_list.head)
294 michael 2638 send_queued_write(ptr->data);
295 adx 30
296     DLINK_FOREACH(ptr, local_client_list.head)
297 michael 2638 send_queued_write(ptr->data);
298 adx 30
299     /* NOTE: This can still put clients on aborted_list; unfortunately,
300     * exit_aborted_clients takes precedence over send_queued_all,
301     * because exiting clients can generate server/oper traffic.
302     * The easiest approach is dealing with aborted clients in the next I/O lap.
303     * -adx
304     */
305     }
306    
307     /* sendto_one()
308     *
309     * inputs - pointer to destination client
310     * - var args message
311     * output - NONE
312     * side effects - send message to single client
313     */
314     void
315     sendto_one(struct Client *to, const char *pattern, ...)
316     {
317     va_list args;
318     char buffer[IRCD_BUFSIZE];
319     int len;
320    
321     if (to->from != NULL)
322     to = to->from;
323     if (IsDead(to))
324     return; /* This socket has already been marked as dead */
325    
326     va_start(args, pattern);
327 michael 2638 len = send_format(buffer, sizeof(buffer), pattern, args);
328 adx 30 va_end(args);
329    
330     send_message(to, buffer, len);
331     }
332    
333     /* sendto_channel_butone()
334     *
335     * inputs - pointer to client(server) to NOT send message to
336     * - pointer to client that is sending this message
337     * - pointer to channel being sent to
338     * - vargs message
339     * output - NONE
340     * side effects - message as given is sent to given channel members.
341     *
342     * WARNING - +D clients are ignored
343     */
344     void
345     sendto_channel_butone(struct Client *one, struct Client *from,
346 michael 1479 struct Channel *chptr, unsigned int type,
347 adx 30 const char *pattern, ...)
348     {
349 adx 285 va_list alocal, aremote, auid;
350 adx 30 char local_buf[IRCD_BUFSIZE];
351     char remote_buf[IRCD_BUFSIZE];
352     char uid_buf[IRCD_BUFSIZE];
353     int local_len, remote_len, uid_len;
354 michael 1078 dlink_node *ptr = NULL, *ptr_next = NULL;
355 adx 30
356     if (IsServer(from))
357 michael 2518 local_len = snprintf(local_buf, sizeof(local_buf), ":%s ",
358 michael 1793 from->name);
359 adx 30 else
360 michael 2518 local_len = snprintf(local_buf, sizeof(local_buf), ":%s!%s@%s ",
361     from->name, from->username, from->host);
362     remote_len = snprintf(remote_buf, sizeof(remote_buf), ":%s ",
363     from->name);
364     uid_len = snprintf(uid_buf, sizeof(uid_buf), ":%s ", ID(from));
365 adx 30
366 adx 285 va_start(alocal, pattern);
367     va_start(aremote, pattern);
368     va_start(auid, pattern);
369 adx 30 local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len,
370 adx 285 pattern, alocal);
371 adx 30 remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len,
372 adx 285 pattern, aremote);
373 adx 30 uid_len += send_format(&uid_buf[uid_len], IRCD_BUFSIZE - uid_len, pattern,
374 adx 285 auid);
375     va_end(auid);
376     va_end(aremote);
377     va_end(alocal);
378 adx 30
379     ++current_serial;
380    
381     DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->members.head)
382     {
383 michael 1479 struct Membership *ms = ptr->data;
384     struct Client *target_p = ms->client_p;
385 adx 30
386 michael 1078 assert(IsClient(target_p));
387    
388 michael 1219 if (IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF) || target_p->from == one)
389 adx 30 continue;
390    
391 michael 1479 if (type != 0 && (ms->flags & type) == 0)
392     continue;
393    
394 michael 1078 if (MyConnect(target_p))
395 adx 30 {
396 michael 1078 if (target_p->localClient->serial != current_serial)
397 adx 30 {
398     send_message(target_p, local_buf, local_len);
399 michael 1078 target_p->localClient->serial = current_serial;
400 adx 30 }
401     }
402     else
403     {
404     /* Now check whether a message has been sent to this
405     * remote link already
406     */
407 michael 1078 if (target_p->from->localClient->serial != current_serial)
408 adx 30 {
409     if (IsCapable(target_p->from, CAP_TS6))
410     send_message_remote(target_p->from, from, uid_buf, uid_len);
411     else
412     send_message_remote(target_p->from, from, remote_buf, remote_len);
413 michael 1078 target_p->from->localClient->serial = current_serial;
414 adx 30 }
415     }
416     }
417     }
418    
419     /* sendto_server()
420     *
421     * inputs - pointer to client to NOT send to
422 db 939 * - pointer to channel
423 adx 30 * - caps or'd together which must ALL be present
424     * - caps or'd together which must ALL NOT be present
425     * - printf style format string
426     * - args to format string
427     * output - NONE
428     * side effects - Send a message to all connected servers, except the
429     * client 'one' (if non-NULL), as long as the servers
430     * support ALL capabs in 'caps', and NO capabs in 'nocaps'.
431     *
432     * This function was written in an attempt to merge together the other
433     * billion sendto_*serv*() functions, which sprung up with capabs,
434     * lazylinks, uids, etc.
435     * -davidt
436     */
437 michael 2638 void
438 michael 1474 sendto_server(struct Client *one,
439 michael 1015 const unsigned int caps,
440     const unsigned int nocaps,
441 adx 30 const char *format, ...)
442     {
443     va_list args;
444 michael 885 dlink_node *ptr = NULL;
445 adx 30 char buffer[IRCD_BUFSIZE];
446 michael 885 int len = 0;
447 adx 30
448     va_start(args, format);
449 michael 2638 len = send_format(buffer, sizeof(buffer), format, args);
450 adx 30 va_end(args);
451    
452     DLINK_FOREACH(ptr, serv_list.head)
453     {
454 michael 885 struct Client *client_p = ptr->data;
455 adx 30
456     /* If dead already skip */
457     if (IsDead(client_p))
458     continue;
459     /* check against 'one' */
460     if (one != NULL && (client_p == one->from))
461     continue;
462     /* check we have required capabs */
463     if ((client_p->localClient->caps & caps) != caps)
464     continue;
465     /* check we don't have any forbidden capabs */
466     if ((client_p->localClient->caps & nocaps) != 0)
467     continue;
468    
469     send_message(client_p, buffer, len);
470     }
471     }
472    
473     /* sendto_common_channels_local()
474     *
475     * inputs - pointer to client
476     * - pattern to send
477     * output - NONE
478     * side effects - Sends a message to all people on local server who are
479     * in same channel with user.
480     * used by m_nick.c and exit_one_client.
481     */
482     void
483 michael 1734 sendto_common_channels_local(struct Client *user, int touser, unsigned int cap,
484 adx 30 const char *pattern, ...)
485     {
486     va_list args;
487     dlink_node *uptr;
488     dlink_node *cptr;
489     struct Channel *chptr;
490     struct Membership *ms;
491     struct Client *target_p;
492     char buffer[IRCD_BUFSIZE];
493     int len;
494    
495     va_start(args, pattern);
496 michael 2638 len = send_format(buffer, sizeof(buffer), pattern, args);
497 adx 30 va_end(args);
498    
499     ++current_serial;
500    
501     DLINK_FOREACH(cptr, user->channel.head)
502     {
503 michael 2638 chptr = ((struct Membership *)cptr->data)->chptr;
504 adx 30 assert(chptr != NULL);
505    
506 michael 572 DLINK_FOREACH(uptr, chptr->members.head)
507 adx 30 {
508     ms = uptr->data;
509     target_p = ms->client_p;
510     assert(target_p != NULL);
511    
512 michael 572 if (!MyConnect(target_p) || target_p == user || IsDefunct(target_p) ||
513 michael 1078 target_p->localClient->serial == current_serial)
514 adx 30 continue;
515    
516 michael 1734 if (HasCap(target_p, cap) != cap)
517     continue;
518    
519 michael 1078 target_p->localClient->serial = current_serial;
520 adx 30 send_message(target_p, buffer, len);
521     }
522     }
523    
524     if (touser && MyConnect(user) && !IsDead(user) &&
525 michael 1078 user->localClient->serial != current_serial)
526 michael 1844 if (HasCap(user, cap) == cap)
527 michael 1734 send_message(user, buffer, len);
528 adx 30 }
529    
530     /* sendto_channel_local()
531     *
532     * inputs - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
533     * - whether to ignore +D clients (YES/NO)
534     * - pointer to channel to send to
535     * - var args pattern
536     * output - NONE
537     * side effects - Send a message to all members of a channel that are
538     * locally connected to this server.
539     */
540     void
541 michael 2543 sendto_channel_local(unsigned int type, int nodeaf, struct Channel *chptr,
542 adx 30 const char *pattern, ...)
543     {
544     va_list args;
545     char buffer[IRCD_BUFSIZE];
546 michael 2638 int len = 0;
547     dlink_node *ptr = NULL;
548 adx 30
549     va_start(args, pattern);
550 michael 2638 len = send_format(buffer, sizeof(buffer), pattern, args);
551 adx 30 va_end(args);
552    
553 michael 572 DLINK_FOREACH(ptr, chptr->members.head)
554 adx 30 {
555 michael 2638 struct Membership *ms = ptr->data;
556     struct Client *target_p = ms->client_p;
557 adx 30
558     if (type != 0 && (ms->flags & type) == 0)
559     continue;
560    
561 michael 572 if (!MyConnect(target_p) || IsDefunct(target_p) ||
562 michael 1219 (nodeaf && HasUMode(target_p, UMODE_DEAF)))
563 adx 30 continue;
564    
565     send_message(target_p, buffer, len);
566     }
567     }
568    
569     /* sendto_channel_local_butone()
570     *
571     * inputs - pointer to client to NOT send message to
572     * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
573     * - pointer to channel to send to
574     * - var args pattern
575     * output - NONE
576     * side effects - Send a message to all members of a channel that are
577     * locally connected to this server except one.
578     *
579     * WARNING - +D clients are omitted
580     */
581 michael 2638 void
582 michael 2543 sendto_channel_local_butone(struct Client *one, unsigned int type, unsigned int cap,
583 michael 2638 struct Channel *chptr, const char *pattern, ...)
584 adx 30 {
585     va_list args;
586     char buffer[IRCD_BUFSIZE];
587 michael 2638 int len = 0;
588     dlink_node *ptr = NULL;
589 adx 30
590 michael 2638 va_start(args, pattern);
591     len = send_format(buffer, sizeof(buffer), pattern, args);
592 adx 30 va_end(args);
593    
594 michael 2638 DLINK_FOREACH(ptr, chptr->members.head)
595     {
596     struct Membership *ms = ptr->data;
597     struct Client *target_p = ms->client_p;
598 adx 30
599     if (type != 0 && (ms->flags & type) == 0)
600     continue;
601    
602 michael 572 if (!MyConnect(target_p) || target_p == one ||
603 michael 1219 IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF))
604 adx 30 continue;
605 michael 1734
606     if (HasCap(target_p, cap) != cap)
607 michael 2638 continue;
608    
609 adx 30 send_message(target_p, buffer, len);
610     }
611     }
612    
613    
614     /* sendto_channel_remote()
615     *
616     * inputs - Client not to send towards
617     * - Client from whom message is from
618     * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
619     * - pointer to channel to send to
620     * - var args pattern
621     * output - NONE
622     * side effects - Send a message to all members of a channel that are
623     * remote to this server.
624     */
625     void
626 michael 2543 sendto_channel_remote(struct Client *one, struct Client *from, unsigned int type,
627 michael 1015 const unsigned int caps, const unsigned int nocaps,
628     struct Channel *chptr, const char *pattern, ...)
629 adx 30 {
630     va_list args;
631     char buffer[IRCD_BUFSIZE];
632 michael 2638 int len = 0;
633     dlink_node *ptr = NULL;
634 adx 30
635     va_start(args, pattern);
636 michael 2638 len = send_format(buffer, sizeof(buffer), pattern, args);
637 adx 30 va_end(args);
638    
639 db 189 ++current_serial;
640    
641 adx 30 DLINK_FOREACH(ptr, chptr->members.head)
642     {
643 michael 2638 struct Membership *ms = ptr->data;
644     struct Client *target_p = ms->client_p;
645 adx 30
646     if (type != 0 && (ms->flags & type) == 0)
647     continue;
648    
649     if (MyConnect(target_p))
650     continue;
651 michael 2638
652 adx 30 target_p = target_p->from;
653    
654     if (target_p == one->from ||
655     ((target_p->from->localClient->caps & caps) != caps) ||
656     ((target_p->from->localClient->caps & nocaps) != 0))
657     continue;
658 michael 2638
659 michael 1078 if (target_p->from->localClient->serial != current_serial)
660 db 189 {
661     send_message(target_p, buffer, len);
662 michael 1078 target_p->from->localClient->serial = current_serial;
663 db 189 }
664 michael 2638 }
665 adx 30 }
666    
667     /*
668     ** match_it() and sendto_match_butone() ARE only used
669     ** to send a msg to all ppl on servers/hosts that match a specified mask
670     ** (used for enhanced PRIVMSGs) for opers
671     **
672     ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
673     **
674     */
675    
676     /* match_it()
677     *
678     * inputs - client pointer to match on
679     * - actual mask to match
680     * - what to match on, HOST or SERVER
681     * output - 1 or 0 if match or not
682     * side effects - NONE
683     */
684     static int
685 michael 2867 match_it(const struct Client *one, const char *mask, unsigned int what)
686 adx 30 {
687     if (what == MATCH_HOST)
688 michael 1652 return !match(mask, one->host);
689 adx 30
690 michael 1652 return !match(mask, one->servptr->name);
691 adx 30 }
692    
693     /* sendto_match_butone()
694     *
695     * Send to all clients which match the mask in a way defined on 'what';
696     * either by user hostname or user servername.
697     *
698     * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh.
699     */
700     void
701     sendto_match_butone(struct Client *one, struct Client *from, char *mask,
702     int what, const char *pattern, ...)
703     {
704 adx 285 va_list alocal, aremote;
705 adx 30 struct Client *client_p;
706     dlink_node *ptr, *ptr_next;
707     char local_buf[IRCD_BUFSIZE], remote_buf[IRCD_BUFSIZE];
708 michael 2518 int local_len = snprintf(local_buf, sizeof(local_buf), ":%s!%s@%s ",
709     from->name, from->username, from->host);
710     int remote_len = snprintf(remote_buf, sizeof(remote_buf), ":%s ",
711     from->name);
712 adx 30
713 adx 285 va_start(alocal, pattern);
714     va_start(aremote, pattern);
715 adx 30 local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len,
716 adx 285 pattern, alocal);
717 adx 30 remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len,
718 adx 285 pattern, aremote);
719     va_end(aremote);
720     va_end(alocal);
721 adx 30
722     /* scan the local clients */
723     DLINK_FOREACH(ptr, local_client_list.head)
724     {
725     client_p = ptr->data;
726    
727     if (client_p != one && !IsDefunct(client_p) &&
728     match_it(client_p, mask, what))
729     send_message(client_p, local_buf, local_len);
730     }
731    
732     /* Now scan servers */
733     DLINK_FOREACH_SAFE(ptr, ptr_next, serv_list.head)
734     {
735     client_p = ptr->data;
736    
737     /*
738     * The old code looped through every client on the
739     * network for each server to check if the
740     * server (client_p) has at least 1 client matching
741     * the mask, using something like:
742     *
743     * for (target_p = GlobalClientList; target_p; target_p = target_p->next)
744     * if (IsRegisteredUser(target_p) &&
745     * match_it(target_p, mask, what) &&
746     * (target_p->from == client_p))
747     * vsendto_prefix_one(client_p, from, pattern, args);
748     *
749     * That way, we wouldn't send the message to
750     * a server who didn't have a matching client.
751     * However, on a network such as EFNet, that
752     * code would have looped through about 50
753     * servers, and in each loop, loop through
754     * about 50k clients as well, calling match()
755     * in each nested loop. That is a very bad
756     * thing cpu wise - just send the message
757     * to every connected server and let that
758     * server deal with it.
759     * -wnder
760     */
761     if (client_p != one && !IsDefunct(client_p))
762     send_message_remote(client_p, from, remote_buf, remote_len);
763     }
764     }
765    
766     /* sendto_match_servs()
767     *
768     * inputs - source client
769     * - mask to send to
770     * - capab needed
771     * - data
772     * outputs - none
773     * side effects - data sent to servers matching with capab
774     */
775     void
776 michael 2543 sendto_match_servs(struct Client *source_p, const char *mask, unsigned int cap,
777 adx 30 const char *pattern, ...)
778     {
779     va_list args;
780 michael 2638 dlink_node *ptr = NULL;
781 michael 2793 char buff_suid[IRCD_BUFSIZE];
782     char buff_name[IRCD_BUFSIZE];
783     int len_suid = 0;
784     int len_name = 0;
785 adx 30
786     va_start(args, pattern);
787 michael 2793 len_suid = snprintf(buff_suid, sizeof(buff_suid), ":%s ", ID(source_p));
788     len_suid += send_format(&buff_suid[len_suid], sizeof(buff_suid) - len_suid,
789     pattern, args);
790 adx 30 va_end(args);
791    
792 michael 2793 va_start(args, pattern);
793     len_name = snprintf(buff_name, sizeof(buff_name), ":%s ", source_p->name);
794     len_name += send_format(&buff_name[len_name], sizeof(buff_name) - len_name,
795     pattern, args);
796     va_end(args);
797    
798 michael 948 ++current_serial;
799 adx 30
800     DLINK_FOREACH(ptr, global_serv_list.head)
801     {
802 michael 2638 struct Client *target_p = ptr->data;
803 adx 30
804     /* Do not attempt to send to ourselves, or the source */
805     if (IsMe(target_p) || target_p->from == source_p->from)
806     continue;
807    
808 michael 1078 if (target_p->from->localClient->serial == current_serial)
809 adx 30 continue;
810    
811 michael 1652 if (!match(mask, target_p->name))
812 adx 30 {
813     /*
814     * if we set the serial here, then we'll never do a
815     * match() again, if !IsCapable()
816     */
817 michael 1078 target_p->from->localClient->serial = current_serial;
818 adx 30
819     if (!IsCapable(target_p->from, cap))
820     continue;
821    
822 michael 2793 if (HasID(target_p->from))
823     send_message_remote(target_p->from, source_p, buff_suid, len_suid);
824     else
825     send_message_remote(target_p->from, source_p, buff_name, len_name);
826 adx 30 }
827     }
828     }
829    
830     /* sendto_anywhere()
831     *
832     * inputs - pointer to dest client
833     * - pointer to from client
834     * - varags
835     * output - NONE
836     * side effects - less efficient than sendto_remote and sendto_one
837     * but useful when one does not know where target "lives"
838     */
839     void
840     sendto_anywhere(struct Client *to, struct Client *from,
841 michael 2793 const char *command,
842 adx 30 const char *pattern, ...)
843     {
844     va_list args;
845     char buffer[IRCD_BUFSIZE];
846 michael 2793 int len = 0;
847 adx 30
848 michael 2793 if (IsDead(to->from))
849 adx 30 return;
850    
851     if (MyClient(to))
852     {
853     if (IsServer(from))
854 michael 2793 len = snprintf(buffer, sizeof(buffer), ":%s %s %s ",
855     from->name, command, to->name);
856 adx 30 else
857 michael 2793 len = snprintf(buffer, sizeof(buffer), ":%s!%s@%s %s %s ",
858     from->name, from->username, from->host, command, to->name);
859 adx 30 }
860 michael 2634 else
861 michael 2793 len = snprintf(buffer, sizeof(buffer), ":%s %s %s ",
862     ID_or_name(from, to), command,
863     ID_or_name(to, to));
864 adx 30
865     va_start(args, pattern);
866 michael 2793 len += send_format(&buffer[len], sizeof(buffer) - len, pattern, args);
867 adx 30 va_end(args);
868    
869 michael 2518 if (MyClient(to))
870 michael 2793 send_message(to, buffer, len);
871 adx 30 else
872 michael 2793 send_message_remote(to, from, buffer, len);
873 adx 30 }
874    
875     /* sendto_realops_flags()
876     *
877     * inputs - flag types of messages to show to real opers
878     * - flag indicating opers/admins
879     * - var args input message
880     * output - NONE
881     * side effects - Send to *local* ops only but NOT +s nonopers.
882     */
883     void
884 michael 1618 sendto_realops_flags(unsigned int flags, int level, int type, const char *pattern, ...)
885 adx 30 {
886 michael 1618 const char *ntype = NULL;
887 michael 1078 dlink_node *ptr = NULL;
888 adx 30 char nbuf[IRCD_BUFSIZE];
889     va_list args;
890    
891     va_start(args, pattern);
892 michael 1618 vsnprintf(nbuf, sizeof(nbuf), pattern, args);
893 adx 30 va_end(args);
894    
895 michael 1618 switch (type)
896 adx 30 {
897 michael 1618 case SEND_NOTICE:
898     ntype = "Notice";
899     break;
900     case SEND_GLOBAL:
901     ntype = "Global";
902     break;
903     case SEND_LOCOPS:
904     ntype = "LocOps";
905     break;
906     default:
907     assert(0);
908 adx 30 }
909    
910 michael 1206 DLINK_FOREACH(ptr, oper_list.head)
911     {
912     struct Client *client_p = ptr->data;
913 michael 1618 assert(HasUMode(client_p, UMODE_OPER));
914 michael 1206
915 michael 1618 /*
916     * If we're sending it to opers and they're an admin, skip.
917     * If we're sending it to admins, and they're not, skip.
918 michael 1206 */
919 michael 1219 if (((level == L_ADMIN) && !HasUMode(client_p, UMODE_ADMIN)) ||
920 michael 2638 ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN)))
921 michael 1206 continue;
922    
923 michael 1219 if (HasUMode(client_p, flags))
924 michael 1618 sendto_one(client_p, ":%s NOTICE %s :*** %s -- %s",
925     me.name, client_p->name, ntype, nbuf);
926 michael 1206 }
927     }
928    
929 adx 30 /* sendto_wallops_flags()
930     *
931     * inputs - flag types of messages to show to real opers
932     * - client sending request
933     * - var args input message
934     * output - NONE
935     * side effects - Send a wallops to local opers
936     */
937     void
938     sendto_wallops_flags(unsigned int flags, struct Client *source_p,
939     const char *pattern, ...)
940     {
941 michael 1078 dlink_node *ptr = NULL;
942 adx 30 va_list args;
943     char buffer[IRCD_BUFSIZE];
944     int len;
945    
946     if (IsClient(source_p))
947 michael 2518 len = snprintf(buffer, sizeof(buffer), ":%s!%s@%s WALLOPS :",
948 michael 2638 source_p->name, source_p->username,
949 michael 2518 source_p->host);
950 adx 30 else
951 michael 2518 len = snprintf(buffer, sizeof(buffer), ":%s WALLOPS :",
952     source_p->name);
953 adx 30
954     va_start(args, pattern);
955     len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args);
956     va_end(args);
957    
958     DLINK_FOREACH(ptr, oper_list.head)
959     {
960 michael 1078 struct Client *client_p = ptr->data;
961 adx 30 assert(client_p->umodes & UMODE_OPER);
962    
963 michael 1219 if (HasUMode(client_p, flags) && !IsDefunct(client_p))
964 adx 30 send_message(client_p, buffer, len);
965     }
966     }
967    
968     /* ts_warn()
969     *
970     * inputs - var args message
971     * output - NONE
972     * side effects - Call sendto_realops_flags, with some flood checking
973     * (at most 5 warnings every 5 seconds)
974     */
975     void
976     ts_warn(const char *pattern, ...)
977     {
978     va_list args;
979 michael 1078 char buffer[IRCD_BUFSIZE];
980 adx 30 static time_t last = 0;
981     static int warnings = 0;
982    
983     /*
984     ** if we're running with TS_WARNINGS enabled and someone does
985     ** something silly like (remotely) connecting a nonTS server,
986     ** we'll get a ton of warnings, so we make sure we don't send
987     ** more than 5 every 5 seconds. -orabidoo
988     */
989    
990     if (CurrentTime - last < 5)
991     {
992     if (++warnings > 5)
993     return;
994     }
995     else
996     {
997     last = CurrentTime;
998     warnings = 0;
999     }
1000    
1001     va_start(args, pattern);
1002 michael 1086 vsnprintf(buffer, sizeof(buffer), pattern, args);
1003 adx 30 va_end(args);
1004    
1005 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s", buffer);
1006 michael 1247 ilog(LOG_TYPE_IRCD, "%s", buffer);
1007 adx 30 }
1008    
1009     /* kill_client()
1010     *
1011     * inputs - client to send kill towards
1012     * - pointer to client to kill
1013     * - reason for kill
1014     * output - NONE
1015     * side effects - NONE
1016     */
1017     void
1018     kill_client(struct Client *client_p, struct Client *diedie,
1019     const char *pattern, ...)
1020     {
1021     va_list args;
1022     char buffer[IRCD_BUFSIZE];
1023     int len;
1024    
1025     if (client_p->from != NULL)
1026     client_p = client_p->from;
1027     if (IsDead(client_p))
1028     return;
1029    
1030 michael 2518 len = snprintf(buffer, sizeof(buffer), ":%s KILL %s :",
1031     ID_or_name(&me, client_p->from),
1032     ID_or_name(diedie, client_p));
1033 adx 30
1034     va_start(args, pattern);
1035     len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args);
1036     va_end(args);
1037    
1038     send_message(client_p, buffer, len);
1039     }
1040    
1041     /* kill_client_ll_serv_butone()
1042     *
1043     * inputs - pointer to client to not send to
1044     * - pointer to client to kill
1045     * output - NONE
1046     * side effects - Send a KILL for the given client
1047     * message to all connected servers
1048     * except the client 'one'. Also deal with
1049     * client being unknown to leaf, as in lazylink...
1050     */
1051     void
1052 michael 2565 kill_client_serv_butone(struct Client *one, struct Client *source_p,
1053     const char *pattern, ...)
1054 adx 30 {
1055     va_list args;
1056     int have_uid = 0;
1057 michael 885 dlink_node *ptr = NULL;
1058 adx 30 char buf_uid[IRCD_BUFSIZE], buf_nick[IRCD_BUFSIZE];
1059 michael 885 int len_uid = 0, len_nick = 0;
1060 adx 30
1061 michael 1115 if (HasID(source_p))
1062 adx 30 {
1063     have_uid = 1;
1064 adx 285 va_start(args, pattern);
1065 michael 2518 len_uid = snprintf(buf_uid, sizeof(buf_uid), ":%s KILL %s :",
1066     me.id, ID(source_p));
1067 michael 2638 len_uid += send_format(&buf_uid[len_uid], IRCD_BUFSIZE - len_uid, pattern, args);
1068 adx 285 va_end(args);
1069 adx 30 }
1070 adx 285
1071     va_start(args, pattern);
1072 michael 2518 len_nick = snprintf(buf_nick, sizeof(buf_nick), ":%s KILL %s :",
1073     me.name, source_p->name);
1074 michael 2638 len_nick += send_format(&buf_nick[len_nick], IRCD_BUFSIZE - len_nick, pattern, args);
1075 adx 30 va_end(args);
1076    
1077     DLINK_FOREACH(ptr, serv_list.head)
1078     {
1079 michael 885 struct Client *client_p = ptr->data;
1080 adx 30
1081     if (one != NULL && (client_p == one->from))
1082     continue;
1083     if (IsDefunct(client_p))
1084     continue;
1085    
1086 michael 885 if (have_uid && IsCapable(client_p, CAP_TS6))
1087     send_message(client_p, buf_uid, len_uid);
1088     else
1089     send_message(client_p, buf_nick, len_nick);
1090 adx 30 }
1091 michael 2638 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision