PageRenderTime 24ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/ratbox-services-1.2.1/src/io.c

#
C | 1500 lines | 1018 code | 248 blank | 234 comment | 214 complexity | a0b9decf4f1ee14e9f88564067f6b262 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /* src/io.c
  2. * Contains code for handling input and output to sockets.
  3. *
  4. * Copyright (C) 2003-2007 Lee Hardy <leeh@leeh.co.uk>
  5. * Copyright (C) 2003-2007 ircd-ratbox development team
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * 1.Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. * 2.Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3.The name of the author may not be used to endorse or promote products
  17. * derived from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  23. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  25. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  27. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  28. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * $Id: io.c 23499 2007-01-17 19:17:35Z androsyn $
  32. */
  33. #include <sys/types.h>
  34. #include <sys/socket.h>
  35. #include <netinet/in.h>
  36. #include <arpa/inet.h>
  37. #include <netdb.h>
  38. #include "stdinc.h"
  39. #include "scommand.h"
  40. #include "ucommand.h"
  41. #include "tools.h"
  42. #include "rserv.h"
  43. #include "io.h"
  44. #include "event.h"
  45. #include "conf.h"
  46. #include "tools.h"
  47. #include "client.h"
  48. #include "log.h"
  49. #include "service.h"
  50. #include "hook.h"
  51. #include "serno.h"
  52. #include "watch.h"
  53. #define IO_HOST 0
  54. #define IO_IP 1
  55. dlink_list connection_list;
  56. struct lconn *server_p;
  57. time_t last_connect_time;
  58. time_t current_time;
  59. fd_set readfds;
  60. fd_set writefds;
  61. static int signon_server(struct lconn *conn_p);
  62. static void signon_client_in(struct lconn *conn_p);
  63. static int signon_client_out(struct lconn *conn_p);
  64. static void signoff_server(struct lconn *conn_p);
  65. static void signoff_client(struct lconn *conn_p);
  66. static void read_server(struct lconn *conn_p);
  67. static void read_client(struct lconn *conn_p);
  68. static int write_sendq(struct lconn *conn_p);
  69. static void parse_server(char *buf, int len);
  70. static void parse_client(struct lconn *conn_p, char *buf, int len);
  71. #ifdef HAVE_GETADDRINFO
  72. static struct addrinfo *gethostinfo(char const *host, int port);
  73. #endif
  74. /* stolen from squid */
  75. static int
  76. ignore_errno(int ierrno)
  77. {
  78. switch(ierrno)
  79. {
  80. case EINPROGRESS:
  81. case EWOULDBLOCK:
  82. #if EAGAIN != EWOULDBLOCK
  83. case EAGAIN:
  84. #endif
  85. case EALREADY:
  86. case EINTR:
  87. #ifdef ERESTART
  88. case ERESTART:
  89. #endif
  90. return 1;
  91. default:
  92. return 0;
  93. }
  94. }
  95. /* get_line()
  96. * Gets a line of data from a given connection
  97. *
  98. * inputs - connection to get line for, buffer to put in, size of buffer
  99. * outputs - characters read
  100. */
  101. static int
  102. get_line(struct lconn *conn_p)
  103. {
  104. char *p;
  105. size_t n;
  106. int term;
  107. size_t buflen;
  108. if((n = recv(conn_p->fd, conn_p->recvbuf + conn_p->recvbuf_offset,
  109. sizeof(conn_p->recvbuf) - conn_p->recvbuf_offset, MSG_PEEK)) <= 0)
  110. {
  111. if(n == -1 && ignore_errno(errno))
  112. return 0;
  113. return -1;
  114. }
  115. /* if we found a '\n', set n to the position of it in the stream,
  116. * that way the following read() call will only read a single line
  117. */
  118. if((p = memchr(conn_p->recvbuf, '\n', conn_p->recvbuf_offset + n)) != NULL)
  119. n = p - conn_p->recvbuf - conn_p->recvbuf_offset + 1;
  120. if((n = read(conn_p->fd, conn_p->recvbuf + conn_p->recvbuf_offset, n)) <= 0)
  121. {
  122. if(n == -1 && ignore_errno(errno))
  123. return 0;
  124. return -1;
  125. }
  126. buflen = conn_p->recvbuf_offset + n;
  127. /* for sanity reasons, this makes sure that when recv() told us we
  128. * were getting a '\n', we actually did from read() --fl
  129. */
  130. if(memchr(conn_p->recvbuf, '\n', buflen))
  131. term = 1;
  132. else
  133. term = 0;
  134. /* if this isnt terminated, and is still under the length limit then
  135. * we likely have a short read and more data is coming.
  136. *
  137. * update the offset so we dont trash the recvbuf and return a
  138. * non-fatal error
  139. */
  140. if(!term && (buflen < sizeof(conn_p->recvbuf)))
  141. {
  142. conn_p->recvbuf_offset += n;
  143. return 0;
  144. }
  145. else
  146. conn_p->recvbuf_offset = 0;
  147. /* we're allowed to parse this line.. */
  148. if((conn_p->flags & CONN_FLAGS_UNTERMINATED) == 0)
  149. {
  150. if(buflen >= sizeof(conn_p->recvbuf))
  151. conn_p->recvbuf[sizeof(conn_p->recvbuf) - 1] = '\0';
  152. else
  153. conn_p->recvbuf[buflen] = '\0';
  154. if(!term)
  155. conn_p->flags |= CONN_FLAGS_UNTERMINATED;
  156. return buflen;
  157. }
  158. /* found a \n, can begin parsing again.. */
  159. if(term)
  160. conn_p->flags &= ~CONN_FLAGS_UNTERMINATED;
  161. /* we dont want to parse this.. its the remainder of an unterminated
  162. * line --fl
  163. */
  164. return 0;
  165. }
  166. /* read_io()
  167. * The main IO loop for reading/writing data.
  168. *
  169. * inputs -
  170. * outputs -
  171. */
  172. void
  173. read_io(void)
  174. {
  175. struct lconn *conn_p;
  176. dlink_node *ptr;
  177. dlink_node *next_ptr;
  178. struct timeval read_time_out;
  179. int select_result;
  180. while(1)
  181. {
  182. FD_ZERO(&readfds);
  183. FD_ZERO(&writefds);
  184. read_time_out.tv_sec = 1L;
  185. read_time_out.tv_usec = 0L;
  186. if(server_p != NULL)
  187. {
  188. /* socket isnt dead.. */
  189. if(!ConnDead(server_p))
  190. {
  191. /* client struct is. im not sure how this
  192. * could happen, but..
  193. */
  194. if(server_p->client_p != NULL &&
  195. IsDead(server_p->client_p))
  196. {
  197. mlog("Connection to server %s lost: (Server exited)",
  198. server_p->name);
  199. sendto_all("Connection to server %s lost: (Server exited)",
  200. server_p->name);
  201. (server_p->io_close)(server_p);
  202. }
  203. /* connection timed out.. */
  204. else if(ConnConnecting(server_p) &&
  205. ((server_p->first_time + 30) <= CURRENT_TIME))
  206. {
  207. mlog("Connection to server %s timed out",
  208. server_p->name);
  209. sendto_all("Connection to server %s timed out",
  210. server_p->name);
  211. (server_p->io_close)(server_p);
  212. }
  213. /* authentication timed out.. */
  214. else if(ConnHandshake(server_p) &&
  215. ((server_p->first_time + 60) <=
  216. CURRENT_TIME))
  217. {
  218. mlog("Connection to server %s timed out",
  219. server_p->name);
  220. sendto_all("Connection to server %s timed out",
  221. server_p->name);
  222. (server_p->io_close)(server_p);
  223. }
  224. /* pinged out */
  225. else if(ConnSentPing(server_p) &&
  226. ((server_p->last_time + config_file.ping_time*2)
  227. <= CURRENT_TIME))
  228. {
  229. mlog("Connection to server %s lost: (Ping timeout)",
  230. server_p->name);
  231. sendto_all("Connection to server %s lost: (Ping timeout)",
  232. server_p->name);
  233. (server_p->io_close)(server_p);
  234. }
  235. /* no data for a while.. send ping */
  236. else if(!ConnSentPing(server_p) &&
  237. ((server_p->last_time + config_file.ping_time)
  238. <= CURRENT_TIME))
  239. {
  240. sendto_server("PING :%s", MYUID);
  241. SetConnSentPing(server_p);
  242. }
  243. }
  244. if(ConnDead(server_p))
  245. {
  246. /* connection is dead, uplinks still here. byebye */
  247. if(server_p->client_p != NULL &&
  248. !IsDead(server_p->client_p))
  249. exit_client(server_p->client_p);
  250. my_free(server_p->name);
  251. my_free(server_p->sid);
  252. my_free(server_p);
  253. server_p = NULL;
  254. }
  255. }
  256. /* remove any timed out/dead connections */
  257. DLINK_FOREACH_SAFE(ptr, next_ptr, connection_list.head)
  258. {
  259. conn_p = ptr->data;
  260. /* connection timed out.. */
  261. if(ConnConnecting(conn_p) &&
  262. ((conn_p->first_time + 30) <= CURRENT_TIME))
  263. (conn_p->io_close)(conn_p);
  264. if(ConnDead(conn_p))
  265. {
  266. my_free(conn_p->name);
  267. my_free(conn_p);
  268. dlink_delete(ptr, &connection_list);
  269. }
  270. }
  271. /* we can safely exit anything thats dead at this point */
  272. DLINK_FOREACH_SAFE(ptr, next_ptr, exited_list.head)
  273. {
  274. free_client(ptr->data);
  275. }
  276. exited_list.head = exited_list.tail = NULL;
  277. exited_list.length = 0;
  278. if(server_p != NULL)
  279. {
  280. if(ConnConnecting(server_p))
  281. {
  282. FD_SET(server_p->fd, &writefds);
  283. }
  284. else
  285. {
  286. if(dlink_list_length(&server_p->sendq) > 0)
  287. FD_SET(server_p->fd, &writefds);
  288. FD_SET(server_p->fd, &readfds);
  289. }
  290. }
  291. DLINK_FOREACH(ptr, connection_list.head)
  292. {
  293. conn_p = ptr->data;
  294. if(ConnConnecting(conn_p))
  295. {
  296. if(ConnDccIn(conn_p))
  297. FD_SET(conn_p->fd, &readfds);
  298. else
  299. FD_SET(conn_p->fd, &writefds);
  300. }
  301. else
  302. {
  303. if(dlink_list_length(&conn_p->sendq) > 0)
  304. FD_SET(conn_p->fd, &writefds);
  305. FD_SET(conn_p->fd, &readfds);
  306. }
  307. }
  308. set_time();
  309. eventRun();
  310. select_result = select(FD_SETSIZE, &readfds, &writefds, NULL,
  311. &read_time_out);
  312. if(select_result == 0)
  313. continue;
  314. /* have data to parse */
  315. if(select_result > 0)
  316. {
  317. if(server_p != NULL && !ConnDead(server_p))
  318. {
  319. /* data from server to read */
  320. if(FD_ISSET(server_p->fd, &readfds) &&
  321. server_p->io_read != NULL)
  322. {
  323. server_p->last_time = CURRENT_TIME;
  324. ClearConnSentPing(server_p);
  325. (server_p->io_read)(server_p);
  326. }
  327. /* couldve died during read.. */
  328. if(!ConnDead(server_p) &&
  329. FD_ISSET(server_p->fd, &writefds) &&
  330. server_p->io_write != NULL)
  331. {
  332. (server_p->io_write)(server_p);
  333. }
  334. }
  335. DLINK_FOREACH(ptr, connection_list.head)
  336. {
  337. conn_p = ptr->data;
  338. if(ConnDead(conn_p))
  339. continue;
  340. if(FD_ISSET(conn_p->fd, &readfds) &&
  341. conn_p->io_read != NULL)
  342. {
  343. conn_p->last_time = CURRENT_TIME;
  344. (conn_p->io_read)(conn_p);
  345. }
  346. if(!ConnDead(conn_p) &&
  347. FD_ISSET(conn_p->fd, &writefds) &&
  348. conn_p->io_write != NULL)
  349. {
  350. (conn_p->io_write)(conn_p);
  351. }
  352. }
  353. }
  354. }
  355. }
  356. /* next_autoconn()
  357. * finds the next entry to autoconnect to
  358. *
  359. * inputs -
  360. * outputs - struct conf_server to connect to, or NULL
  361. */
  362. static struct conf_server *
  363. next_autoconn(void)
  364. {
  365. struct conf_server *conf_p = NULL;
  366. struct conf_server *tmp_p;
  367. dlink_node *ptr;
  368. if(dlink_list_length(&conf_server_list) <= 0)
  369. die(0, "No servers to connect to");
  370. DLINK_FOREACH(ptr, conf_server_list.head)
  371. {
  372. tmp_p = ptr->data;
  373. /* negative port == no autoconn */
  374. if(!ConfServerAutoconn(tmp_p))
  375. continue;
  376. if(conf_p == NULL || tmp_p->last_connect < conf_p->last_connect)
  377. conf_p = tmp_p;
  378. }
  379. if(conf_p != NULL)
  380. {
  381. conf_p->port = conf_p->defport;
  382. conf_p->last_connect = CURRENT_TIME;
  383. }
  384. return conf_p;
  385. }
  386. /* connect_to_server()
  387. * Connects to given server, or next autoconn.
  388. *
  389. * inputs - optional server to connect to
  390. * outputs -
  391. * requirements - if target_server is specified, it must set the port
  392. */
  393. void
  394. connect_to_server(void *target_server)
  395. {
  396. struct conf_server *conf_p;
  397. struct lconn *conn_p;
  398. int serv_fd;
  399. if(server_p != NULL)
  400. return;
  401. /* no specific server, so try autoconn */
  402. if(target_server == NULL)
  403. {
  404. /* no autoconnect? */
  405. if((conf_p = next_autoconn()) == NULL)
  406. die(1, "No server to autoconnect to.");
  407. }
  408. else
  409. conf_p = target_server;
  410. mlog("Connection to server %s/%d activated",
  411. conf_p->name, conf_p->port);
  412. sendto_all("Connection to server %s/%d activated",
  413. conf_p->name, conf_p->port);
  414. serv_fd = sock_open(conf_p->host, conf_p->port, conf_p->vhost, IO_HOST);
  415. if(serv_fd < 0)
  416. {
  417. eventAddOnce("connect_to_server", connect_to_server, NULL,
  418. config_file.reconnect_time);
  419. return;
  420. }
  421. conn_p = my_malloc(sizeof(struct lconn));
  422. conn_p->name = my_strdup(conf_p->name);
  423. conn_p->fd = serv_fd;
  424. conn_p->first_time = conn_p->last_time = CURRENT_TIME;
  425. conn_p->pass = my_strdup(conf_p->pass);
  426. conn_p->io_read = NULL;
  427. conn_p->io_write = signon_server;
  428. conn_p->io_close = signoff_server;
  429. SetConnConnecting(conn_p);
  430. server_p = conn_p;
  431. }
  432. /* connect_to_client()
  433. * connects to a client
  434. *
  435. * inputs - client requesting dcc, host/port to connect to
  436. * outputs -
  437. */
  438. void
  439. connect_to_client(struct client *client_p, struct conf_oper *oper_p,
  440. const char *host, int port)
  441. {
  442. struct lconn *conn_p;
  443. int client_fd;
  444. client_fd = sock_open(host, port, config_file.dcc_vhost, IO_IP);
  445. if(client_fd < 0)
  446. return;
  447. conn_p = my_malloc(sizeof(struct lconn));
  448. conn_p->name = my_strdup(oper_p->name);
  449. conn_p->oper = oper_p;
  450. oper_p->refcount++;
  451. conn_p->fd = client_fd;
  452. conn_p->first_time = conn_p->last_time = CURRENT_TIME;
  453. conn_p->io_read = NULL;
  454. conn_p->io_write = signon_client_out;
  455. conn_p->io_close = signoff_client;
  456. SetConnConnecting(conn_p);
  457. SetConnDccOut(conn_p);
  458. dlink_add_alloc(conn_p, &connection_list);
  459. }
  460. void
  461. connect_from_client(struct client *client_p, struct conf_oper *oper_p,
  462. const char *servicenick)
  463. {
  464. struct lconn *conn_p;
  465. struct sockaddr_in addr;
  466. struct hostent *local_addr;
  467. unsigned long local_ip;
  468. int client_fd;
  469. int port;
  470. int res;
  471. client_fd = sock_create(AF_INET);
  472. if(config_file.dcc_vhost == NULL ||
  473. (local_addr = gethostbyname(config_file.dcc_vhost)) == NULL)
  474. return;
  475. /* XXX ERROR */
  476. if(client_fd < 0)
  477. return;
  478. for(port = config_file.dcc_low_port; port < config_file.dcc_high_port;
  479. port++)
  480. {
  481. memset(&addr, 0, sizeof(struct sockaddr_in));
  482. memcpy(&addr.sin_addr, local_addr->h_addr,
  483. local_addr->h_length);
  484. addr.sin_family = AF_INET;
  485. addr.sin_port = htons(port);
  486. res = bind(client_fd, (struct sockaddr *) &addr,
  487. sizeof(struct sockaddr_in));
  488. if(res >= 0)
  489. break;
  490. }
  491. if(res < 0)
  492. {
  493. close(client_fd);
  494. return;
  495. }
  496. if(listen(client_fd, 1) < 0)
  497. {
  498. close(client_fd);
  499. return;
  500. }
  501. conn_p = my_malloc(sizeof(struct lconn));
  502. conn_p->name = my_strdup(oper_p->name);
  503. conn_p->oper = oper_p;
  504. oper_p->refcount++;
  505. conn_p->fd = client_fd;
  506. conn_p->first_time = conn_p->last_time = CURRENT_TIME;
  507. conn_p->io_read = signon_client_in;
  508. conn_p->io_close = signoff_client;
  509. SetConnConnecting(conn_p);
  510. SetConnDccIn(conn_p);
  511. dlink_add_alloc(conn_p, &connection_list);
  512. memcpy(&local_ip, local_addr->h_addr, local_addr->h_length);
  513. local_ip = htonl(local_ip);
  514. sendto_server(":%s PRIVMSG %s :\001DCC CHAT chat %lu %d\001",
  515. servicenick, UID(client_p), local_ip, port);
  516. }
  517. /* signon_server()
  518. * sends our connection information to a server
  519. *
  520. * inputs - connection entry to send to
  521. * outputs - 1 on success, -1 on failure
  522. */
  523. static int
  524. signon_server(struct lconn *conn_p)
  525. {
  526. ClearConnConnecting(conn_p);
  527. SetConnHandshake(conn_p);
  528. conn_p->io_read = read_server;
  529. conn_p->io_write = write_sendq;
  530. /* ok, if connect() failed, this will cause an error.. */
  531. sendto_server("PASS %s TS 6 %s", conn_p->pass, config_file.sid);
  532. /* ..so we need to return. */
  533. if(ConnDead(conn_p))
  534. return -1;
  535. mlog("Connection to server %s established", conn_p->name);
  536. sendto_all("Connection to server %s established",
  537. conn_p->name);
  538. sendto_server("CAPAB :QS TB EX IE ENCAP SERVICES");
  539. sendto_server("SERVER %s 1 :%s", MYNAME, config_file.gecos);
  540. return 1;
  541. }
  542. static void
  543. signon_client_in(struct lconn *conn_p)
  544. {
  545. struct sockaddr_in addr;
  546. int sock;
  547. int addrlen = sizeof(struct sockaddr);
  548. memset(&addr, 0, sizeof(struct sockaddr_in));
  549. if((sock = accept(conn_p->fd, (struct sockaddr *) &addr,
  550. (socklen_t *) &addrlen)) < 0)
  551. {
  552. if(ignore_errno(errno))
  553. return;
  554. /* XXX FAILED NOTICE */
  555. shutdown(conn_p->fd, SHUT_RDWR);
  556. (conn_p->io_close)(conn_p);
  557. return;
  558. }
  559. ClearConnConnecting(conn_p);
  560. conn_p->io_read = read_client;
  561. conn_p->io_write = write_sendq;
  562. shutdown(conn_p->fd, SHUT_RDWR);
  563. close(conn_p->fd);
  564. conn_p->fd = sock;
  565. sendto_one(conn_p, "Welcome to %s, version ratbox-services-%s",
  566. MYNAME, RSERV_VERSION);
  567. if(ConnDead(conn_p))
  568. return;
  569. sendto_one(conn_p, "Please login via .login <username> <password>");
  570. return;
  571. }
  572. /* signon_client_out()
  573. * sends the initial connection info to a new client of ours
  574. *
  575. * inputs - connection entry to send to
  576. * outputs - 1 on success, -1 on failure
  577. */
  578. static int
  579. signon_client_out(struct lconn *conn_p)
  580. {
  581. ClearConnConnecting(conn_p);
  582. conn_p->io_read = read_client;
  583. conn_p->io_write = write_sendq;
  584. /* ok, if connect() failed, this will cause an error.. */
  585. sendto_one(conn_p, "Welcome to %s, version ratbox-services-%s",
  586. MYNAME, RSERV_VERSION);
  587. if(ConnDead(conn_p))
  588. return -1;
  589. sendto_one(conn_p, "Please login via .login <username> <password>");
  590. return 1;
  591. }
  592. static void
  593. signoff_client(struct lconn *conn_p)
  594. {
  595. if(ConnDead(conn_p))
  596. return;
  597. hook_call(HOOK_DCC_EXIT, conn_p, NULL);
  598. /* Mark it as dead right away to avoid infinite calls! -- jilles */
  599. SetConnDead(conn_p);
  600. if(UserAuth(conn_p))
  601. watch_send(WATCH_AUTH, NULL, conn_p, 1, "has logged out (dcc)");
  602. if(conn_p->oper != NULL)
  603. deallocate_conf_oper(conn_p->oper);
  604. sock_close(conn_p);
  605. }
  606. static void
  607. signoff_server(struct lconn *conn_p)
  608. {
  609. struct client *service_p;
  610. dlink_node *ptr;
  611. if(ConnDead(conn_p))
  612. return;
  613. /* Mark it as dead right away to avoid infinite calls! -- jilles */
  614. SetConnDead(conn_p);
  615. /* clear any introduced status */
  616. DLINK_FOREACH(ptr, service_list.head)
  617. {
  618. service_p = ptr->data;
  619. ClearServiceIntroduced(service_p);
  620. del_client(service_p);
  621. }
  622. if(conn_p == server_p)
  623. {
  624. eventAddOnce("connect_to_server", connect_to_server, NULL,
  625. config_file.reconnect_time);
  626. if(server_p->client_p != NULL)
  627. exit_client(server_p->client_p);
  628. }
  629. sock_close(conn_p);
  630. }
  631. /* read_server()
  632. * reads some data from the server, exiting it on read error
  633. *
  634. * inputs - connection entry to read from [unused]
  635. * outputs -
  636. */
  637. static void
  638. read_server(struct lconn *conn_p)
  639. {
  640. int n;
  641. if((n = get_line(server_p)) > 0)
  642. parse_server(server_p->recvbuf, n);
  643. /* we had a fatal error.. close the socket */
  644. else if(n < 0)
  645. {
  646. if(ignore_errno(errno))
  647. {
  648. mlog("Connection to server %s lost", conn_p->name);
  649. sendto_all("Connection to server %s lost",
  650. conn_p->name);
  651. }
  652. else
  653. {
  654. mlog("Connection to server %s lost: (Read error: %s)",
  655. conn_p->name, strerror(errno));
  656. sendto_all("Connection to server %s lost: (Read error: %s)",
  657. conn_p->name, strerror(errno));
  658. }
  659. (conn_p->io_close)(conn_p);
  660. }
  661. /* n == 0 we can safely ignore */
  662. }
  663. /* read_client()
  664. * reads some data from a client, exiting it on read errors
  665. *
  666. * inputs - connection entry to read from
  667. * outputs -
  668. */
  669. static void
  670. read_client(struct lconn *conn_p)
  671. {
  672. int n;
  673. if((n = get_line(conn_p)) > 0)
  674. parse_client(conn_p, conn_p->recvbuf, n);
  675. /* fatal error */
  676. else if(n < 0)
  677. (conn_p->io_close)(conn_p);
  678. /* n == 0 we can safely ignore */
  679. }
  680. /* io_to_array()
  681. * Changes a given buffer into an array of parameters.
  682. * Taken from ircd-ratbox.
  683. *
  684. * inputs - string to parse, array to put in
  685. * outputs - number of parameters
  686. */
  687. static __inline int
  688. io_to_array(char *string, char *parv[MAXPARA])
  689. {
  690. char *p, *buf = string;
  691. int x = 0;
  692. parv[x] = NULL;
  693. if(EmptyString(string))
  694. return x;
  695. while (*buf == ' ') /* skip leading spaces */
  696. buf++;
  697. if(*buf == '\0') /* ignore all-space args */
  698. return x;
  699. do
  700. {
  701. if(*buf == ':') /* Last parameter */
  702. {
  703. buf++;
  704. parv[x++] = buf;
  705. parv[x] = NULL;
  706. return x;
  707. }
  708. else
  709. {
  710. parv[x++] = buf;
  711. parv[x] = NULL;
  712. if((p = strchr(buf, ' ')) != NULL)
  713. {
  714. *p++ = '\0';
  715. buf = p;
  716. }
  717. else
  718. return x;
  719. }
  720. while (*buf == ' ')
  721. buf++;
  722. if(*buf == '\0')
  723. return x;
  724. }
  725. while (x < MAXPARA - 1);
  726. if(*p == ':')
  727. p++;
  728. parv[x++] = p;
  729. parv[x] = NULL;
  730. return x;
  731. }
  732. /* parse_server()
  733. * parses a given buffer into a command and calls handler
  734. *
  735. * inputs - buffer to parse, length of buffer
  736. * outputs -
  737. */
  738. void
  739. parse_server(char *buf, int len)
  740. {
  741. static char *parv[MAXPARA + 1];
  742. const char *command;
  743. const char *source;
  744. char *s;
  745. char *ch;
  746. int parc;
  747. if(len > BUFSIZE)
  748. buf[BUFSIZE-1] = '\0';
  749. if((s = strchr(buf, '\n')) != NULL)
  750. *s = '\0';
  751. if((s = strchr(buf, '\r')) != NULL)
  752. *s = '\0';
  753. /* skip leading spaces.. */
  754. for(ch = buf; *ch == ' '; ch++)
  755. ;
  756. source = server_p->name;
  757. if(*ch == ':')
  758. {
  759. ch++;
  760. source = ch;
  761. if((s = strchr(ch, ' ')) != NULL)
  762. {
  763. *s++ = '\0';
  764. ch = s;
  765. }
  766. while(*ch == ' ')
  767. ch++;
  768. }
  769. if(EmptyString(ch))
  770. return;
  771. command = ch;
  772. if((s = strchr(ch, ' ')) != NULL)
  773. {
  774. *s++ = '\0';
  775. ch = s;
  776. while(*ch == ' ')
  777. ch++;
  778. }
  779. else
  780. ch = NULL;
  781. parc = io_to_array(ch, parv);
  782. handle_scommand(source, command, (const char **) parv, parc);
  783. }
  784. /* parse_client()
  785. * parses a given buffer and calls command handlers
  786. *
  787. * inputs - connection who sent data, buffer to parse, length of buffer
  788. * outputs -
  789. */
  790. void
  791. parse_client(struct lconn *conn_p, char *buf, int len)
  792. {
  793. static char *parv[MAXPARA + 1];
  794. const char *command;
  795. char *s;
  796. char *ch;
  797. int parc;
  798. if(len > BUFSIZE)
  799. buf[BUFSIZE-1] = '\0';
  800. if((s = strchr(buf, '\n')) != NULL)
  801. *s = '\0';
  802. if((s = strchr(buf, '\r')) != NULL)
  803. *s = '\0';
  804. /* skip leading spaces.. */
  805. for(ch = buf; *ch == ' '; ch++)
  806. ;
  807. /* partyline */
  808. if(*ch != '.')
  809. {
  810. if(!UserAuth(conn_p))
  811. {
  812. sendto_one(conn_p, "You must .login first");
  813. return;
  814. }
  815. if(!UserChat(conn_p))
  816. {
  817. sendto_one(conn_p, "You must '.chat on' first.");
  818. return;
  819. }
  820. sendto_all_chat(conn_p, "<%s> %s", conn_p->name, ch);
  821. return;
  822. }
  823. ch++;
  824. if(EmptyString(ch))
  825. return;
  826. command = ch;
  827. /* command with params? */
  828. if((s = strchr(ch, ' ')) != NULL)
  829. {
  830. *s++ = '\0';
  831. ch = s;
  832. while(*ch == ' ')
  833. ch++;
  834. }
  835. else
  836. ch = NULL;
  837. parc = io_to_array(ch, parv);
  838. /* pass it off to the handler */
  839. handle_ucommand(conn_p, command, (const char **) parv, parc);
  840. }
  841. /* sendto_server()
  842. * attempts to send the given data to our server
  843. *
  844. * inputs - string to send
  845. * outputs -
  846. */
  847. void
  848. sendto_server(const char *format, ...)
  849. {
  850. char buf[BUFSIZE];
  851. va_list args;
  852. if(server_p == NULL || ConnDead(server_p))
  853. return;
  854. va_start(args, format);
  855. vsnprintf(buf, sizeof(buf)-3, format, args);
  856. va_end(args);
  857. strcat(buf, "\r\n");
  858. if(sock_write(server_p, buf, strlen(buf)) < 0)
  859. {
  860. mlog("Connection to server %s lost: (Write error: %s)",
  861. server_p->name, strerror(errno));
  862. sendto_all("Connection to server %s lost: (Write error: %s)",
  863. server_p->name, strerror(errno));
  864. (server_p->io_close)(server_p);
  865. }
  866. }
  867. /* sendto_one()
  868. * attempts to send the given data to a given connection
  869. *
  870. * inputs - connection to send to, data to send
  871. * outputs -
  872. */
  873. void
  874. sendto_one(struct lconn *conn_p, const char *format, ...)
  875. {
  876. char buf[BUFSIZE];
  877. va_list args;
  878. if(conn_p == NULL || ConnDead(conn_p))
  879. return;
  880. va_start(args, format);
  881. vsnprintf(buf, sizeof(buf)-3, format, args);
  882. va_end(args);
  883. strcat(buf, "\r\n");
  884. if(sock_write(conn_p, buf, strlen(buf)) < 0)
  885. (conn_p->io_close)(conn_p);
  886. }
  887. /* sendto_all()
  888. * attempts to send the given data to all clients connected
  889. *
  890. * inputs - umode required [0 for none], data to send
  891. * outputs -
  892. */
  893. void
  894. sendto_all(const char *format, ...)
  895. {
  896. struct lconn *conn_p;
  897. char buf[BUFSIZE];
  898. dlink_node *ptr;
  899. va_list args;
  900. va_start(args, format);
  901. vsnprintf(buf, sizeof(buf)-3, format, args);
  902. va_end(args);
  903. DLINK_FOREACH(ptr, connection_list.head)
  904. {
  905. conn_p = ptr->data;
  906. if(!UserAuth(conn_p))
  907. continue;
  908. sendto_one(conn_p, "%s", buf);
  909. }
  910. }
  911. /* sendto_all_chat()
  912. * attempts to send the given chat to all dcc clients except the
  913. * originator
  914. *
  915. * inputs - client sending this message, data
  916. * outputs -
  917. */
  918. void
  919. sendto_all_chat(struct lconn *one, const char *format, ...)
  920. {
  921. struct lconn *conn_p;
  922. char buf[BUFSIZE];
  923. dlink_node *ptr;
  924. va_list args;
  925. va_start(args, format);
  926. vsnprintf(buf, sizeof(buf)-3, format, args);
  927. va_end(args);
  928. DLINK_FOREACH(ptr, connection_list.head)
  929. {
  930. conn_p = ptr->data;
  931. if(!UserAuth(conn_p) || !UserChat(conn_p))
  932. continue;
  933. /* the one we shouldnt be sending to.. */
  934. if(conn_p == one)
  935. continue;
  936. sendto_one(conn_p, "%s", buf);
  937. }
  938. }
  939. /* get_sendq()
  940. * gets the sendq of a given connection
  941. *
  942. * inputs - connection entry to get sendq for
  943. * outputs - sendq
  944. */
  945. unsigned long
  946. get_sendq(struct lconn *conn_p)
  947. {
  948. struct send_queue *sendq_ptr;
  949. dlink_node *ptr;
  950. unsigned long sendq = 0;
  951. DLINK_FOREACH(ptr, conn_p->sendq.head)
  952. {
  953. sendq_ptr = ptr->data;
  954. sendq += sendq_ptr->len;
  955. }
  956. return sendq;
  957. }
  958. /* write_sendq()
  959. * write()'s as much of a given users sendq as possible
  960. *
  961. * inputs - connection to flush sendq of
  962. * outputs - -1 on fatal error, 0 on partial write, otherwise 1
  963. */
  964. static int
  965. write_sendq(struct lconn *conn_p)
  966. {
  967. struct send_queue *sendq;
  968. dlink_node *ptr;
  969. dlink_node *next_ptr;
  970. int n;
  971. DLINK_FOREACH_SAFE(ptr, next_ptr, conn_p->sendq.head)
  972. {
  973. sendq = ptr->data;
  974. /* write, starting at the offset */
  975. if((n = write(conn_p->fd, sendq->buf + sendq->pos, sendq->len)) < 0)
  976. {
  977. if(n == -1 && ignore_errno(errno))
  978. return 0;
  979. return -1;
  980. }
  981. /* wrote full sendq? */
  982. if(n == sendq->len)
  983. {
  984. dlink_destroy(ptr, &conn_p->sendq);
  985. my_free((void *)sendq->buf);
  986. my_free(sendq);
  987. }
  988. else
  989. {
  990. sendq->pos += n;
  991. sendq->len -= n;
  992. return 0;
  993. }
  994. }
  995. return 1;
  996. }
  997. /* sendq_add()
  998. * adds a given buffer to a connections sendq
  999. *
  1000. * inputs - connection to add to, buffer to add, length of buffer,
  1001. * offset at where to start writing
  1002. * outputs -
  1003. */
  1004. static void
  1005. sendq_add(struct lconn *conn_p, const char *buf, size_t len, size_t offset)
  1006. {
  1007. struct send_queue *sendq = my_calloc(1, sizeof(struct send_queue));
  1008. sendq->buf = my_strdup(buf);
  1009. sendq->len = len - offset;
  1010. sendq->pos = offset;
  1011. dlink_add_tail_alloc(sendq, &conn_p->sendq);
  1012. }
  1013. int
  1014. sock_create(int domain)
  1015. {
  1016. int fd = -1;
  1017. int optval = 1;
  1018. int flags;
  1019. if((fd = socket(domain, SOCK_STREAM, 0)) < 0)
  1020. return -1;
  1021. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
  1022. flags= fcntl(fd, F_GETFL, 0);
  1023. flags |= O_NONBLOCK;
  1024. if(fcntl(fd, F_SETFL, flags) == -1)
  1025. return -1;
  1026. return fd;
  1027. }
  1028. #ifdef HAVE_GETADDRINFO
  1029. /* sock_open()
  1030. * attempts to open a connection
  1031. *
  1032. * inputs - host/port to connect to, vhost to use
  1033. * outputs - fd of socket, -1 on error
  1034. */
  1035. int
  1036. sock_open(const char *host, int port, const char *vhost, int type)
  1037. {
  1038. struct addrinfo *hostres;
  1039. int fd = -1;
  1040. /* no specific vhost, try default */
  1041. if(vhost == NULL)
  1042. vhost = config_file.vhost;
  1043. if(vhost != NULL)
  1044. {
  1045. struct addrinfo *bindres;
  1046. if((bindres = gethostinfo(vhost, 0)) != NULL)
  1047. {
  1048. fd = sock_create(bindres->ai_family);
  1049. if(fd < 0)
  1050. {
  1051. mlog("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1052. host, port, strerror(errno));
  1053. sendto_all("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1054. host, port, strerror(errno));
  1055. return -1;
  1056. }
  1057. if((bind(fd, bindres->ai_addr, bindres->ai_addrlen)) < 0)
  1058. {
  1059. mlog("Connection to %s/%d failed: "
  1060. "(unable to bind to %s: %s)",
  1061. host, port, vhost, strerror(errno));
  1062. sendto_all("Connection to %s/%d failed: (unable to bind to %s: %s)",
  1063. host, port, vhost, strerror(errno));
  1064. return -1;
  1065. }
  1066. }
  1067. freeaddrinfo(bindres);
  1068. }
  1069. if(type == IO_HOST)
  1070. {
  1071. if((hostres = gethostinfo(host, port)) == NULL)
  1072. {
  1073. mlog("Connection to %s/%d failed: "
  1074. "(unable to resolve: %s)",
  1075. host, port, host);
  1076. sendto_all("Connection to %s/%d failed: (unable to resolve: %s)",
  1077. host, port, host);
  1078. return -1;
  1079. }
  1080. if(fd < 0)
  1081. fd = sock_create(hostres->ai_family);
  1082. if(fd < 0)
  1083. {
  1084. mlog("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1085. host, port, strerror(errno));
  1086. sendto_all("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1087. host, port, strerror(errno));
  1088. return -1;
  1089. }
  1090. connect(fd, hostres->ai_addr, hostres->ai_addrlen);
  1091. freeaddrinfo(hostres);
  1092. return fd;
  1093. }
  1094. else
  1095. {
  1096. struct sockaddr_in raddr;
  1097. unsigned long hl;
  1098. if(fd < 0)
  1099. fd = sock_create(AF_INET);
  1100. if(fd < 0)
  1101. {
  1102. mlog("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1103. host, port, strerror(errno));
  1104. sendto_all("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1105. host, port, strerror(errno));
  1106. return -1;
  1107. }
  1108. memset(&raddr, 0, sizeof(struct sockaddr_in));
  1109. raddr.sin_family = AF_INET;
  1110. raddr.sin_port = htons(port);
  1111. hl = strtoul(host, NULL, 10);
  1112. raddr.sin_addr.s_addr = htonl(hl);
  1113. connect(fd, (struct sockaddr *) &raddr, sizeof(struct sockaddr_in));
  1114. return fd;
  1115. }
  1116. }
  1117. #else
  1118. /* sock_open()
  1119. * attempts to open a connection
  1120. *
  1121. * inputs - host/port to connect to, vhost to use
  1122. * outputs - fd of socket, -1 on error
  1123. */
  1124. int
  1125. sock_open(const char *host, int port, const char *vhost, int type)
  1126. {
  1127. struct sockaddr_in raddr;
  1128. struct hostent *host_addr;
  1129. int fd = -1;
  1130. fd = sock_create(AF_INET);
  1131. if(fd < 0)
  1132. {
  1133. mlog("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1134. host, port, strerror(errno));
  1135. sendto_all("Connection to %s/%d failed: (socket()/fcntl(): %s)",
  1136. host, port, strerror(errno));
  1137. return -1;
  1138. }
  1139. /* no specific vhost, try default */
  1140. if(vhost == NULL)
  1141. vhost = config_file.vhost;
  1142. if(vhost != NULL)
  1143. {
  1144. struct sockaddr_in addr;
  1145. if((host_addr = gethostbyname(vhost)) != NULL)
  1146. {
  1147. memset(&addr, 0, sizeof(struct sockaddr_in));
  1148. memcpy(&addr.sin_addr, host_addr->h_addr,
  1149. host_addr->h_length);
  1150. addr.sin_family = AF_INET;
  1151. addr.sin_port = 0;
  1152. if(bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
  1153. {
  1154. mlog("Connection to %s/%d failed: "
  1155. "(unable to bind to %s: %s)",
  1156. host, port, vhost, strerror(errno));
  1157. sendto_all("Connection to %s/%d failed: (unable to bind to %s: %s)",
  1158. host, port, vhost, strerror(errno));
  1159. return -1;
  1160. }
  1161. }
  1162. }
  1163. memset(&raddr, 0, sizeof(struct sockaddr_in));
  1164. raddr.sin_family = AF_INET;
  1165. raddr.sin_port = htons(port);
  1166. if(type == IO_HOST)
  1167. {
  1168. if((host_addr = gethostbyname(host)) == NULL)
  1169. {
  1170. mlog("Connection to %s/%d failed: "
  1171. "(unable to resolve: %s)",
  1172. host, port, host);
  1173. sendto_all("Connection to %s/%d failed: (unable to resolve: %s)",
  1174. host, port, host);
  1175. return -1;
  1176. }
  1177. memcpy(&raddr.sin_addr, host_addr->h_addr, host_addr->h_length);
  1178. }
  1179. else
  1180. {
  1181. unsigned long hl = strtoul(host, NULL, 10);
  1182. raddr.sin_addr.s_addr = htonl(hl);
  1183. }
  1184. connect(fd, (struct sockaddr *) &raddr, sizeof(struct sockaddr_in));
  1185. return fd;
  1186. }
  1187. #endif
  1188. /* sock_write()
  1189. * Writes a buffer to a given user, flushing sendq first.
  1190. *
  1191. * inputs - connection to write to, buffer, length of buffer
  1192. * outputs - -1 on fatal error, 0 on partial write, otherwise 1
  1193. */
  1194. int
  1195. sock_write(struct lconn *conn_p, const char *buf, size_t len)
  1196. {
  1197. size_t n;
  1198. if(dlink_list_length(&conn_p->sendq) > 0)
  1199. {
  1200. n = (conn_p->io_write)(conn_p);
  1201. /* got a partial write, add the new line to the sendq */
  1202. if(n == 0)
  1203. {
  1204. sendq_add(conn_p, buf, len, 0);
  1205. return 0;
  1206. }
  1207. else if(n == -1)
  1208. return -1;
  1209. }
  1210. if((n = write(conn_p->fd, buf, len)) < 0)
  1211. {
  1212. if(!ignore_errno(errno))
  1213. return -1;
  1214. /* write wouldve blocked so wasnt done, we didnt write
  1215. * anything so reset n to zero and carry on.
  1216. */
  1217. n = 0;
  1218. }
  1219. /* partial write.. add this line to sendq with offset of however
  1220. * much we wrote
  1221. */
  1222. if(n != len)
  1223. sendq_add(conn_p, buf, len, n);
  1224. return 1;
  1225. }
  1226. void
  1227. sock_close(struct lconn *conn_p)
  1228. {
  1229. close(conn_p->fd);
  1230. conn_p->fd = -1;
  1231. }
  1232. #ifdef HAVE_GETADDRINFO
  1233. /* Stolen from FreeBSD's whois client, modified for rserv by W. Campbell */
  1234. static struct addrinfo *gethostinfo(char const *host, int port)
  1235. {
  1236. struct addrinfo hints, *res;
  1237. int error;
  1238. char portbuf[6];
  1239. memset(&hints, 0, sizeof(hints));
  1240. hints.ai_flags = 0;
  1241. hints.ai_family = AF_UNSPEC;
  1242. hints.ai_socktype = SOCK_STREAM;
  1243. snprintf(portbuf, sizeof(portbuf), "%d", port);
  1244. error = getaddrinfo(host, portbuf, &hints, &res);
  1245. if (error)
  1246. {
  1247. mlog("gethostinfo error: %s: %s", host, gai_strerror(error));
  1248. return (NULL);
  1249. }
  1250. return (res);
  1251. }
  1252. #endif