sockd_child.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:23k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1997, 1998, 1999
  3.  *      Inferno Nettverk A/S, Norway.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. The above copyright notice, this list of conditions and the following
  9.  *    disclaimer must appear in all copies of the software, derivative works
  10.  *    or modified versions, and any portions thereof, aswell as in all
  11.  *    supporting documentation.
  12.  * 2. All advertising materials mentioning features or use of this software
  13.  *    must display the following acknowledgement:
  14.  *      This product includes software developed by
  15.  *      Inferno Nettverk A/S, Norway.
  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 WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * Inferno Nettverk A/S requests users of this software to return to
  31.  *
  32.  *  Software Distribution Coordinator  or  sdc@inet.no
  33.  *  Inferno Nettverk A/S
  34.  *  Oslo Research Park
  35.  *  Gaustadal閑n 21
  36.  *  N-0349 Oslo
  37.  *  Norway
  38.  *
  39.  * any improvements or extensions that they make and grant Inferno Nettverk A/S
  40.  * the rights to redistribute these changes.
  41.  *
  42.  */
  43. #include "common.h"
  44. static const char rcsid[] =
  45. "$Id: sockd_child.c,v 1.118 2000/01/05 10:38:58 michaels Exp $";
  46. #define MOTHER 0 /* descriptor mother reads/writes on. */
  47. #define CHILD 1 /* descriptor child reads/writes on. */
  48. __BEGIN_DECLS
  49. static int
  50. setchildtype __P((int type, struct sockd_child_t ***childv, int **childc,
  51. void (**function)(struct sockd_mother_t *mother)));
  52. /*
  53.  * Sets "childv", "childc" and "function" to the correct value depending
  54.  * on "type".
  55.  */
  56. static int
  57. findchild __P((pid_t pid, int childc, const struct sockd_child_t *childv));
  58. /*
  59.  * Finds the child with pid "pid" in the array "childv".  Searching
  60.  * Elements in "childv" is given by "childc".
  61.  * Returns:
  62.  * On success: the index of the child in "childv".
  63.  * On failure: -1.
  64.  */
  65. __END_DECLS
  66. static struct sockd_child_t *iochildv; /* all our iochildren */
  67. static int iochildc;
  68. static struct sockd_child_t *negchildv; /* all our negotiatorchildren */
  69. static int negchildc;
  70. static struct sockd_child_t *reqchildv; /* all our requestchildren */
  71. static int reqchildc;
  72. struct sockd_child_t *
  73. addchild(type)
  74. int type;
  75. {
  76. const char *function = "addchild()";
  77. /*
  78.     * It is better to reserve some descriptors for temporary use
  79.     * than to get errors when passing them and thus lose clients.
  80.     */
  81. const int reserved = FDPASS_MAX /* max descriptors we pass. */
  82.  + 1 /* need a descriptor for accept(). */
  83.  + 2; /* for each new child. */
  84. struct sockd_mother_t mother;
  85. struct sockd_child_t **childv;
  86. int *childc;
  87. void (*childfunction)(struct sockd_mother_t *mother);
  88. pid_t pid;
  89. int optval, flags;
  90. int pipev[] = { -1, -1 };
  91. int ackpipev[] = { -1, -1 };
  92. /*
  93.  * XXX This is a expensive test which shouldn't be hard to optimize
  94.  * away.  It only happens when we are running low on slots though,
  95.  * so assume it's "good enough" until I get the time to fix it.
  96.  */
  97. if (freedescriptors(NULL) < reserved) {
  98. errno = EMFILE;
  99. swarn(function);
  100. return NULL;
  101. }
  102. /* create datapipe. */
  103. if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {
  104. swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
  105. return NULL;
  106. }
  107. /* and ackpipe. */
  108. if (pipe(ackpipev) != 0) {
  109. swarn("%s: pipe()", function);
  110. closev(pipev, ELEMENTS(pipev));
  111. return NULL;
  112. }
  113. /*
  114.  * Try to set socketbuffer and watermarks to a optimal size.
  115.  */
  116. switch (type = setchildtype(type, &childv, &childc, &childfunction)) {
  117. case CHILD_NEGOTIATE:
  118. /*
  119.  * A negotiator child receives only descriptors, so mothers
  120.  * send buffer can be small, and so can the child's receive buffer.
  121.  * The child sends a sockd_request_t struct back to mother, so
  122.  * mothers recv buffer has to be considerably bigger, as does
  123.  * childs send buffer.
  124.  */
  125. /* negotiator shouldn't block on sending to mother. */
  126. if ((flags = fcntl(pipev[CHILD], F_GETFL, 0)) == -1
  127. ||  fcntl(pipev[CHILD], F_SETFL, flags | O_NONBLOCK) == -1)
  128. swarn("%s: fcntl()", function);
  129. #if HAVE_SENDMSG_DEADLOCK
  130. if ((mother.lock = socks_mklock(SOCKS_LOCKFILE)) == -1) {
  131. swarn("%s: socks_mklock()", function);
  132. closev(pipev, ELEMENTS(pipev));
  133. closev(ackpipev, ELEMENTS(ackpipev));
  134. return NULL;
  135. }
  136. #endif /* HAVE_SENDMSG_DEADLOCK */
  137. optval = sizeof(struct sockd_request_t) * (SOCKD_NEGOTIATEMAX + 1);
  138. if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
  139. sizeof(optval)) != 0
  140. ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
  141. sizeof(optval)) != 0)
  142. swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);
  143. #if HAVE_SO_SNDLOWAT
  144. optval = sizeof(struct sockd_request_t) * LOWATSKEW;
  145. if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,
  146. sizeof(optval)) != 0
  147. || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,
  148. sizeof(optval)) != 0)
  149. swarn("%s: setsockopt(SO_SNDLOWAT/SO_RCVLOWAT)", function);
  150. #endif
  151. break;
  152. case CHILD_REQUEST:
  153. /*
  154.  * A request child receives a sockd_request_t structure,
  155.  * it sends back a sockd_io_t structure.
  156.  */
  157. #if HAVE_SENDMSG_DEADLOCK
  158. mother.lock = -1; /* doesn't need lock. */
  159. #endif /* HAVE_SENDMSG_DEADLOCK */
  160. optval = sizeof(struct sockd_request_t) * (SOCKD_REQUESTMAX + 1);
  161. if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,
  162. sizeof(optval)) != 0
  163. ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,
  164. sizeof(optval)) != 0)
  165. swarn("%s: setsockopt()", function);
  166. optval = sizeof(struct sockd_io_t) * (SOCKD_REQUESTMAX + 1);
  167. if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
  168. sizeof(optval)) != 0
  169. ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
  170. sizeof(optval)) != 0)
  171. swarn("%s: setsockopt()", function);
  172. #if HAVE_SO_SNDLOWAT
  173. optval = sizeof(struct sockd_request_t) * LOWATSKEW;
  174. if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,
  175. sizeof(optval)) != 0
  176. || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,
  177. sizeof(optval)) != 0)
  178. swarn("%s: setsockopt(SO_RCVLOWAT)", function);
  179. optval = sizeof(struct sockd_io_t) * LOWATSKEW;
  180. if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,
  181. sizeof(optval)) != 0
  182. || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,
  183. sizeof(optval)) != 0)
  184. swarn("%s: setsockopt(SO_RCVLOWAT/SO_SNDLOWAT)", function);
  185. #endif
  186. break;
  187. case CHILD_IO:
  188. /*
  189.  * A io child receives a sockd_io_t structure,
  190.  * it sends back only a ack.
  191.  */
  192. #if HAVE_SENDMSG_DEADLOCK
  193. mother.lock = -1; /* doesn't need lock. */
  194. #endif /* HAVE_SENDMSG_DEADLOCK */
  195. optval = sizeof(struct sockd_io_t) * (SOCKD_IOMAX + 1);
  196. if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,
  197. sizeof(optval)) != 0
  198. ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,
  199. sizeof(optval)) != 0)
  200. swarn("%s: setsockopt(SO_SNDBUF/SO_RCVBUF)", function);
  201. optval = sizeof(int) * (SOCKD_IOMAX + 1);
  202. if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
  203. sizeof(optval)) != 0
  204. ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
  205. sizeof(optval)) != 0)
  206. swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);
  207. #if HAVE_SO_SNDLOWAT
  208. optval = sizeof(struct sockd_io_t) * LOWATSKEW;
  209. if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,
  210. sizeof(optval)) != 0
  211. || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,
  212. sizeof(optval)) != 0)
  213. swarn("%s: setsockopt(SO_RCVLOWAT)", function);
  214. #endif
  215. break;
  216. default:
  217. SERRX(type);
  218. }
  219. switch ((pid = fork())) {
  220. case -1:
  221. swarn("%s: fork()", function);
  222. closev(pipev, ELEMENTS(pipev));
  223. closev(ackpipev, ELEMENTS(ackpipev));
  224. #if HAVE_SENDMSG_DEADLOCK
  225. if (mother.lock != -1)
  226. close(mother.lock);
  227. #endif /* HAVE_SENDMSG_DEADLOCK */
  228. return NULL;
  229. case 0: {
  230. size_t i, maxfd;
  231. struct sigaction sigact;
  232. config.state.type = type;
  233. config.state.pid = getpid();
  234. initlog();
  235. slog(LOG_DEBUG, "created new %schild", childtype2string(type));
  236. #if 0
  237. slog(LOG_DEBUG, "sleeping...");
  238. sleep(20);
  239. #endif
  240. mother.s = pipev[CHILD];
  241. mother.ack = ackpipev[CHILD];
  242. /*
  243.  * It would be nice to be able to lose all privileges here
  244.  * but unfortunately we can't, yet.
  245.  *
  246.  * negotiation children:
  247.  * could need privileges to check password.
  248.  *
  249.  * request children:
  250.  * could need privileges to bind port.
  251.  *
  252.  * io children:
  253.  * doesn't really need any, but a sighup() performs misc.
  254.  * seteuid() tests that would fail if we lose privileges.
  255.  */
  256. switch (type) {
  257. case CHILD_NEGOTIATE:
  258. #if HAVE_LIBWRAP
  259. #if SOCKD_NEGOTIATEMAX > 1
  260. resident = 1;
  261. #endif /* SOCKD_NEGOTIATEMAX > 1 */
  262. #endif  /* HAVE_LIBWRAP */
  263. break;
  264. case CHILD_REQUEST:
  265. #if HAVE_LIBWRAP
  266. #if SOCKD_REQUESTMAX > 1
  267. resident = 1;
  268. #endif /* SOCKD_REQUESTMAX > 1 */
  269. #endif  /* HAVE_LIBWRAP */
  270. break;
  271. case CHILD_IO:
  272. #if HAVE_LIBWRAP
  273. #if SOCKD_IOMAX > 1
  274. resident = 1;
  275. #endif /* SOCKD_IOMAX > 1 */
  276. #endif  /* HAVE_LIBWRAP */
  277. break;
  278. default:
  279. SERRX(type);
  280. }
  281. sigemptyset(&sigact.sa_mask);
  282. sigact.sa_flags = 0;
  283. /* signals mother has set up but which we ignore at this point. */
  284. sigact.sa_handler = SIG_IGN;
  285. #if HAVE_SIGNAL_SIGINFO
  286. if (sigaction(SIGINFO, &sigact, NULL) != 0)
  287. swarn("%s: sigaction(SIGINFO)", function);
  288. #endif  /* HAVE_SIGNAL_SIGINFO */
  289. if (sigaction(SIGUSR1, &sigact, NULL) != 0)
  290. swarn("%s: sigaction(USR1)", function);
  291. /* delete everything we got from parent. */
  292. for (i = 0, maxfd = getdtablesize(); i < maxfd; ++i) {
  293. /* exceptions */
  294. if (i == (size_t)mother.s
  295. #if HAVE_SENDMSG_DEADLOCK
  296. || i == (size_t)mother.lock
  297. #endif /* HAVE_SENDMSG_DEADLOCK */
  298. || i == (size_t)mother.ack)
  299. continue;
  300. if (socks_logmatch(i, &config.log))
  301. continue;
  302. close((int)i);
  303. }
  304. initlog(); /* for syslog. */
  305. childfunction(&mother);
  306. /* NOTREACHED */
  307. }
  308. default: {
  309. struct sockd_child_t *newchildv;
  310. if ((newchildv = (struct sockd_child_t *)realloc(*childv,
  311. sizeof(**childv) * (*childc + 1))) == NULL) {
  312. slog(LOG_WARNING, "%s: %s", function, NOMEM);
  313. closev(pipev, ELEMENTS(pipev));
  314. closev(ackpipev, ELEMENTS(ackpipev));
  315. return NULL;
  316. }
  317. *childv = newchildv;
  318. (*childv)[*childc].type = type;
  319. (*childv)[*childc].pid = pid;
  320. (*childv)[*childc].s = pipev[MOTHER];
  321. #if HAVE_SENDMSG_DEADLOCK
  322. (*childv)[*childc].lock = mother.lock;
  323. #endif /* HAVE_SENDMSG_DEADLOCK */
  324. (*childv)[*childc].ack = ackpipev[MOTHER];
  325. close(pipev[CHILD]);
  326. close(ackpipev[CHILD]);
  327. switch ((*childv)[*childc].type) {
  328. case CHILD_NEGOTIATE:
  329. (*childv)[*childc].freec = SOCKD_NEGOTIATEMAX;
  330. break;
  331. case CHILD_REQUEST:
  332. (*childv)[*childc].freec = SOCKD_REQUESTMAX;
  333. break;
  334. case CHILD_IO:
  335. (*childv)[*childc].freec = SOCKD_IOMAX;
  336. break;
  337. default:
  338. SERRX((*childv)[*childc].type);
  339. }
  340. return &(*childv)[(*childc)++];
  341. }
  342. }
  343. }
  344. int
  345. childcheck(type)
  346. int type;
  347. {
  348. int child, proxyc;
  349. int min, max;
  350. struct sockd_child_t **childv;
  351. int *childc;
  352. switch (type) {
  353. case -CHILD_NEGOTIATE:
  354. case CHILD_NEGOTIATE:
  355. childc = &negchildc;
  356. childv = &negchildv;
  357. min = SOCKD_FREESLOTS;
  358. max = SOCKD_NEGOTIATEMAX;
  359. break;
  360. case -CHILD_REQUEST:
  361. case CHILD_REQUEST:
  362. childc = &reqchildc;
  363. childv = &reqchildv;
  364. min = SOCKD_FREESLOTS;
  365. max = SOCKD_REQUESTMAX;
  366. break;
  367. case -CHILD_IO:
  368. case CHILD_IO:
  369. childc = &iochildc;
  370. childv = &iochildv;
  371. /* attempt to keep in a state where we can accept all requests. */
  372. min = MAX(SOCKD_FREESLOTS, childcheck(-CHILD_REQUEST));
  373. max = SOCKD_IOMAX;
  374. break;
  375. default:
  376. SERRX(type);
  377. }
  378. /*
  379.  * get a estimate over how many (new) clients our children are able to
  380.  * accept in total.
  381.     */
  382. for (child = 0, proxyc = 0; child < *childc; ++child) {
  383. SASSERTX((*childv)[child].freec <= max);
  384. proxyc += type < 0 ? max : (*childv)[child].freec;
  385. }
  386. if (type >= 0)
  387. if (proxyc < min && config.state.addchild)
  388. if (addchild(type) != NULL)
  389. return childcheck(type);
  390. else
  391. config.state.addchild = 0; /* don't retry until a child dies. */
  392. return proxyc;
  393. }
  394. int
  395. fillset(set)
  396. fd_set *set;
  397. {
  398. int negc, reqc, ioc;
  399. int i, dbits;
  400. /*
  401.  * There is no point in setting data descriptor of child N unless
  402.  * child N+1 is able to accept the data from child N.  So find
  403.  * out if we have slots of the various types available .
  404.  */
  405. ioc = childcheck(CHILD_IO);
  406. reqc = childcheck(CHILD_REQUEST);
  407. negc = childcheck(CHILD_NEGOTIATE);
  408. FD_ZERO(set);
  409. dbits = -1;
  410. /* new clients we accept. */
  411. if (negc > 0)
  412. for (i = 0; i < config.internalc; ++i) {
  413. SASSERTX(config.internalv[i].s >= 0);
  414. FD_SET(config.internalv[i].s, set);
  415. dbits = MAX(dbits, config.internalv[i].s);
  416. }
  417. /* negotiator children. */
  418. for (i = 0; i < negchildc; ++i) {
  419. if (reqc > 0) {
  420. SASSERTX(negchildv[i].s >= 0);
  421. FD_SET(negchildv[i].s, set);
  422. dbits = MAX(dbits, negchildv[i].s);
  423. }
  424. /* we can always accept a ack ofcourse. */
  425. SASSERTX(negchildv[i].ack >= 0);
  426. FD_SET(negchildv[i].ack, set);
  427. dbits = MAX(dbits, negchildv[i].ack);
  428. }
  429. /* request children. */
  430. for (i = 0; i < reqchildc; ++i) {
  431. if (ioc > 0) {
  432. SASSERTX(reqchildv[i].s >= 0);
  433. FD_SET(reqchildv[i].s, set);
  434. dbits = MAX(dbits, reqchildv[i].s);
  435. }
  436. /* we can always accept a ack ofcourse. */
  437. SASSERTX(reqchildv[i].ack >= 0);
  438. FD_SET(reqchildv[i].ack, set);
  439. dbits = MAX(dbits, reqchildv[i].ack);
  440. }
  441. /* io children, last in chain. */
  442. for (i = 0; i < iochildc; ++i) {
  443. SASSERTX(iochildv[i].s >= 0);
  444. FD_SET(iochildv[i].s, set);
  445. dbits = MAX(dbits, iochildv[i].s);
  446. SASSERTX(iochildv[i].ack >= 0);
  447. FD_SET(iochildv[i].ack, set);
  448. dbits = MAX(dbits, iochildv[i].ack);
  449. }
  450. return dbits;
  451. }
  452. void
  453. clearset(type, child, set)
  454. int type;
  455. const struct sockd_child_t *child;
  456. fd_set *set;
  457. {
  458. switch (type) {
  459. case SOCKD_FREESLOT:
  460. FD_CLR(child->ack, set);
  461. break;
  462. case SOCKD_NEWREQUEST:
  463. FD_CLR(child->s, set);
  464. break;
  465. default:
  466. SERRX(type);
  467. }
  468. }
  469. struct sockd_child_t *
  470. getset(type, set)
  471. int type;
  472. fd_set *set;
  473. {
  474. int i;
  475. /* check negotiator children for match. */
  476. for (i = 0; i < negchildc; ++i)
  477. switch (type) {
  478. case SOCKD_NEWREQUEST:
  479. if (FD_ISSET(negchildv[i].s, set))
  480. return &negchildv[i];
  481. break;
  482. case SOCKD_FREESLOT:
  483. if (FD_ISSET(negchildv[i].ack, set))
  484. return &negchildv[i];
  485. break;
  486. }
  487. /* check request children for match. */
  488. for (i = 0; i < reqchildc; ++i)
  489. switch (type) {
  490. case SOCKD_NEWREQUEST:
  491. if (FD_ISSET(reqchildv[i].s, set))
  492. return &reqchildv[i];
  493. break;
  494. case SOCKD_FREESLOT:
  495. if (FD_ISSET(reqchildv[i].ack, set))
  496. return &reqchildv[i];
  497. break;
  498. }
  499. /* check io children for match. */
  500. for (i = 0; i < iochildc; ++i)
  501. switch (type) {
  502. case SOCKD_NEWREQUEST:
  503. if (FD_ISSET(iochildv[i].s, set))
  504. return &iochildv[i];
  505. break;
  506. case SOCKD_FREESLOT:
  507. if (FD_ISSET(iochildv[i].ack, set))
  508. return &iochildv[i];
  509. break;
  510. }
  511. return NULL;
  512. }
  513. int
  514. removechild(pid)
  515. pid_t pid;
  516. {
  517. const char *function = "removechild()";
  518. struct sockd_child_t **childv;
  519. struct sockd_child_t *newchildv;
  520. int *childc;
  521. int child;
  522. slog(LOG_DEBUG, "%s: %d", function, (int)pid);
  523. setchildtype(childtype(pid), &childv, &childc, NULL);
  524. child = findchild(pid, *childc, *childv);
  525. SASSERTX(child >= 0);
  526. close((*childv)[child].s);
  527. close((*childv)[child].ack);
  528. /* shift all following one down */
  529. while (child < *childc - 1)
  530. (*childv)[child] = (*childv)[++child];
  531. --*childc;
  532. if ((newchildv = (struct sockd_child_t *)realloc(*childv,
  533. sizeof(**childv) * (*childc + 1))) == NULL) {
  534. slog(LOG_WARNING, NOMEM);
  535. return -1;
  536. }
  537. *childv = newchildv;
  538. return 0;
  539. }
  540. struct sockd_child_t *
  541. nextchild(type)
  542. int type;
  543. {
  544. const char *function = "nextchild()";
  545. struct timeval timeout;
  546. struct sockd_child_t **childv;
  547. int *childc;
  548. int i, maxd;
  549. fd_set wset;
  550. setchildtype(type, &childv, &childc, NULL);
  551. FD_ZERO(&wset);
  552. for (i = 0, maxd = -1; i < *childc; ++i)
  553. if ((*childv)[i].freec > 0) {
  554. FD_SET((*childv)[i].s, &wset);
  555. maxd = MAX(maxd, (*childv)[i].s);
  556. }
  557. if (maxd < 0)
  558. return NULL;
  559. ++maxd;
  560. timeout.tv_sec = 0;
  561. timeout.tv_usec = 0;
  562. switch (selectn(maxd, NULL, &wset, NULL, &timeout)) {
  563. case -1:
  564. SERR(-1);
  565. /* NOTREACHED */
  566. case 0:
  567. slog(LOG_DEBUG, "%s: no child writable", function);
  568. return NULL;
  569. }
  570. return getset(SOCKD_NEWREQUEST, &wset);
  571. }
  572. static int
  573. setchildtype(type, childv, childc, function)
  574. int type;
  575. struct sockd_child_t ***childv;
  576. int **childc;
  577. void (**function)(struct sockd_mother_t *mother);
  578. {
  579. switch (type) {
  580. case CHILD_IO:
  581. if (childv != NULL)
  582. *childv = &iochildv;
  583. if (childc != NULL)
  584. *childc = &iochildc;
  585. if (function != NULL)
  586. *function = &run_io;
  587. break;
  588. case CHILD_NEGOTIATE:
  589. if (childv != NULL)
  590. *childv = &negchildv;
  591. if (childc != NULL)
  592. *childc = &negchildc;
  593. if (function != NULL)
  594. *function = &run_negotiate;
  595. break;
  596. case CHILD_REQUEST:
  597. if (childv != NULL)
  598. *childv = &reqchildv;
  599. if (childc != NULL)
  600. *childc = &reqchildc;
  601. if (function != NULL)
  602. *function = &run_request;
  603. break;
  604. default:
  605. SASSERTX(type);
  606. }
  607. return type;
  608. }
  609. int
  610. childtype(pid)
  611. pid_t pid;
  612. {
  613. if (findchild(pid, iochildc, iochildv) != -1)
  614. return CHILD_IO;
  615. if (findchild(pid, negchildc, negchildv) != -1)
  616. return CHILD_NEGOTIATE;
  617. if (findchild(pid, reqchildc, reqchildv) != -1)
  618. return CHILD_REQUEST;
  619. if (pidismother(pid))
  620. return CHILD_MOTHER;
  621. SERRX(pid);
  622. /* NOTREACHED */
  623. }
  624. static int
  625. findchild(pid, childc, childv)
  626. pid_t pid;
  627. int childc;
  628. const struct sockd_child_t *childv;
  629. {
  630. int i;
  631. for (i = 0; i < childc; ++i)
  632. if (childv[i].pid == pid)
  633. return i;
  634. return -1;
  635. }
  636. struct sockd_child_t *
  637. getchild(pid)
  638. pid_t pid;
  639. {
  640. int child, type;
  641. int *childc;
  642. struct sockd_child_t **childv;
  643. switch (type = childtype(pid)) {
  644. case CHILD_IO:
  645. case CHILD_NEGOTIATE:
  646. case CHILD_REQUEST:
  647. break;
  648. case CHILD_MOTHER:
  649. return NULL;
  650. default:
  651. SERRX(type);
  652. }
  653. setchildtype(type, &childv, &childc, NULL);
  654. if ((child = findchild(pid, *childc, *childv)) != -1)
  655. return &(*childv)[child];
  656. return NULL;
  657. }
  658. int
  659. send_io(s, io)
  660. int s;
  661. const struct sockd_io_t *io;
  662. {
  663. const char *function = "send_io()";
  664. struct iovec iovec[1];
  665. struct msghdr msg;
  666. int w, fdsent, length;
  667. CMSG_AALLOC(sizeof(int) * FDPASS_MAX);
  668. length = 0;
  669. /* LINTED operands have incompatible pointer types */
  670. iovec[0].iov_base = (const void *)io;
  671. iovec[0].iov_len = sizeof(*io);
  672. length   += iovec[0].iov_len;
  673. fdsent = 0;
  674. CMSG_ADDOBJECT(io->in.s, sizeof(io->in.s) * fdsent++);
  675. CMSG_ADDOBJECT(io->out.s, sizeof(io->out.s) * fdsent++);
  676. switch (io->state.command) {
  677. case SOCKS_BIND:
  678. case SOCKS_BINDREPLY:
  679. if (!io->state.extension.bind)
  680. break;
  681. /* else: */ /* FALLTHROUGH */
  682. case SOCKS_UDPASSOCIATE:
  683. CMSG_ADDOBJECT(io->control.s, sizeof(io->control.s) * fdsent++);
  684. break;
  685. case SOCKS_CONNECT:
  686. break;
  687. default:
  688. SERRX(io->state.command);
  689. }
  690. msg.msg_iov = iovec;
  691. msg.msg_iovlen = ELEMENTS(iovec);
  692. msg.msg_name = NULL;
  693. msg.msg_namelen = 0;
  694. CMSG_SETHDR_SEND(sizeof(int) * fdsent);
  695. if ((w = sendmsg(s, &msg, 0)) != length) {
  696. swarn("%s: sendmsg(): %d of %d", function, w, length);
  697. return -1;
  698. }
  699. #if DEBUG
  700. printfd(io, "sent");
  701. #endif
  702. return 0;
  703. }
  704. int
  705. send_client(s, client)
  706. int s;
  707. int client;
  708. {
  709. const char *function = "send_client()";
  710. const char command = SOCKD_NEWREQUEST;
  711. struct iovec iovec[1];
  712. struct msghdr msg;
  713. CMSG_AALLOC(sizeof(int));
  714. int fdsent;
  715. /* LINTED operands have incompatible pointer types */
  716. iovec[0].iov_base = (const void *)&command;
  717. iovec[0].iov_len = sizeof(command);
  718. fdsent = 0;
  719. CMSG_ADDOBJECT(client, sizeof(client) * fdsent++);
  720. msg.msg_iov = iovec;
  721. msg.msg_iovlen = ELEMENTS(iovec);
  722. msg.msg_name = NULL;
  723. msg.msg_namelen = 0;
  724. CMSG_SETHDR_SEND(sizeof(int) * fdsent);
  725. if (sendmsg(s, &msg, 0) != sizeof(command)) {
  726. swarn("%s: sendmsg()", function);
  727. return -1;
  728. }
  729. return 0;
  730. }
  731. int
  732. send_req(s, req)
  733. int s;
  734. const struct sockd_request_t *req;
  735. {
  736. const char *function = "send_req()";
  737. struct iovec iovec[1];
  738. struct msghdr msg;
  739. int fdsent;
  740. CMSG_AALLOC(sizeof(int));
  741. /* LINTED operands have incompatible pointer types */
  742. iovec[0].iov_base = (const void *)req;
  743. iovec[0].iov_len = sizeof(*req);
  744. fdsent = 0;
  745. CMSG_ADDOBJECT(req->s, sizeof(req->s) * fdsent++);
  746. msg.msg_iov = iovec;
  747. msg.msg_iovlen = ELEMENTS(iovec);
  748. msg.msg_name = NULL;
  749. msg.msg_namelen = 0;
  750. CMSG_SETHDR_SEND(sizeof(int) * fdsent);
  751. if (sendmsg(s, &msg, 0) != sizeof(*req)) {
  752. swarn("%s: sendmsg()", function);
  753. return -1;
  754. }
  755. return 0;
  756. }
  757. const char *
  758. childtype2string(type)
  759. int type;
  760. {
  761. switch (type) {
  762. case CHILD_IO:
  763. return "io";
  764. case CHILD_MOTHER:
  765. return "mother";
  766. case CHILD_NEGOTIATE:
  767. return "negotiator";
  768. case CHILD_REQUEST:
  769. return "request";
  770. default:
  771. SERRX(type);
  772. }
  773. /* NOTREACHED */
  774. }
  775. void
  776. sigchildbroadcast(sig, childtype)
  777. int sig;
  778. int childtype;
  779. {
  780. int i;
  781. if (childtype & CHILD_NEGOTIATE)
  782. for (i = 0; i < negchildc; ++i)
  783. kill(negchildv[i].pid, sig);
  784. if (childtype & CHILD_REQUEST)
  785. for (i = 0; i < reqchildc; ++i)
  786. kill(reqchildv[i].pid, sig);
  787. if (childtype & CHILD_IO)
  788. for (i = 0; i < iochildc; ++i)
  789. kill(iochildv[i].pid, sig);
  790. }
  791. #if DEBUG
  792. void
  793. printfd(io, prefix)
  794. const struct sockd_io_t *io;
  795. const char *prefix;
  796. {
  797. const char *function = "printfd()";
  798. struct sockaddr name;
  799. socklen_t namelen;
  800. char namestring[MAXSOCKADDRSTRING];
  801. bzero(&name, sizeof(name));
  802. namelen = sizeof(name);
  803. /* LINTED pointer casts may be troublesome */
  804. if (getsockname(io->in.s, &name, &namelen) != 0)
  805. swarn("%s: getsockname(io->in)", function);
  806. else
  807. slog(LOG_DEBUG, "%s: io->in (%d), name: %s",
  808. prefix, io->in.s, sockaddr2string(&name, namestring, sizeof(namestring)));
  809. bzero(&name, sizeof(name));
  810. namelen = sizeof(name);
  811. /* LINTED pointer casts may be troublesome */
  812. if (getsockname(io->out.s, &name, &namelen) != 0)
  813. swarn("%s: getsockname(io->out)", function);
  814. else
  815. slog(LOG_DEBUG, "%s: io->out (%d), name: %s",
  816. prefix, io->out.s,
  817. sockaddr2string(&name, namestring, sizeof(namestring)));
  818. switch (io->state.command) {
  819. case SOCKS_BIND:
  820. case SOCKS_BINDREPLY:
  821. if (!io->state.extension.bind)
  822. break;
  823. /* else: */ /* FALLTHROUGH */
  824. case SOCKS_UDPASSOCIATE:
  825. bzero(&name, sizeof(name));
  826. namelen = sizeof(name);
  827. /* LINTED pointer casts may be troublesome */
  828. if (getpeername(io->control.s, &name, &namelen)
  829. != 0)
  830. swarn("%s: getpeername(io->control)", function);
  831. else  {
  832. if (namelen == 0)
  833. slog(LOG_DEBUG, "%s: io->control (%d), name: <none>",
  834. prefix, io->control.s);
  835. else
  836. slog(LOG_DEBUG, "%s: io->control (%d), name: %s",
  837. prefix, io->control.s,
  838. sockaddr2string(&name, namestring, sizeof(namestring)));
  839. }
  840. break;
  841. case SOCKS_CONNECT:
  842. break;
  843. default:
  844. SERRX(io->state.command);
  845. }
  846. }
  847. #endif