PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/s_bsd.c

https://bitbucket.org/rizon/ircd/
C | 834 lines | 498 code | 91 blank | 245 comment | 71 complexity | e2aadebee1d7be73151cef71c8c9434b MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /*
  2. * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
  3. * s_bsd.c: Network functions.
  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. * $Id: s_bsd.c 465 2006-12-28 02:31:10Z jon $
  23. */
  24. #include "stdinc.h"
  25. #ifndef _WIN32
  26. #include <netinet/in_systm.h>
  27. #include <netinet/ip.h>
  28. #include <netinet/tcp.h>
  29. #endif
  30. #include "fdlist.h"
  31. #include "s_bsd.h"
  32. #include "client.h"
  33. #include "common.h"
  34. #include "dbuf.h"
  35. #include "event.h"
  36. #include "irc_string.h"
  37. #include "irc_getnameinfo.h"
  38. #include "irc_getaddrinfo.h"
  39. #include "ircd.h"
  40. #include "list.h"
  41. #include "listener.h"
  42. #include "numeric.h"
  43. #include "packet.h"
  44. #include "irc_res.h"
  45. #include "inet_misc.h"
  46. #include "restart.h"
  47. #include "s_auth.h"
  48. #include "s_conf.h"
  49. #include "s_log.h"
  50. #include "s_serv.h"
  51. #include "s_stats.h"
  52. #include "send.h"
  53. #include "memory.h"
  54. #include "s_user.h"
  55. #include "hook.h"
  56. static const char *comm_err_str[] = { "Comm OK", "Error during bind()",
  57. "Error during DNS lookup", "connect timeout", "Error during connect()",
  58. "Comm Error"
  59. };
  60. struct Callback *setup_socket_cb = NULL;
  61. static void comm_connect_callback(fde_t * fd, int status);
  62. static PF comm_connect_timeout;
  63. static void comm_connect_dns_callback(void *vptr, struct DNSReply *reply);
  64. static PF comm_connect_tryconnect;
  65. extern void init_netio(void);
  66. /* check_can_use_v6()
  67. * Check if the system can open AF_INET6 sockets
  68. */
  69. void
  70. check_can_use_v6(void)
  71. {
  72. #ifdef IPV6
  73. int v6;
  74. if((v6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
  75. ServerInfo.can_use_v6 = 0;
  76. else
  77. {
  78. ServerInfo.can_use_v6 = 1;
  79. #ifdef _WIN32
  80. closesocket(v6);
  81. #else
  82. close(v6);
  83. #endif
  84. }
  85. #else
  86. ServerInfo.can_use_v6 = 0;
  87. #endif
  88. }
  89. /* get_sockerr - get the error value from the socket or the current errno
  90. *
  91. * Get the *real* error from the socket (well try to anyway..).
  92. * This may only work when SO_DEBUG is enabled but its worth the
  93. * gamble anyway.
  94. */
  95. int
  96. get_sockerr(int fd)
  97. {
  98. #ifndef _WIN32
  99. int errtmp = errno;
  100. #else
  101. int errtmp = WSAGetLastError();
  102. #endif
  103. #ifdef SO_ERROR
  104. int err = 0;
  105. socklen_t len = sizeof(err);
  106. if(-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &err, (socklen_t *) & len))
  107. {
  108. if(err)
  109. errtmp = err;
  110. }
  111. errno = errtmp;
  112. #endif
  113. return errtmp;
  114. }
  115. /*
  116. * report_error - report an error from an errno.
  117. * Record error to log and also send a copy to all *LOCAL* opers online.
  118. *
  119. * text is a *format* string for outputing error. It must
  120. * contain only two '%s', the first will be replaced
  121. * by the sockhost from the client_p, and the latter will
  122. * be taken from sys_errlist[errno].
  123. *
  124. * client_p if not NULL, is the *LOCAL* client associated with
  125. * the error.
  126. *
  127. * Cannot use perror() within daemon. stderr is closed in
  128. * ircd and cannot be used. And, worse yet, it might have
  129. * been reassigned to a normal connection...
  130. *
  131. * Actually stderr is still there IFF ircd was run with -s --Rodder
  132. */
  133. void
  134. report_error(int level, const char *text, const char *who, int error)
  135. {
  136. who = (who) ? who : "";
  137. sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error));
  138. log_oper_action(LOG_IOERR_TYPE, NULL, "%s %s %s\n", who, text, strerror(error));
  139. ilog(L_ERROR, text, who, strerror(error));
  140. }
  141. /*
  142. * setup_socket()
  143. *
  144. * Set the socket non-blocking, and other wonderful bits.
  145. */
  146. static void *
  147. setup_socket(va_list args)
  148. {
  149. int fd = va_arg(args, int);
  150. int opt = 1;
  151. setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &opt, sizeof(opt));
  152. #ifdef IPTOS_LOWDELAY
  153. opt = IPTOS_LOWDELAY;
  154. setsockopt(fd, IPPROTO_IP, IP_TOS, (char *) &opt, sizeof(opt));
  155. #endif
  156. #ifndef _WIN32
  157. fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
  158. #endif
  159. return NULL;
  160. }
  161. /*
  162. * init_comm()
  163. *
  164. * Initializes comm subsystem.
  165. */
  166. void
  167. init_comm(void)
  168. {
  169. setup_socket_cb = register_callback("setup_socket", setup_socket);
  170. init_netio();
  171. }
  172. /*
  173. * close_connection
  174. * Close the physical connection. This function must make
  175. * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
  176. */
  177. void
  178. close_connection(struct Client *client_p)
  179. {
  180. struct ConfItem *conf;
  181. struct AccessItem *aconf;
  182. struct ClassItem *aclass;
  183. assert(NULL != client_p);
  184. if(!IsDead(client_p))
  185. {
  186. /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
  187. /* there is still a chance that we might send data to this socket
  188. * even if it is marked as blocked (COMM_SELECT_READ handler is called
  189. * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
  190. */
  191. ClearSendqBlocked(client_p);
  192. send_queued_write(client_p);
  193. }
  194. if(IsServer(client_p))
  195. {
  196. ServerStats->is_sv++;
  197. ServerStats->is_sbs += client_p->localClient->send.bytes;
  198. ServerStats->is_sbr += client_p->localClient->recv.bytes;
  199. ServerStats->is_sti += CurrentTime - client_p->firsttime;
  200. /* XXX Does this even make any sense at all anymore?
  201. * scheduling a 'quick' reconnect could cause a pile of
  202. * nick collides under TSora protocol... -db
  203. */
  204. /*
  205. * If the connection has been up for a long amount of time, schedule
  206. * a 'quick' reconnect, else reset the next-connect cycle.
  207. */
  208. if((conf = find_conf_exact(SERVER_TYPE,
  209. client_p->name, client_p->username, client_p->host)))
  210. {
  211. /*
  212. * Reschedule a faster reconnect, if this was a automatically
  213. * connected configuration entry. (Note that if we have had
  214. * a rehash in between, the status has been changed to
  215. * CONF_ILLEGAL). But only do this if it was a "good" link.
  216. */
  217. aconf = (struct AccessItem *) map_to_conf(conf);
  218. aclass = (struct ClassItem *) map_to_conf(aconf->class_ptr);
  219. aconf->hold = time(NULL);
  220. aconf->hold += (aconf->hold - client_p->since > HANGONGOODLINK) ?
  221. HANGONRETRYDELAY : ConFreq(aclass);
  222. if(nextconnect > aconf->hold)
  223. nextconnect = aconf->hold;
  224. }
  225. }
  226. else if(IsClient(client_p))
  227. {
  228. ServerStats->is_cl++;
  229. ServerStats->is_cbs += client_p->localClient->send.bytes;
  230. ServerStats->is_cbr += client_p->localClient->recv.bytes;
  231. ServerStats->is_cti += CurrentTime - client_p->firsttime;
  232. }
  233. else
  234. ServerStats->is_ni++;
  235. #ifdef HAVE_LIBCRYPTO
  236. if(client_p->localClient->fd.ssl)
  237. {
  238. SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN);
  239. if(!SSL_shutdown(client_p->localClient->fd.ssl))
  240. SSL_shutdown(client_p->localClient->fd.ssl);
  241. }
  242. #endif
  243. if(client_p->localClient->fd.flags.open)
  244. fd_close(&client_p->localClient->fd);
  245. if(HasServlink(client_p))
  246. {
  247. if(client_p->localClient->ctrlfd.flags.open)
  248. fd_close(&client_p->localClient->ctrlfd);
  249. }
  250. dbuf_clear(&client_p->localClient->buf_sendq);
  251. dbuf_clear(&client_p->localClient->buf_recvq);
  252. MyFree(client_p->localClient->passwd);
  253. detach_conf(client_p, CONF_TYPE);
  254. client_p->from = NULL; /* ...this should catch them! >:) --msa */
  255. }
  256. #ifdef HAVE_LIBCRYPTO
  257. /*
  258. * ssl_handshake - let OpenSSL initialize the protocol. Register for
  259. * read/write events if necessary.
  260. */
  261. static void
  262. ssl_handshake(int fd, struct Client *client_p)
  263. {
  264. int ret = SSL_accept(client_p->localClient->fd.ssl);
  265. X509 *cert;
  266. if ((cert = SSL_get_peer_certificate(client_p->localClient->fd.ssl)) != NULL)
  267. {
  268. int res = SSL_get_verify_result(client_p->localClient->fd.ssl);
  269. if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
  270. res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
  271. res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
  272. {
  273. /* The client sent a certificate which verified OK */
  274. memcpy(client_p->certfp, cert->sha1_hash, sizeof(client_p->certfp));
  275. }
  276. else
  277. {
  278. ilog(L_WARN, "Client %s!%s@%s gave bad SSL client certificate: %d",
  279. client_p->name, client_p->username, client_p->host, res);
  280. }
  281. }
  282. if (ret <= 0)
  283. switch (SSL_get_error(client_p->localClient->fd.ssl, ret))
  284. {
  285. case SSL_ERROR_WANT_WRITE:
  286. comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
  287. (PF *) ssl_handshake, client_p, 0);
  288. return;
  289. case SSL_ERROR_WANT_READ:
  290. comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
  291. (PF *) ssl_handshake, client_p, 0);
  292. return;
  293. default:
  294. exit_client(client_p, client_p, "Error during SSL handshake");
  295. return;
  296. }
  297. execute_callback(auth_cb, client_p);
  298. }
  299. #endif
  300. /*
  301. * add_connection - creates a client which has just connected to us on
  302. * the given fd. The sockhost field is initialized with the ip# of the host.
  303. * An unique id is calculated now, in case it is needed for auth.
  304. * The client is sent to the auth module for verification, and not put in
  305. * any client list yet.
  306. */
  307. void
  308. add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
  309. {
  310. struct Client *new_client;
  311. assert(NULL != listener);
  312. new_client = make_client(NULL);
  313. fd_open(&new_client->localClient->fd, fd, 1,
  314. (listener->flags & LISTENER_SSL) ?
  315. "Incoming SSL connection" : "Incoming connection");
  316. /*
  317. * copy address to 'sockhost' as a string, copy it to host too
  318. * so we have something valid to put into error messages...
  319. */
  320. memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
  321. irc_getnameinfo((struct sockaddr *) &new_client->localClient->ip,
  322. new_client->localClient->ip.ss_len, new_client->sockhost,
  323. HOSTIPLEN, NULL, 0, NI_NUMERICHOST);
  324. new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
  325. #ifdef IPV6
  326. if(new_client->sockhost[0] == ':')
  327. strlcat(new_client->host, "0", HOSTLEN + 1);
  328. if(new_client->localClient->aftype == AF_INET6 && ConfigFileEntry.dot_in_ip6_addr == 1)
  329. {
  330. strlcat(new_client->host, new_client->sockhost, HOSTLEN + 1);
  331. strlcat(new_client->host, ".", HOSTLEN + 1);
  332. }
  333. else
  334. #endif
  335. strlcat(new_client->host, new_client->sockhost, HOSTLEN + 1);
  336. strlcat(new_client->realhost, new_client->host, HOSTLEN + 1);
  337. new_client->connect_id = ++connect_id;
  338. new_client->localClient->listener = listener;
  339. ++listener->ref_count;
  340. #ifdef HAVE_LIBCRYPTO
  341. if(listener->flags & LISTENER_SSL)
  342. {
  343. if((new_client->localClient->fd.ssl = SSL_new(ServerInfo.ctx)) == NULL)
  344. {
  345. ilog(L_CRIT, "SSL_new() ERROR! -- %s",
  346. ERR_error_string(ERR_get_error(), NULL));
  347. SetDead(new_client);
  348. exit_client(new_client, new_client, "SSL_new failed");
  349. return;
  350. }
  351. SSL_set_fd(new_client->localClient->fd.ssl, fd);
  352. ssl_handshake(0, new_client);
  353. }
  354. else
  355. #endif
  356. execute_callback(auth_cb, new_client);
  357. }
  358. /*
  359. * stolen from squid - its a neat (but overused! :) routine which we
  360. * can use to see whether we can ignore this errno or not. It is
  361. * generally useful for non-blocking network IO related errnos.
  362. * -- adrian
  363. */
  364. int
  365. ignoreErrno(int ierrno)
  366. {
  367. switch (ierrno)
  368. {
  369. case EINPROGRESS:
  370. case EWOULDBLOCK:
  371. #if EAGAIN != EWOULDBLOCK
  372. case EAGAIN:
  373. #endif
  374. case EALREADY:
  375. case EINTR:
  376. #ifdef ERESTART
  377. case ERESTART:
  378. #endif
  379. return 1;
  380. default:
  381. return 0;
  382. }
  383. }
  384. /*
  385. * comm_settimeout() - set the socket timeout
  386. *
  387. * Set the timeout for the fd
  388. */
  389. void
  390. comm_settimeout(fde_t * fd, time_t timeout, PF * callback, void *cbdata)
  391. {
  392. assert(fd->flags.open);
  393. fd->timeout = CurrentTime + (timeout / 1000);
  394. fd->timeout_handler = callback;
  395. fd->timeout_data = cbdata;
  396. }
  397. /*
  398. * comm_setflush() - set a flush function
  399. *
  400. * A flush function is simply a function called if found during
  401. * comm_timeouts(). Its basically a second timeout, except in this case
  402. * I'm too lazy to implement multiple timeout functions! :-)
  403. * its kinda nice to have it separate, since this is designed for
  404. * flush functions, and when comm_close() is implemented correctly
  405. * with close functions, we _actually_ don't call comm_close() here ..
  406. * -- originally Adrian's notes
  407. * comm_close() is replaced with fd_close() in fdlist.c
  408. */
  409. void
  410. comm_setflush(fde_t * fd, time_t timeout, PF * callback, void *cbdata)
  411. {
  412. assert(fd->flags.open);
  413. fd->flush_timeout = CurrentTime + (timeout / 1000);
  414. fd->flush_handler = callback;
  415. fd->flush_data = cbdata;
  416. }
  417. /*
  418. * comm_checktimeouts() - check the socket timeouts
  419. *
  420. * All this routine does is call the given callback/cbdata, without closing
  421. * down the file descriptor. When close handlers have been implemented,
  422. * this will happen.
  423. */
  424. void
  425. comm_checktimeouts(void *notused)
  426. {
  427. int i;
  428. fde_t *F;
  429. PF *hdl;
  430. void *data;
  431. for(i = 0; i < FD_HASH_SIZE; i++)
  432. for(F = fd_hash[i]; F != NULL; F = fd_next_in_loop)
  433. {
  434. assert(F->flags.open);
  435. fd_next_in_loop = F->hnext;
  436. /* check flush functions */
  437. if(F->flush_handler && F->flush_timeout > 0 &&
  438. F->flush_timeout < CurrentTime)
  439. {
  440. hdl = F->flush_handler;
  441. data = F->flush_data;
  442. comm_setflush(F, 0, NULL, NULL);
  443. hdl(F, data);
  444. }
  445. /* check timeouts */
  446. if(F->timeout_handler && F->timeout > 0 && F->timeout < CurrentTime)
  447. {
  448. /* Call timeout handler */
  449. hdl = F->timeout_handler;
  450. data = F->timeout_data;
  451. comm_settimeout(F, 0, NULL, NULL);
  452. hdl(F, data);
  453. }
  454. }
  455. }
  456. /*
  457. * void comm_connect_tcp(int fd, const char *host, unsigned short port,
  458. * struct sockaddr *clocal, int socklen,
  459. * CNCB *callback, void *data, int aftype, int timeout)
  460. * Input: An fd to connect with, a host and port to connect to,
  461. * a local sockaddr to connect from + length(or NULL to use the
  462. * default), a callback, the data to pass into the callback, the
  463. * address family.
  464. * Output: None.
  465. * Side-effects: A non-blocking connection to the host is started, and
  466. * if necessary, set up for selection. The callback given
  467. * may be called now, or it may be called later.
  468. */
  469. void
  470. comm_connect_tcp(fde_t * fd, const char *host, unsigned short port,
  471. struct sockaddr *clocal, int socklen, CNCB * callback,
  472. void *data, int aftype, int timeout)
  473. {
  474. struct addrinfo hints, *res;
  475. char portname[PORTNAMELEN + 1];
  476. assert(callback);
  477. fd->connect.callback = callback;
  478. fd->connect.data = data;
  479. fd->connect.hostaddr.ss.ss_family = aftype;
  480. fd->connect.hostaddr.ss_port = htons(port);
  481. /* Note that we're using a passed sockaddr here. This is because
  482. * generally you'll be bind()ing to a sockaddr grabbed from
  483. * getsockname(), so this makes things easier.
  484. * XXX If NULL is passed as local, we should later on bind() to the
  485. * virtual host IP, for completeness.
  486. * -- adrian
  487. */
  488. if((clocal != NULL) && (bind(fd->fd, clocal, socklen) < 0))
  489. {
  490. /* Failure, call the callback with COMM_ERR_BIND */
  491. comm_connect_callback(fd, COMM_ERR_BIND);
  492. /* ... and quit */
  493. return;
  494. }
  495. /* Next, if we have been given an IP, get the addr and skip the
  496. * DNS check (and head direct to comm_connect_tryconnect().
  497. */
  498. memset(&hints, 0, sizeof(hints));
  499. hints.ai_family = AF_UNSPEC;
  500. hints.ai_socktype = SOCK_STREAM;
  501. hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
  502. snprintf(portname, PORTNAMELEN, "%d", port);
  503. if(irc_getaddrinfo(host, portname, &hints, &res))
  504. {
  505. /* Send the DNS request, for the next level */
  506. fd->dns_query = MyMalloc(sizeof(struct DNSQuery));
  507. fd->dns_query->ptr = fd;
  508. fd->dns_query->callback = comm_connect_dns_callback;
  509. gethost_byname(host, fd->dns_query);
  510. }
  511. else
  512. {
  513. /* We have a valid IP, so we just call tryconnect */
  514. /* Make sure we actually set the timeout here .. */
  515. assert(res != NULL);
  516. memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen);
  517. fd->connect.hostaddr.ss_len = res->ai_addrlen;
  518. fd->connect.hostaddr.ss.ss_family = res->ai_family;
  519. irc_freeaddrinfo(res);
  520. comm_settimeout(fd, timeout * 1000, comm_connect_timeout, NULL);
  521. comm_connect_tryconnect(fd, NULL);
  522. }
  523. }
  524. /*
  525. * comm_connect_callback() - call the callback, and continue with life
  526. */
  527. static void
  528. comm_connect_callback(fde_t * fd, int status)
  529. {
  530. CNCB *hdl;
  531. /* This check is gross..but probably necessary */
  532. if(fd->connect.callback == NULL)
  533. return;
  534. /* Clear the connect flag + handler */
  535. hdl = fd->connect.callback;
  536. fd->connect.callback = NULL;
  537. /* Clear the timeout handler */
  538. comm_settimeout(fd, 0, NULL, NULL);
  539. /* Call the handler */
  540. hdl(fd, status, fd->connect.data);
  541. }
  542. /*
  543. * comm_connect_timeout() - this gets called when the socket connection
  544. * times out. This *only* can be called once connect() is initially
  545. * called ..
  546. */
  547. static void
  548. comm_connect_timeout(fde_t * fd, void *notused)
  549. {
  550. /* error! */
  551. comm_connect_callback(fd, COMM_ERR_TIMEOUT);
  552. }
  553. /*
  554. * comm_connect_dns_callback() - called at the completion of the DNS request
  555. *
  556. * The DNS request has completed, so if we've got an error, return it,
  557. * otherwise we initiate the connect()
  558. */
  559. static void
  560. comm_connect_dns_callback(void *vptr, struct DNSReply *reply)
  561. {
  562. fde_t *F = vptr;
  563. if(reply == NULL)
  564. {
  565. MyFree(F->dns_query);
  566. F->dns_query = NULL;
  567. comm_connect_callback(F, COMM_ERR_DNS);
  568. return;
  569. }
  570. /* No error, set a 10 second timeout */
  571. comm_settimeout(F, 30 * 1000, comm_connect_timeout, NULL);
  572. /* Copy over the DNS reply info so we can use it in the connect() */
  573. /*
  574. * Note we don't fudge the refcount here, because we aren't keeping
  575. * the DNS record around, and the DNS cache is gone anyway..
  576. * -- adrian
  577. */
  578. memcpy(&F->connect.hostaddr, &reply->addr, reply->addr.ss_len);
  579. /* The cast is hacky, but safe - port offset is same on v4 and v6 */
  580. ((struct sockaddr_in *) &F->connect.hostaddr)->sin_port = F->connect.hostaddr.ss_port;
  581. F->connect.hostaddr.ss_len = reply->addr.ss_len;
  582. /* Now, call the tryconnect() routine to try a connect() */
  583. MyFree(F->dns_query);
  584. F->dns_query = NULL;
  585. comm_connect_tryconnect(F, NULL);
  586. }
  587. /* static void comm_connect_tryconnect(int fd, void *notused)
  588. * Input: The fd, the handler data(unused).
  589. * Output: None.
  590. * Side-effects: Try and connect with pending connect data for the FD. If
  591. * we succeed or get a fatal error, call the callback.
  592. * Otherwise, it is still blocking or something, so register
  593. * to select for a write event on this FD.
  594. */
  595. static void
  596. comm_connect_tryconnect(fde_t * fd, void *notused)
  597. {
  598. int retval;
  599. /* This check is needed or re-entrant s_bsd_* like sigio break it. */
  600. if(fd->connect.callback == NULL)
  601. return;
  602. /* Try the connect() */
  603. retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr,
  604. fd->connect.hostaddr.ss_len);
  605. /* Error? */
  606. if(retval < 0)
  607. {
  608. #ifdef _WIN32
  609. errno = WSAGetLastError();
  610. #endif
  611. /*
  612. * If we get EISCONN, then we've already connect()ed the socket,
  613. * which is a good thing.
  614. * -- adrian
  615. */
  616. if(errno == EISCONN)
  617. comm_connect_callback(fd, COMM_OK);
  618. else if(ignoreErrno(errno))
  619. /* Ignore error? Reschedule */
  620. comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect, NULL, 0);
  621. else
  622. /* Error? Fail with COMM_ERR_CONNECT */
  623. comm_connect_callback(fd, COMM_ERR_CONNECT);
  624. return;
  625. }
  626. /* If we get here, we've suceeded, so call with COMM_OK */
  627. comm_connect_callback(fd, COMM_OK);
  628. }
  629. /*
  630. * comm_errorstr() - return an error string for the given error condition
  631. */
  632. const char *
  633. comm_errstr(int error)
  634. {
  635. if(error < 0 || error >= COMM_ERR_MAX)
  636. return "Invalid error number!";
  637. return comm_err_str[error];
  638. }
  639. /*
  640. * comm_open() - open a socket
  641. *
  642. * This is a highly highly cut down version of squid's comm_open() which
  643. * for the most part emulates socket(), *EXCEPT* it fails if we're about
  644. * to run out of file descriptors.
  645. */
  646. int
  647. comm_open(fde_t * F, int family, int sock_type, int proto, const char *note)
  648. {
  649. int fd;
  650. /* First, make sure we aren't going to run out of file descriptors */
  651. if(number_fd >= hard_fdlimit)
  652. {
  653. errno = ENFILE;
  654. return -1;
  655. }
  656. /*
  657. * Next, we try to open the socket. We *should* drop the reserved FD
  658. * limit if/when we get an error, but we can deal with that later.
  659. * XXX !!! -- adrian
  660. */
  661. fd = socket(family, sock_type, proto);
  662. if(fd < 0)
  663. {
  664. #ifdef _WIN32
  665. errno = WSAGetLastError();
  666. #endif
  667. return -1; /* errno will be passed through, yay.. */
  668. }
  669. execute_callback(setup_socket_cb, fd);
  670. /* update things in our fd tracking */
  671. fd_open(F, fd, 1, note);
  672. return 0;
  673. }
  674. /*
  675. * comm_accept() - accept an incoming connection
  676. *
  677. * This is a simple wrapper for accept() which enforces FD limits like
  678. * comm_open() does. Returned fd must be either closed or tagged with
  679. * fd_open (this function no longer does it).
  680. */
  681. int
  682. comm_accept(struct Listener *lptr, struct irc_ssaddr *pn)
  683. {
  684. int newfd;
  685. socklen_t addrlen = sizeof(struct irc_ssaddr);
  686. if(number_fd >= hard_fdlimit)
  687. {
  688. errno = ENFILE;
  689. return -1;
  690. }
  691. /*
  692. * Next, do the accept(). if we get an error, we should drop the
  693. * reserved fd limit, but we can deal with that when comm_open()
  694. * also does it. XXX -- adrian
  695. */
  696. newfd = accept(lptr->fd.fd, (struct sockaddr *) pn, (socklen_t *) & addrlen);
  697. if(newfd < 0)
  698. {
  699. #ifdef _WIN32
  700. errno = WSAGetLastError();
  701. #endif
  702. return -1;
  703. }
  704. #ifdef IPV6
  705. remove_ipv6_mapping(pn);
  706. #else
  707. pn->ss_len = addrlen;
  708. #endif
  709. execute_callback(setup_socket_cb, newfd);
  710. /* .. and return */
  711. return newfd;
  712. }
  713. /*
  714. * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
  715. * This function should really inspect the struct itself rather than relying
  716. * on inet_pton and inet_ntop. OSes with IPv6 mapping listening on both
  717. * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
  718. *
  719. */
  720. #ifdef IPV6
  721. void
  722. remove_ipv6_mapping(struct irc_ssaddr *addr)
  723. {
  724. if(addr->ss.ss_family == AF_INET6)
  725. {
  726. struct sockaddr_in6 *v6;
  727. v6 = (struct sockaddr_in6 *) addr;
  728. if(IN6_IS_ADDR_V4MAPPED(&v6->sin6_addr))
  729. {
  730. char v4ip[HOSTIPLEN];
  731. struct sockaddr_in *v4 = (struct sockaddr_in *) addr;
  732. inetntop(AF_INET6, &v6->sin6_addr, v4ip, HOSTIPLEN);
  733. inet_pton(AF_INET, v4ip, &v4->sin_addr);
  734. addr->ss.ss_family = AF_INET;
  735. addr->ss_len = sizeof(struct sockaddr_in);
  736. }
  737. else
  738. addr->ss_len = sizeof(struct sockaddr_in6);
  739. }
  740. else
  741. addr->ss_len = sizeof(struct sockaddr_in);
  742. }
  743. #endif