35 |
|
#include "numeric.h" |
36 |
|
#include "fdlist.h" |
37 |
|
#include "s_bsd.h" |
38 |
< |
#include "s_serv.h" |
38 |
> |
#include "server.h" |
39 |
|
#include "conf.h" |
40 |
|
#include "log.h" |
41 |
|
#include "memory.h" |
42 |
|
#include "packet.h" |
43 |
|
|
44 |
– |
#ifndef IOV_MAX |
45 |
– |
#define IOV_MAX 64 |
46 |
– |
#endif |
44 |
|
|
45 |
|
static unsigned int current_serial = 0; |
46 |
|
|
185 |
|
sendq_unblocked(fde_t *fd, struct Client *client_p) |
186 |
|
{ |
187 |
|
assert(fd == &client_p->localClient->fd); |
191 |
– |
send_queued_write(client_p); |
192 |
– |
} |
193 |
– |
|
194 |
– |
#ifdef HAVE_LIBCRYPTO |
195 |
– |
static int |
196 |
– |
send_SSL_writev(SSL *ssl, const struct iovec *vec, int iovcnt) |
197 |
– |
{ |
198 |
– |
int total_written = 0; |
199 |
– |
|
200 |
– |
for (int i = 0; i < iovcnt; ++i) |
201 |
– |
{ |
202 |
– |
const struct iovec *iov = &vec[i]; |
203 |
– |
int ret = 0; |
204 |
– |
|
205 |
– |
/* Translate openssl error codes, sigh */ |
206 |
– |
if ((ret = SSL_write(ssl, iov->iov_base, iov->iov_len)) <= 0) |
207 |
– |
{ |
208 |
– |
switch (SSL_get_error(ssl, i)) |
209 |
– |
{ |
210 |
– |
case SSL_ERROR_WANT_READ: |
211 |
– |
return -1; |
212 |
– |
case SSL_ERROR_WANT_WRITE: |
213 |
– |
errno = EWOULDBLOCK; |
214 |
– |
case SSL_ERROR_SYSCALL: |
215 |
– |
break; |
216 |
– |
case SSL_ERROR_SSL: |
217 |
– |
if (errno == EAGAIN) |
218 |
– |
break; |
219 |
– |
default: |
220 |
– |
errno = 0; /* Either an SSL-specific error or EOF */ |
221 |
– |
} |
222 |
– |
|
223 |
– |
return 0; |
224 |
– |
} |
225 |
– |
|
226 |
– |
total_written += ret; |
227 |
– |
} |
188 |
|
|
189 |
< |
return total_written; |
189 |
> |
DelFlag(client_p, FLAGS_BLOCKED); |
190 |
> |
send_queued_write(client_p); |
191 |
|
} |
231 |
– |
#endif |
192 |
|
|
193 |
|
/* |
194 |
|
** send_queued_write |
199 |
|
void |
200 |
|
send_queued_write(struct Client *to) |
201 |
|
{ |
202 |
< |
int retlen = 0, i = 0; |
243 |
< |
dlink_node *ptr = NULL; |
244 |
< |
struct iovec vec[IOV_MAX]; |
202 |
> |
int retlen = 0; |
203 |
|
|
204 |
|
/* |
205 |
< |
* Once socket is marked dead, we cannot start writing to it, |
206 |
< |
* even if the error is removed... |
205 |
> |
** Once socket is marked dead, we cannot start writing to it, |
206 |
> |
** even if the error is removed... |
207 |
|
*/ |
208 |
< |
if (IsDead(to)) |
209 |
< |
return; /* No use calling send() now */ |
252 |
< |
|
253 |
< |
if (HasFlag(to, FLAGS_CORK)) |
254 |
< |
return; |
255 |
< |
|
256 |
< |
/* Nothing to do? */ |
257 |
< |
if (!dbuf_length(&to->localClient->buf_sendq)) |
258 |
< |
return; |
208 |
> |
if (IsDead(to) || HasFlag(to, FLAGS_BLOCKED)) |
209 |
> |
return; /* no use calling send() now */ |
210 |
|
|
211 |
< |
/* Build iovec */ |
212 |
< |
DLINK_FOREACH(ptr, to->localClient->buf_sendq.blocks.head) |
211 |
> |
/* Next, lets try to write some data */ |
212 |
> |
if (dbuf_length(&to->localClient->buf_sendq)) |
213 |
|
{ |
214 |
< |
struct dbuf_block *block = ptr->data; |
215 |
< |
struct iovec *iov; |
216 |
< |
int offset; |
214 |
> |
do |
215 |
> |
{ |
216 |
> |
struct dbuf_block *first = to->localClient->buf_sendq.blocks.head->data; |
217 |
|
|
218 |
< |
if (i >= sizeof(vec) / sizeof(struct iovec)) |
219 |
< |
break; |
220 |
< |
|
221 |
< |
iov = &vec[i]; |
271 |
< |
offset = !i ? to->localClient->buf_sendq.pos : 0; |
218 |
> |
#ifdef HAVE_LIBCRYPTO |
219 |
> |
if (to->localClient->fd.ssl) |
220 |
> |
{ |
221 |
> |
retlen = SSL_write(to->localClient->fd.ssl, first->data + to->localClient->buf_sendq.pos, first->size - to->localClient->buf_sendq.pos); |
222 |
|
|
223 |
< |
iov->iov_base = block->data + offset; |
224 |
< |
iov->iov_len = block->size - offset; |
223 |
> |
/* translate openssl error codes, sigh */ |
224 |
> |
if (retlen < 0) |
225 |
> |
{ |
226 |
> |
switch (SSL_get_error(to->localClient->fd.ssl, retlen)) |
227 |
> |
{ |
228 |
> |
case SSL_ERROR_WANT_READ: |
229 |
> |
return; /* retry later, don't register for write events */ |
230 |
> |
case SSL_ERROR_WANT_WRITE: |
231 |
> |
errno = EWOULDBLOCK; |
232 |
> |
case SSL_ERROR_SYSCALL: |
233 |
> |
break; |
234 |
> |
case SSL_ERROR_SSL: |
235 |
> |
if (errno == EAGAIN) |
236 |
> |
break; |
237 |
> |
default: |
238 |
> |
retlen = errno = 0; /* either an SSL-specific error or EOF */ |
239 |
> |
} |
240 |
> |
} |
241 |
> |
} |
242 |
> |
else |
243 |
> |
#endif |
244 |
> |
retlen = send(to->localClient->fd.fd, first->data + to->localClient->buf_sendq.pos, first->size - to->localClient->buf_sendq.pos, 0); |
245 |
|
|
246 |
< |
++i; |
247 |
< |
} |
246 |
> |
if (retlen <= 0) |
247 |
> |
break; |
248 |
|
|
249 |
< |
/* Next, lets try to write some data */ |
280 |
< |
#ifdef HAVE_LIBCRYPTO |
281 |
< |
if (to->localClient->fd.ssl) |
282 |
< |
{ |
283 |
< |
if ((retlen = send_SSL_writev(to->localClient->fd.ssl, vec, i)) == -1) |
284 |
< |
return; |
285 |
< |
} |
286 |
< |
else |
287 |
< |
#endif |
288 |
< |
retlen = writev(to->localClient->fd.fd, vec, i); |
249 |
> |
dbuf_delete(&to->localClient->buf_sendq, retlen); |
250 |
|
|
251 |
< |
if (retlen > 0) |
252 |
< |
{ |
253 |
< |
dbuf_delete(&to->localClient->buf_sendq, retlen); |
251 |
> |
/* We have some data written .. update counters */ |
252 |
> |
to->localClient->send.bytes += retlen; |
253 |
> |
me.localClient->send.bytes += retlen; |
254 |
> |
} while (dbuf_length(&to->localClient->buf_sendq)); |
255 |
|
|
256 |
< |
/* We have some data written .. update counters */ |
257 |
< |
to->localClient->send.bytes += retlen; |
258 |
< |
me.localClient->send.bytes += retlen; |
256 |
> |
if (retlen < 0 && ignoreErrno(errno)) |
257 |
> |
{ |
258 |
> |
AddFlag(to, FLAGS_BLOCKED); |
259 |
|
|
260 |
< |
if (dbuf_length(&to->localClient->buf_sendq)) |
260 |
> |
/* we have a non-fatal error, reschedule a write */ |
261 |
|
comm_setselect(&to->localClient->fd, COMM_SELECT_WRITE, |
262 |
|
(PF *)sendq_unblocked, to, 0); |
263 |
+ |
} |
264 |
+ |
else if (retlen <= 0) |
265 |
+ |
{ |
266 |
+ |
dead_link_on_write(to, errno); |
267 |
+ |
return; |
268 |
+ |
} |
269 |
|
} |
302 |
– |
else if (retlen < 0 && ignoreErrno(errno)) |
303 |
– |
/* we have a non-fatal error, reschedule a write */ |
304 |
– |
comm_setselect(&to->localClient->fd, COMM_SELECT_WRITE, |
305 |
– |
(PF *)sendq_unblocked, to, 0); |
306 |
– |
else if (retlen <= 0) |
307 |
– |
dead_link_on_write(to, errno); |
270 |
|
} |
271 |
|
|
272 |
|
/* send_queued_all() |
331 |
|
sendto_one_numeric(struct Client *to, struct Client *from, enum irc_numerics numeric, ...) |
332 |
|
{ |
333 |
|
struct dbuf_block *buffer = NULL; |
334 |
< |
const char *dest = NULL; |
334 |
> |
const char *dest = NULL, *numstr = NULL; |
335 |
|
va_list args; |
336 |
|
|
337 |
|
if (IsDead(to->from)) |
338 |
|
return; |
339 |
|
|
340 |
|
dest = ID_or_name(to, to); |
341 |
+ |
|
342 |
|
if (EmptyString(dest)) |
343 |
|
dest = "*"; |
344 |
|
|
345 |
|
buffer = dbuf_alloc(); |
346 |
|
|
347 |
< |
dbuf_put_fmt(buffer, ":%s %03d %s ", ID_or_name(from, to), numeric, dest); |
347 |
> |
dbuf_put_fmt(buffer, ":%s %03d %s ", ID_or_name(from, to), numeric & ~SND_EXPLICIT, dest); |
348 |
|
|
349 |
|
va_start(args, numeric); |
350 |
< |
send_format(buffer, numeric_form(numeric), args); |
350 |
> |
|
351 |
> |
if (numeric & SND_EXPLICIT) |
352 |
> |
numstr = va_arg(args, const char *); |
353 |
> |
else |
354 |
> |
numstr = numeric_form(numeric); |
355 |
> |
send_format(buffer, numstr, args); |
356 |
|
va_end(args); |
357 |
|
|
358 |
|
send_message(to->from, buffer); |
371 |
|
return; |
372 |
|
|
373 |
|
dest = ID_or_name(to, to); |
374 |
+ |
|
375 |
|
if (EmptyString(dest)) |
376 |
|
dest = "*"; |
377 |
|
|
410 |
|
|
411 |
|
local_buf = dbuf_alloc(), remote_buf = dbuf_alloc(); |
412 |
|
|
413 |
< |
if (IsServer(from)) |
445 |
< |
dbuf_put_fmt(local_buf, ":%s ", from->name); |
446 |
< |
else |
413 |
> |
if (IsClient(from)) |
414 |
|
dbuf_put_fmt(local_buf, ":%s!%s@%s ", from->name, from->username, from->host); |
415 |
+ |
else |
416 |
+ |
dbuf_put_fmt(local_buf, ":%s ", from->name); |
417 |
|
|
418 |
|
dbuf_put_fmt(remote_buf, ":%s ", from->id); |
419 |
|
|
438 |
|
(one && target_p->from == one->from)) |
439 |
|
continue; |
440 |
|
|
441 |
< |
if (type != 0 && (ms->flags & type) == 0) |
441 |
> |
if (type && (ms->flags & type) == 0) |
442 |
|
continue; |
443 |
|
|
444 |
|
if (MyConnect(target_p)) |
494 |
|
if (IsDead(client_p)) |
495 |
|
continue; |
496 |
|
/* check against 'one' */ |
497 |
< |
if (one != NULL && (client_p == one->from)) |
497 |
> |
if (one && (client_p == one->from)) |
498 |
|
continue; |
499 |
|
/* check we have required capabs */ |
500 |
|
if ((client_p->localClient->caps & caps) != caps) |
501 |
|
continue; |
502 |
|
/* check we don't have any forbidden capabs */ |
503 |
< |
if ((client_p->localClient->caps & nocaps) != 0) |
503 |
> |
if ((client_p->localClient->caps & nocaps)) |
504 |
|
continue; |
505 |
|
|
506 |
|
send_message(client_p, buffer); |
541 |
|
DLINK_FOREACH(cptr, user->channel.head) |
542 |
|
{ |
543 |
|
chptr = ((struct Membership *)cptr->data)->chptr; |
575 |
– |
assert(chptr != NULL); |
544 |
|
|
545 |
< |
DLINK_FOREACH(uptr, chptr->members.head) |
545 |
> |
DLINK_FOREACH(uptr, chptr->locmembers.head) |
546 |
|
{ |
547 |
|
ms = uptr->data; |
548 |
|
target_p = ms->client_p; |
581 |
– |
assert(target_p != NULL); |
549 |
|
|
550 |
< |
if (!MyConnect(target_p) || target_p == user || IsDefunct(target_p) || |
550 |
> |
if (target_p == user || IsDefunct(target_p) || |
551 |
|
target_p->localClient->serial == current_serial) |
552 |
|
continue; |
553 |
|
|
591 |
|
send_format(buffer, pattern, args); |
592 |
|
va_end(args); |
593 |
|
|
594 |
< |
DLINK_FOREACH(ptr, chptr->members.head) |
594 |
> |
DLINK_FOREACH(ptr, chptr->locmembers.head) |
595 |
|
{ |
596 |
|
struct Membership *ms = ptr->data; |
597 |
|
struct Client *target_p = ms->client_p; |
598 |
|
|
599 |
< |
if (type != 0 && (ms->flags & type) == 0) |
599 |
> |
if (type && (ms->flags & type) == 0) |
600 |
|
continue; |
601 |
|
|
602 |
< |
if (!MyConnect(target_p) || IsDefunct(target_p) || |
602 |
> |
if (IsDefunct(target_p) || |
603 |
|
(nodeaf && HasUMode(target_p, UMODE_DEAF))) |
604 |
|
continue; |
605 |
|
|
635 |
|
send_format(buffer, pattern, args); |
636 |
|
va_end(args); |
637 |
|
|
638 |
< |
DLINK_FOREACH(ptr, chptr->members.head) |
638 |
> |
DLINK_FOREACH(ptr, chptr->locmembers.head) |
639 |
|
{ |
640 |
|
struct Membership *ms = ptr->data; |
641 |
|
struct Client *target_p = ms->client_p; |
642 |
|
|
643 |
< |
if (type != 0 && (ms->flags & type) == 0) |
643 |
> |
if (type && (ms->flags & type) == 0) |
644 |
|
continue; |
645 |
|
|
646 |
< |
if (!MyConnect(target_p) || (one && target_p == one->from)) |
646 |
> |
if (one && target_p == one->from) |
647 |
|
continue; |
648 |
|
|
649 |
|
if (IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF)) |
772 |
|
const char *pattern, ...) |
773 |
|
{ |
774 |
|
va_list args; |
775 |
< |
dlink_node *ptr = NULL; |
776 |
< |
struct dbuf_block *buff_suid; |
775 |
> |
dlink_node *ptr = NULL, *ptr_next = NULL; |
776 |
> |
struct dbuf_block *buffer; |
777 |
|
|
778 |
< |
buff_suid = dbuf_alloc(); |
778 |
> |
buffer = dbuf_alloc(); |
779 |
|
|
780 |
+ |
dbuf_put_fmt(buffer, ":%s ", source_p->id); |
781 |
|
va_start(args, pattern); |
782 |
< |
dbuf_put_fmt(buff_suid, ":%s ", source_p->id); |
815 |
< |
dbuf_put_args(buff_suid, pattern, args); |
782 |
> |
send_format(buffer, pattern, args); |
783 |
|
va_end(args); |
784 |
|
|
785 |
|
++current_serial; |
786 |
|
|
787 |
< |
DLINK_FOREACH(ptr, global_serv_list.head) |
787 |
> |
DLINK_FOREACH_SAFE(ptr, ptr_next, global_server_list.head) |
788 |
|
{ |
789 |
|
struct Client *target_p = ptr->data; |
790 |
|
|
806 |
|
if (!IsCapable(target_p->from, cap)) |
807 |
|
continue; |
808 |
|
|
809 |
< |
send_message_remote(target_p->from, source_p, buff_suid); |
809 |
> |
send_message_remote(target_p->from, source_p, buffer); |
810 |
|
} |
811 |
|
} |
812 |
|
|
813 |
< |
dbuf_ref_free(buff_suid); |
813 |
> |
dbuf_ref_free(buffer); |
814 |
|
} |
815 |
|
|
816 |
|
/* sendto_anywhere() |
923 |
|
static time_t last = 0; |
924 |
|
static int warnings = 0; |
925 |
|
|
959 |
– |
/* |
960 |
– |
** if we're running with TS_WARNINGS enabled and someone does |
961 |
– |
** something silly like (remotely) connecting a nonTS server, |
962 |
– |
** we'll get a ton of warnings, so we make sure we don't send |
963 |
– |
** more than 5 every 5 seconds. -orabidoo |
964 |
– |
*/ |
965 |
– |
|
926 |
|
if (CurrentTime - last < 5) |
927 |
|
{ |
928 |
|
if (++warnings > 5) |