ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/s_bsd.c
Revision: 8339
Committed: Sat Mar 3 22:47:06 2018 UTC (7 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 20216 byte(s)
Log Message:
- Restore fd_table. No longer allocate fde_t items from within any other structures like the AuthRequest, or Connection structure
- struct AuthRequest once again is no longer allocated from within the Connection structure

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 8279 * Copyright (c) 1997-2018 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21    
22 michael 2916 /*! \file s_bsd.c
23     * \brief Network functions.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28     #include <netinet/in_systm.h>
29     #include <netinet/ip.h>
30     #include <netinet/tcp.h>
31 michael 1011 #include "list.h"
32 adx 30 #include "fdlist.h"
33     #include "s_bsd.h"
34     #include "client.h"
35     #include "dbuf.h"
36     #include "event.h"
37     #include "irc_string.h"
38     #include "ircd.h"
39     #include "listener.h"
40     #include "numeric.h"
41     #include "packet.h"
42 michael 3322 #include "res.h"
43 adx 30 #include "restart.h"
44 michael 1309 #include "conf.h"
45     #include "log.h"
46 michael 3347 #include "server.h"
47 adx 30 #include "send.h"
48     #include "memory.h"
49 michael 3347 #include "user.h"
50 adx 30
51 michael 3274
52 michael 5887 static const char *const comm_err_str[] =
53     {
54     [COMM_OK] = "Comm OK",
55     [COMM_ERR_BIND] = "Error during bind()",
56     [COMM_ERR_DNS] = "Error during DNS lookup",
57     [COMM_ERR_TIMEOUT] = "connect timeout",
58     [COMM_ERR_CONNECT] = "Error during connect()",
59     [COMM_ERROR] = "Comm Error"
60     };
61 adx 30
62 michael 1013 static void comm_connect_callback(fde_t *, int);
63 michael 4461 static void comm_connect_timeout(fde_t *, void *);
64 michael 4408 static void comm_connect_dns_callback(void *, const struct irc_ssaddr *, const char *, size_t);
65 michael 4461 static void comm_connect_tryconnect(fde_t *, void *);
66 adx 30
67    
68     /* get_sockerr - get the error value from the socket or the current errno
69     *
70     * Get the *real* error from the socket (well try to anyway..).
71     * This may only work when SO_DEBUG is enabled but its worth the
72     * gamble anyway.
73     */
74     int
75     get_sockerr(int fd)
76     {
77     int errtmp = errno;
78     #ifdef SO_ERROR
79     int err = 0;
80     socklen_t len = sizeof(err);
81    
82 michael 967 if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len))
83 adx 30 {
84     if (err)
85     errtmp = err;
86     }
87     errno = errtmp;
88     #endif
89     return errtmp;
90     }
91    
92     /*
93 michael 2916 * report_error - report an error from an errno.
94 adx 30 * Record error to log and also send a copy to all *LOCAL* opers online.
95     *
96     * text is a *format* string for outputing error. It must
97     * contain only two '%s', the first will be replaced
98     * by the sockhost from the client_p, and the latter will
99     * be taken from sys_errlist[errno].
100     *
101     * client_p if not NULL, is the *LOCAL* client associated with
102     * the error.
103     *
104     * Cannot use perror() within daemon. stderr is closed in
105     * ircd and cannot be used. And, worse yet, it might have
106     * been reassigned to a normal connection...
107 michael 2916 *
108 adx 30 * Actually stderr is still there IFF ircd was run with -s --Rodder
109     */
110    
111     void
112 michael 2916 report_error(int level, const char* text, const char* who, int error)
113 adx 30 {
114     who = (who) ? who : "";
115    
116 michael 1618 sendto_realops_flags(UMODE_DEBUG, level, SEND_NOTICE,
117     text, who, strerror(error));
118 michael 1247 ilog(LOG_TYPE_IRCD, text, who, strerror(error));
119 adx 30 }
120    
121     /*
122     * setup_socket()
123     *
124     * Set the socket non-blocking, and other wonderful bits.
125     */
126 michael 2632 static void
127     setup_socket(int fd)
128 adx 30 {
129     int opt = 1;
130    
131 michael 967 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
132 adx 30
133     #ifdef IPTOS_LOWDELAY
134     opt = IPTOS_LOWDELAY;
135 michael 967 setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
136 adx 30 #endif
137    
138     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
139     }
140    
141     /*
142     * close_connection
143     * Close the physical connection. This function must make
144     * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
145     */
146     void
147     close_connection(struct Client *client_p)
148     {
149 michael 1391 assert(client_p);
150 adx 30
151 michael 683 if (!IsDead(client_p))
152     {
153 michael 3311 /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
154     /* there is still a chance that we might send data to this socket
155     * even if it is marked as blocked (COMM_SELECT_READ handler is called
156     * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
157 michael 683 */
158 michael 3312 DelFlag(client_p, FLAGS_BLOCKED);
159 michael 683 send_queued_write(client_p);
160     }
161    
162 michael 1143 if (IsClient(client_p))
163 adx 30 {
164 michael 1143 ++ServerStats.is_cl;
165 michael 4588 ServerStats.is_cbs += client_p->connection->send.bytes;
166     ServerStats.is_cbr += client_p->connection->recv.bytes;
167     ServerStats.is_cti += CurrentTime - client_p->connection->firsttime;
168 michael 1143 }
169     else if (IsServer(client_p))
170     {
171 michael 4815 dlink_node *node = NULL;
172    
173 michael 896 ++ServerStats.is_sv;
174 michael 4588 ServerStats.is_sbs += client_p->connection->send.bytes;
175     ServerStats.is_sbr += client_p->connection->recv.bytes;
176     ServerStats.is_sti += CurrentTime - client_p->connection->firsttime;
177 adx 30
178 michael 7401 DLINK_FOREACH(node, connect_items.head)
179 adx 30 {
180 michael 4815 struct MaskItem *conf = node->data;
181 michael 1391
182     if (irccmp(conf->name, client_p->name))
183     continue;
184    
185 adx 30 /*
186 michael 1391 * Reset next-connect cycle of all connect{} blocks that match
187     * this servername.
188 adx 30 */
189 michael 1649 conf->until = CurrentTime + conf->class->con_freq;
190 adx 30 }
191     }
192     else
193 michael 896 ++ServerStats.is_ni;
194 adx 30
195 michael 8339 if (tls_isusing(&client_p->connection->fd->ssl))
196     tls_shutdown(&client_p->connection->fd->ssl);
197 michael 451
198 michael 8339 if (&client_p->connection->fd)
199     {
200     fd_close(client_p->connection->fd);
201     client_p->connection->fd = NULL;
202     }
203 adx 30
204 michael 4588 dbuf_clear(&client_p->connection->buf_sendq);
205     dbuf_clear(&client_p->connection->buf_recvq);
206 michael 2916
207 michael 7032 xfree(client_p->connection->password);
208 michael 4588 client_p->connection->password = NULL;
209 michael 4439
210 michael 5583 detach_conf(client_p, CONF_CLIENT | CONF_OPER | CONF_SERVER);
211 adx 30 }
212    
213     /*
214     * ssl_handshake - let OpenSSL initialize the protocol. Register for
215     * read/write events if necessary.
216     */
217     static void
218 michael 8339 ssl_handshake(fde_t *F, void *data)
219 adx 30 {
220 michael 4461 struct Client *client_p = data;
221 adx 30
222 michael 8339 assert(client_p);
223     assert(client_p->connection);
224     assert(client_p->connection->fd);
225     assert(client_p->connection->fd == F);
226    
227     tls_handshake_status_t ret = tls_handshake(&F->ssl, TLS_ROLE_SERVER, NULL);
228 michael 7105 if (ret != TLS_HANDSHAKE_DONE)
229 michael 2463 {
230 michael 4737 if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
231 michael 2725 {
232 michael 7105 exit_client(client_p, "Timeout during TLS handshake");
233 michael 2725 return;
234     }
235    
236 michael 7105 switch (ret)
237 michael 2463 {
238 michael 7105 case TLS_HANDSHAKE_WANT_WRITE:
239 michael 8339 comm_setselect(client_p->connection->fd, COMM_SELECT_WRITE,
240 michael 4737 ssl_handshake, client_p, CONNECTTIMEOUT);
241 michael 2463 return;
242 michael 7105 case TLS_HANDSHAKE_WANT_READ:
243 michael 8339 comm_setselect(client_p->connection->fd, COMM_SELECT_READ,
244 michael 4737 ssl_handshake, client_p, CONNECTTIMEOUT);
245 michael 2463 return;
246     default:
247 michael 7105 exit_client(client_p, "Error during TLS handshake");
248 michael 2916 return;
249 michael 2463 }
250     }
251    
252 michael 8339 comm_settimeout(F, 0, NULL, NULL);
253 michael 2733
254 michael 8339 if (!tls_verify_cert(&F->ssl, ConfigServerInfo.message_digest_algorithm, &client_p->certfp))
255 michael 7142 ilog(LOG_TYPE_IRCD, "Client %s!%s@%s gave bad TLS client certificate",
256     client_p->name, client_p->username, client_p->host);
257 michael 2228
258 michael 7955 auth_start(client_p);
259 adx 30 }
260    
261     /*
262 michael 2916 * add_connection - creates a client which has just connected to us on
263 adx 30 * the given fd. The sockhost field is initialized with the ip# of the host.
264     * An unique id is calculated now, in case it is needed for auth.
265     * The client is sent to the auth module for verification, and not put in
266     * any client list yet.
267     */
268     void
269 michael 549 add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
270 adx 30 {
271 michael 7957 struct Client *client_p = client_make(NULL);
272 michael 549
273 michael 8339 client_p->connection->fd = fd_open(fd, 1, (listener->flags & LISTENER_SSL) ?
274     "Incoming SSL connection" : "Incoming connection");
275 adx 30
276 michael 1123 /*
277 adx 30 * copy address to 'sockhost' as a string, copy it to host too
278     * so we have something valid to put into error messages...
279     */
280 michael 8310 memcpy(&client_p->connection->ip, irn, sizeof(client_p->connection->ip));
281 adx 30
282 michael 5051 getnameinfo((const struct sockaddr *)&client_p->connection->ip,
283 michael 4588 client_p->connection->ip.ss_len, client_p->sockhost,
284 michael 3171 sizeof(client_p->sockhost), NULL, 0, NI_NUMERICHOST);
285 michael 4588 client_p->connection->aftype = client_p->connection->ip.ss.ss_family;
286 michael 1072
287 michael 8265 if (client_p->sockhost[0] == ':')
288 adx 30 {
289 michael 8265 client_p->sockhost[0] = '0';
290 michael 7431 memmove(client_p->sockhost + 1, client_p->sockhost, sizeof(client_p->sockhost) - 1);
291 michael 549 }
292 adx 30
293 michael 8265 strlcpy(client_p->host, client_p->sockhost, sizeof(client_p->host));
294    
295 michael 4588 client_p->connection->listener = listener;
296 adx 30 ++listener->ref_count;
297    
298 michael 7274 if (listener->flags & LISTENER_SSL)
299 adx 30 {
300 michael 8339 if (!tls_new(&client_p->connection->fd->ssl, fd, TLS_ROLE_SERVER))
301 adx 30 {
302 michael 3171 SetDead(client_p);
303 michael 7105 exit_client(client_p, "TLS context initialization failed");
304 adx 30 return;
305     }
306    
307 michael 3171 AddFlag(client_p, FLAGS_SSL);
308 michael 8339 ssl_handshake(client_p->connection->fd, client_p);
309 adx 30 }
310     else
311 michael 7955 auth_start(client_p);
312 adx 30 }
313    
314     /*
315     * stolen from squid - its a neat (but overused! :) routine which we
316     * can use to see whether we can ignore this errno or not. It is
317     * generally useful for non-blocking network IO related errnos.
318     * -- adrian
319     */
320     int
321     ignoreErrno(int ierrno)
322     {
323     switch (ierrno)
324     {
325     case EINPROGRESS:
326     case EWOULDBLOCK:
327     #if EAGAIN != EWOULDBLOCK
328     case EAGAIN:
329     #endif
330     case EALREADY:
331     case EINTR:
332     #ifdef ERESTART
333     case ERESTART:
334     #endif
335     return 1;
336     default:
337     return 0;
338     }
339     }
340    
341     /*
342     * comm_settimeout() - set the socket timeout
343     *
344     * Set the timeout for the fd
345     */
346     void
347 michael 8339 comm_settimeout(fde_t *F, uintmax_t timeout, void (*callback)(fde_t *, void *), void *cbdata)
348 adx 30 {
349 michael 8339 assert(F->flags.open);
350 adx 30
351 michael 8339 F->timeout = CurrentTime + (timeout / 1000);
352     F->timeout_handler = callback;
353     F->timeout_data = cbdata;
354 adx 30 }
355    
356     /*
357     * comm_setflush() - set a flush function
358     *
359     * A flush function is simply a function called if found during
360     * comm_timeouts(). Its basically a second timeout, except in this case
361     * I'm too lazy to implement multiple timeout functions! :-)
362     * its kinda nice to have it separate, since this is designed for
363     * flush functions, and when comm_close() is implemented correctly
364     * with close functions, we _actually_ don't call comm_close() here ..
365     * -- originally Adrian's notes
366 michael 2916 * comm_close() is replaced with fd_close() in fdlist.c
367 adx 30 */
368     void
369 michael 8339 comm_setflush(fde_t *F, uintmax_t timeout, void (*callback)(fde_t *, void *), void *cbdata)
370 adx 30 {
371 michael 8339 assert(F->flags.open);
372 adx 30
373 michael 8339 F->flush_timeout = CurrentTime + (timeout / 1000);
374     F->flush_handler = callback;
375     F->flush_data = cbdata;
376 adx 30 }
377    
378     /*
379     * comm_checktimeouts() - check the socket timeouts
380     *
381     * All this routine does is call the given callback/cbdata, without closing
382     * down the file descriptor. When close handlers have been implemented,
383     * this will happen.
384     */
385     void
386 michael 4439 comm_checktimeouts(void *unused)
387 adx 30 {
388 michael 4461 void (*hdl)(fde_t *, void *);
389 adx 30 void *data;
390    
391 michael 8339 for (int fd = 0; fd <= highest_fd; ++fd)
392 michael 7431 {
393 michael 8339 fde_t *F = &fd_table[fd];
394 adx 30
395 michael 8339 if (F->flags.open == 0)
396     continue;
397 adx 30
398 michael 8339 /* check flush functions */
399     if (F->flush_handler && F->flush_timeout > 0 &&
400     F->flush_timeout < CurrentTime)
401     {
402     hdl = F->flush_handler;
403     data = F->flush_data;
404     comm_setflush(F, 0, NULL, NULL);
405     hdl(F, data);
406 adx 30 }
407 michael 8339
408     /* check timeouts */
409     if (F->timeout_handler && F->timeout > 0 &&
410     F->timeout < CurrentTime)
411     {
412     /* Call timeout handler */
413     hdl = F->timeout_handler;
414     data = F->timeout_data;
415     comm_settimeout(F, 0, NULL, NULL);
416     hdl(F, data);
417     }
418 michael 7431 }
419 adx 30 }
420    
421     /*
422     * void comm_connect_tcp(int fd, const char *host, unsigned short port,
423     * struct sockaddr *clocal, int socklen,
424     * CNCB *callback, void *data, int aftype, int timeout)
425     * Input: An fd to connect with, a host and port to connect to,
426     * a local sockaddr to connect from + length(or NULL to use the
427     * default), a callback, the data to pass into the callback, the
428     * address family.
429     * Output: None.
430     * Side-effects: A non-blocking connection to the host is started, and
431     * if necessary, set up for selection. The callback given
432     * may be called now, or it may be called later.
433     */
434     void
435 michael 8339 comm_connect_tcp(fde_t *F, const char *host, unsigned short port, struct sockaddr *clocal,
436 michael 4464 int socklen, void (*callback)(fde_t *, int, void *), void *data,
437 michael 7330 int aftype, uintmax_t timeout)
438 adx 30 {
439     struct addrinfo hints, *res;
440 michael 992 char portname[PORTNAMELEN + 1];
441 adx 30
442     assert(callback);
443 michael 8339 F->connect.callback = callback;
444     F->connect.data = data;
445 adx 30
446 michael 8339 F->connect.hostaddr.ss.ss_family = aftype;
447     F->connect.hostaddr.ss_port = htons(port);
448 adx 30
449     /* Note that we're using a passed sockaddr here. This is because
450     * generally you'll be bind()ing to a sockaddr grabbed from
451     * getsockname(), so this makes things easier.
452     * XXX If NULL is passed as local, we should later on bind() to the
453     * virtual host IP, for completeness.
454     * -- adrian
455     */
456 michael 8339 if (clocal && bind(F->fd, clocal, socklen) < 0)
457 michael 2916 {
458 adx 30 /* Failure, call the callback with COMM_ERR_BIND */
459 michael 8339 comm_connect_callback(F, COMM_ERR_BIND);
460 michael 6948 return; /* ... and quit */
461 adx 30 }
462    
463     memset(&hints, 0, sizeof(hints));
464 michael 7431
465 adx 30 hints.ai_family = AF_UNSPEC;
466     hints.ai_socktype = SOCK_STREAM;
467     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
468    
469 michael 992 snprintf(portname, sizeof(portname), "%d", port);
470 adx 30
471 michael 6948 /*
472     * Next, if we have been given an IP address, get the address and skip the
473     * DNS check (and head direct to comm_connect_tryconnect()).
474     */
475 michael 1123 if (getaddrinfo(host, portname, &hints, &res))
476 adx 30 {
477     /* Send the DNS request, for the next level */
478 db 871 if (aftype == AF_INET6)
479 michael 8339 gethost_byname_type(comm_connect_dns_callback, F, host, T_AAAA);
480 db 871 else
481 michael 8339 gethost_byname_type(comm_connect_dns_callback, F, host, T_A);
482 adx 30 }
483     else
484     {
485     /* We have a valid IP, so we just call tryconnect */
486     /* Make sure we actually set the timeout here .. */
487 michael 7431 assert(res);
488    
489 michael 8339 memcpy(&F->connect.hostaddr, res->ai_addr, res->ai_addrlen);
490     F->connect.hostaddr.ss_len = res->ai_addrlen;
491     F->connect.hostaddr.ss.ss_family = res->ai_family;
492 michael 1123 freeaddrinfo(res);
493 michael 7431
494 michael 8339 comm_settimeout(F, timeout * 1000, comm_connect_timeout, NULL);
495     comm_connect_tryconnect(F, NULL);
496 adx 30 }
497     }
498    
499     /*
500     * comm_connect_callback() - call the callback, and continue with life
501     */
502     static void
503 michael 8339 comm_connect_callback(fde_t *F, int status)
504 adx 30 {
505 michael 4464 void (*hdl)(fde_t *, int, void *);
506 adx 30
507     /* This check is gross..but probably necessary */
508 michael 8339 if (F->connect.callback == NULL)
509 adx 30 return;
510    
511     /* Clear the connect flag + handler */
512 michael 8339 hdl = F->connect.callback;
513     F->connect.callback = NULL;
514 adx 30
515     /* Clear the timeout handler */
516 michael 8339 comm_settimeout(F, 0, NULL, NULL);
517 adx 30
518     /* Call the handler */
519 michael 8339 hdl(F, status, F->connect.data);
520 adx 30 }
521    
522     /*
523     * comm_connect_timeout() - this gets called when the socket connection
524     * times out. This *only* can be called once connect() is initially
525     * called ..
526     */
527     static void
528 michael 8339 comm_connect_timeout(fde_t *F, void *unused)
529 adx 30 {
530     /* error! */
531 michael 8339 comm_connect_callback(F, COMM_ERR_TIMEOUT);
532 adx 30 }
533    
534     /*
535     * comm_connect_dns_callback() - called at the completion of the DNS request
536     *
537     * The DNS request has completed, so if we've got an error, return it,
538     * otherwise we initiate the connect()
539     */
540     static void
541 michael 4408 comm_connect_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name, size_t namelength)
542 adx 30 {
543 michael 7431 fde_t *const F = vptr;
544 adx 30
545 michael 4411 if (!addr)
546 adx 30 {
547     comm_connect_callback(F, COMM_ERR_DNS);
548     return;
549     }
550    
551 michael 8339 /* No error, set a 30 second timeout */
552     comm_settimeout(F, 30 * 1000, comm_connect_timeout, NULL);
553 adx 30
554     /* Copy over the DNS reply info so we can use it in the connect() */
555     /*
556     * Note we don't fudge the refcount here, because we aren't keeping
557 michael 2916 * the DNS record around, and the DNS cache is gone anyway..
558 adx 30 * -- adrian
559     */
560 michael 992 memcpy(&F->connect.hostaddr, addr, addr->ss_len);
561 michael 7431
562 adx 30 /* The cast is hacky, but safe - port offset is same on v4 and v6 */
563 michael 7431 ((struct sockaddr_in *)&F->connect.hostaddr)->sin_port = F->connect.hostaddr.ss_port;
564 michael 992 F->connect.hostaddr.ss_len = addr->ss_len;
565 adx 30
566     /* Now, call the tryconnect() routine to try a connect() */
567     comm_connect_tryconnect(F, NULL);
568     }
569    
570 michael 8339 /* static void comm_connect_tryconnect(fde_t *fd, void *unused)
571 adx 30 * Input: The fd, the handler data(unused).
572     * Output: None.
573     * Side-effects: Try and connect with pending connect data for the FD. If
574     * we succeed or get a fatal error, call the callback.
575     * Otherwise, it is still blocking or something, so register
576     * to select for a write event on this FD.
577     */
578     static void
579 michael 8339 comm_connect_tryconnect(fde_t *F, void *unused)
580 adx 30 {
581     /* This check is needed or re-entrant s_bsd_* like sigio break it. */
582 michael 8339 if (F->connect.callback == NULL)
583 adx 30 return;
584    
585     /* Try the connect() */
586 michael 8339 int retval = connect(F->fd, (struct sockaddr *)&F->connect.hostaddr, F->connect.hostaddr.ss_len);
587 adx 30
588     /* Error? */
589     if (retval < 0)
590     {
591     /*
592     * If we get EISCONN, then we've already connect()ed the socket,
593     * which is a good thing.
594     * -- adrian
595     */
596     if (errno == EISCONN)
597 michael 8339 comm_connect_callback(F, COMM_OK);
598 adx 30 else if (ignoreErrno(errno))
599     /* Ignore error? Reschedule */
600 michael 8339 comm_setselect(F, COMM_SELECT_WRITE, comm_connect_tryconnect, NULL, 0);
601 adx 30 else
602     /* Error? Fail with COMM_ERR_CONNECT */
603 michael 8339 comm_connect_callback(F, COMM_ERR_CONNECT);
604 adx 30 return;
605     }
606    
607     /* If we get here, we've suceeded, so call with COMM_OK */
608 michael 8339 comm_connect_callback(F, COMM_OK);
609 adx 30 }
610    
611     /*
612     * comm_errorstr() - return an error string for the given error condition
613     */
614     const char *
615     comm_errstr(int error)
616     {
617     if (error < 0 || error >= COMM_ERR_MAX)
618     return "Invalid error number!";
619     return comm_err_str[error];
620     }
621    
622     /*
623     * comm_open() - open a socket
624     *
625     * This is a highly highly cut down version of squid's comm_open() which
626     * for the most part emulates socket(), *EXCEPT* it fails if we're about
627     * to run out of file descriptors.
628     */
629     int
630 michael 8339 comm_socket(int family, int sock_type, int proto)
631 adx 30 {
632     /* First, make sure we aren't going to run out of file descriptors */
633     if (number_fd >= hard_fdlimit)
634     {
635     errno = ENFILE;
636     return -1;
637     }
638    
639     /*
640     * Next, we try to open the socket. We *should* drop the reserved FD
641     * limit if/when we get an error, but we can deal with that later.
642     * XXX !!! -- adrian
643     */
644 michael 7431 int fd = socket(family, sock_type, proto);
645 adx 30 if (fd < 0)
646     return -1; /* errno will be passed through, yay.. */
647    
648 michael 2632 setup_socket(fd);
649 adx 30
650 michael 8339 return fd;
651 adx 30 }
652    
653     /*
654     * comm_accept() - accept an incoming connection
655     *
656     * This is a simple wrapper for accept() which enforces FD limits like
657     * comm_open() does. Returned fd must be either closed or tagged with
658     * fd_open (this function no longer does it).
659     */
660     int
661 michael 8339 comm_accept(int fd, struct irc_ssaddr *addr)
662 adx 30 {
663     socklen_t addrlen = sizeof(struct irc_ssaddr);
664    
665     if (number_fd >= hard_fdlimit)
666     {
667     errno = ENFILE;
668     return -1;
669     }
670    
671 michael 4413 memset(addr, 0, sizeof(struct irc_ssaddr));
672 michael 4407
673 adx 30 /*
674     * Next, do the accept(). if we get an error, we should drop the
675     * reserved fd limit, but we can deal with that when comm_open()
676     * also does it. XXX -- adrian
677     */
678 michael 8339 int new_fd = accept(fd, (struct sockaddr *)addr, &addrlen);
679     if (new_fd < 0)
680 adx 30 return -1;
681    
682 michael 4407 remove_ipv6_mapping(addr);
683 adx 30
684 michael 8339 setup_socket(new_fd);
685 adx 30
686     /* .. and return */
687 michael 8339 return new_fd;
688 adx 30 }
689    
690 michael 2916 /*
691 adx 30 * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
692 michael 1122 * OSes with IPv6 mapping listening on both
693 adx 30 * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
694 michael 2916 *
695 adx 30 */
696     void
697     remove_ipv6_mapping(struct irc_ssaddr *addr)
698     {
699     if (addr->ss.ss_family == AF_INET6)
700     {
701 michael 1122 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr))
702     {
703 michael 2916 struct sockaddr_in6 v6;
704 michael 1122 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
705 adx 30
706 michael 1122 memcpy(&v6, addr, sizeof(v6));
707     memset(v4, 0, sizeof(struct sockaddr_in));
708     memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr));
709    
710 adx 30 addr->ss.ss_family = AF_INET;
711     addr->ss_len = sizeof(struct sockaddr_in);
712     }
713 michael 2916 else
714 adx 30 addr->ss_len = sizeof(struct sockaddr_in6);
715     }
716     else
717     addr->ss_len = sizeof(struct sockaddr_in);
718 michael 2916 }

Properties

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