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

/xio-socket.c

https://github.com/xscc/socat
C | 2121 lines | 1727 code | 220 blank | 174 comment | 330 complexity | ddfb9ef9156bff2d41ea7e6bb0347103 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* source: xio-socket.c */
  2. /* Copyright Gerhard Rieger */
  3. /* Published under the GNU General Public License V.2, see file COPYING */
  4. /* this file contains the source for socket related functions, and the
  5. implementation of generic socket addresses */
  6. #include "xiosysincludes.h"
  7. #if _WITH_SOCKET
  8. #include "xioopen.h"
  9. #include "xio-ascii.h"
  10. #include "xio-socket.h"
  11. #include "xio-named.h"
  12. #include "xio-unix.h"
  13. #if WITH_IP4
  14. #include "xio-ip4.h"
  15. #endif /* WITH_IP4 */
  16. #if WITH_IP6
  17. #include "xio-ip6.h"
  18. #endif /* WITH_IP6 */
  19. #include "xio-ip.h"
  20. #include "xio-listen.h"
  21. #include "xio-ipapp.h" /*! not clean */
  22. #include "xio-tcpwrap.h"
  23. static
  24. int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
  25. int xioflags, xiofile_t *xfd, unsigned groups,
  26. int dummy1, int dummy2, int dummy3);
  27. static
  28. int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
  29. int xioflags, xiofile_t *xfd, unsigned groups,
  30. int dummy1, int dummy2, int dummy3);
  31. static
  32. int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
  33. int xioflags, xiofile_t *xfd, unsigned groups,
  34. int dummy1, int dummy2, int dummy3);
  35. static
  36. int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
  37. int xioflags, xiofile_t *xfd, unsigned groups,
  38. int dummy1, int dummy2, int dummy3);
  39. static
  40. int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
  41. int xioflags, xiofile_t *xfd, unsigned groups,
  42. int dummy1, int socktype, int dummy3);
  43. static
  44. int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
  45. int xioflags, xiofile_t *xfd, unsigned groups,
  46. int dumy1, int dummy2, int dummy3);
  47. static
  48. int _xioopen_socket_sendto(const char *pfname, const char *type,
  49. const char *proto, const char *address,
  50. struct opt *opts, int xioflags, xiofile_t *xxfd,
  51. unsigned groups);
  52. static int
  53. xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
  54. char *typbuff, int typlen,
  55. char *nambuff, int namlen,
  56. char *envbuff, int envlen,
  57. char *valbuff, int vallen);
  58. #if WITH_GENERICSOCKET
  59. /* generic socket addresses */
  60. const struct addrdesc xioaddr_socket_connect = { "socket-connect", 1, xioopen_socket_connect, GROUP_FD|GROUP_SOCKET|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<remote-address>") };
  61. #if WITH_LISTEN
  62. const struct addrdesc xioaddr_socket_listen = { "socket-listen", 1, xioopen_socket_listen, GROUP_FD|GROUP_SOCKET|GROUP_LISTEN|GROUP_RANGE|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<local-address>") };
  63. #endif /* WITH_LISTEN */
  64. const struct addrdesc xioaddr_socket_sendto = { "socket-sendto", 3, xioopen_socket_sendto, GROUP_FD|GROUP_SOCKET, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
  65. const struct addrdesc xioaddr_socket_datagram= { "socket-datagram", 3, xioopen_socket_datagram, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
  66. const struct addrdesc xioaddr_socket_recvfrom= { "socket-recvfrom", 3, xioopen_socket_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_RANGE|GROUP_CHILD, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
  67. const struct addrdesc xioaddr_socket_recv = { "socket-recv", 1, xioopen_socket_recv, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
  68. #endif /* WITH_GENERICSOCKET */
  69. /* the following options apply not only to generic socket addresses but to all
  70. addresses that have anything to do with sockets */
  71. const struct optdesc opt_so_debug = { "so-debug", "debug", OPT_SO_DEBUG, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DEBUG };
  72. #ifdef SO_ACCEPTCONN /* AIX433 */
  73. const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN};
  74. #endif /* SO_ACCEPTCONN */
  75. const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST};
  76. const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR};
  77. const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE};
  78. #if HAVE_STRUCT_LINGER
  79. const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER };
  80. #else /* !HAVE_STRUCT_LINGER */
  81. const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_LINGER };
  82. #endif /* !HAVE_STRUCT_LINGER */
  83. const struct optdesc opt_so_oobinline= { "so-oobinline", "oobinline", OPT_SO_OOBINLINE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_OOBINLINE};
  84. const struct optdesc opt_so_sndbuf = { "so-sndbuf", "sndbuf", OPT_SO_SNDBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDBUF};
  85. const struct optdesc opt_so_sndbuf_late={ "so-sndbuf-late","sndbuf-late",OPT_SO_SNDBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDBUF };
  86. const struct optdesc opt_so_rcvbuf = { "so-rcvbuf", "rcvbuf", OPT_SO_RCVBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVBUF};
  87. const struct optdesc opt_so_rcvbuf_late={"so-rcvbuf-late","rcvbuf-late",OPT_SO_RCVBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVBUF };
  88. const struct optdesc opt_so_error = { "so-error", "error", OPT_SO_ERROR, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ERROR};
  89. const struct optdesc opt_so_type = { "so-type", "type", OPT_SO_TYPE, GROUP_SOCKET, PH_SOCKET, TYPE_INT, OFUNC_SPEC, SOL_SOCKET, SO_TYPE };
  90. const struct optdesc opt_so_dontroute= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DONTROUTE };
  91. #ifdef SO_RCVLOWAT
  92. const struct optdesc opt_so_rcvlowat = { "so-rcvlowat", "rcvlowat", OPT_SO_RCVLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVLOWAT };
  93. #endif
  94. #ifdef SO_RCVTIMEO
  95. const struct optdesc opt_so_rcvtimeo = { "so-rcvtimeo", "rcvtimeo", OPT_SO_RCVTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVTIMEO };
  96. #endif
  97. #ifdef SO_SNDLOWAT
  98. const struct optdesc opt_so_sndlowat = { "so-sndlowat", "sndlowat", OPT_SO_SNDLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDLOWAT };
  99. #endif
  100. #ifdef SO_SNDTIMEO
  101. const struct optdesc opt_so_sndtimeo = { "so-sndtimeo", "sndtimeo", OPT_SO_SNDTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDTIMEO };
  102. #endif
  103. /* end of setsockopt options of UNIX98 standard */
  104. #ifdef SO_AUDIT /* AIX 4.3.3 */
  105. const struct optdesc opt_so_audit = { "so-audit", "audit", OPT_SO_AUDIT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_AUDIT };
  106. #endif /* SO_AUDIT */
  107. #ifdef SO_ATTACH_FILTER
  108. const struct optdesc opt_so_attach_filter={"so-attach-filter","attachfilter",OPT_SO_ATTACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_ATTACH_FILTER};
  109. #endif
  110. #ifdef SO_DETACH_FILTER
  111. const struct optdesc opt_so_detach_filter={"so-detach-filter","detachfilter",OPT_SO_DETACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DETACH_FILTER};
  112. #endif
  113. #ifdef SO_BINDTODEVICE /* Linux: man 7 socket */
  114. const struct optdesc opt_so_bindtodevice={"so-bindtodevice","if",OPT_SO_BINDTODEVICE,GROUP_SOCKET,PH_PASTSOCKET,TYPE_NAME,OFUNC_SOCKOPT,SOL_SOCKET,SO_BINDTODEVICE};
  115. #endif
  116. #ifdef SO_BSDCOMPAT
  117. const struct optdesc opt_so_bsdcompat= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BSDCOMPAT };
  118. #endif
  119. #ifdef SO_CKSUMRECV
  120. const struct optdesc opt_so_cksumrecv= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_CKSUMRECV };
  121. #endif /* SO_CKSUMRECV */
  122. #ifdef SO_TIMESTAMP
  123. const struct optdesc opt_so_timestamp= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TIMESTAMP };
  124. #endif
  125. #ifdef SO_KERNACCEPT /* AIX 4.3.3 */
  126. const struct optdesc opt_so_kernaccept={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KERNACCEPT};
  127. #endif /* SO_KERNACCEPT */
  128. #ifdef SO_NO_CHECK
  129. const struct optdesc opt_so_no_check = { "so-no-check", "nocheck",OPT_SO_NO_CHECK, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_NO_CHECK };
  130. #endif
  131. #ifdef SO_NOREUSEADDR /* AIX 4.3.3 */
  132. const struct optdesc opt_so_noreuseaddr={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET, SO_NOREUSEADDR};
  133. #endif /* SO_NOREUSEADDR */
  134. #ifdef SO_PASSCRED
  135. const struct optdesc opt_so_passcred = { "so-passcred", "passcred", OPT_SO_PASSCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PASSCRED};
  136. #endif
  137. #ifdef SO_PEERCRED
  138. const struct optdesc opt_so_peercred = { "so-peercred", "peercred", OPT_SO_PEERCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT3,OFUNC_SOCKOPT, SOL_SOCKET, SO_PEERCRED};
  139. #endif
  140. #ifdef SO_PRIORITY
  141. const struct optdesc opt_so_priority = { "so-priority", "priority", OPT_SO_PRIORITY, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PRIORITY};
  142. #endif
  143. #ifdef SO_REUSEPORT /* AIX 4.3.3, BSD, HP-UX */
  144. const struct optdesc opt_so_reuseport= { "so-reuseport","reuseport",OPT_SO_REUSEPORT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEPORT };
  145. #endif /* defined(SO_REUSEPORT) */
  146. #ifdef SO_SECURITY_AUTHENTICATION
  147. const struct optdesc opt_so_security_authentication={"so-security-authentication","securityauthentication",OPT_SO_SECURITY_AUTHENTICATION,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_AUTHENTICATION};
  148. #endif
  149. #ifdef SO_SECURITY_ENCRYPTION_NETWORK
  150. const struct optdesc opt_so_security_encryption_network={"so-security-encryption-network","securityencryptionnetwork",OPT_SO_SECURITY_ENCRYPTION_NETWORK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_NETWORK};
  151. #endif
  152. #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
  153. const struct optdesc opt_so_security_encryption_transport={"so-security-encryption-transport","securityencryptiontransport",OPT_SO_SECURITY_ENCRYPTION_TRANSPORT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_TRANSPORT};
  154. #endif
  155. #ifdef SO_USE_IFBUFS
  156. const struct optdesc opt_so_use_ifbufs={ "so-use-ifbufs","useifbufs",OPT_SO_USE_IFBUFS,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_USE_IFBUFS};
  157. #endif /* SO_USE_IFBUFS */
  158. #ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */
  159. const struct optdesc opt_so_useloopback={"so-useloopback","useloopback",OPT_SO_USELOOPBACK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT, SOL_SOCKET, SO_USELOOPBACK};
  160. #endif /* SO_USELOOPBACK */
  161. #ifdef SO_DGRAM_ERRIND /* Solaris */
  162. const struct optdesc opt_so_dgram_errind={"so-dgram-errind","dgramerrind",OPT_SO_DGRAM_ERRIND,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DGRAM_ERRIND};
  163. #endif /* SO_DGRAM_ERRIND */
  164. #ifdef SO_DONTLINGER /* Solaris */
  165. const struct optdesc opt_so_dontlinger = {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DONTLINGER };
  166. #endif
  167. /* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more
  168. general purpose */
  169. const struct optdesc opt_so_prototype = {"so-prototype", "prototype", OPT_SO_PROTOTYPE, GROUP_SOCKET,PH_SOCKET, TYPE_INT,OFUNC_SPEC, SOL_SOCKET,SO_PROTOTYPE };
  170. #ifdef FIOSETOWN
  171. const struct optdesc opt_fiosetown = { "fiosetown", NULL, OPT_FIOSETOWN, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, FIOSETOWN };
  172. #endif
  173. #ifdef SIOCSPGRP
  174. const struct optdesc opt_siocspgrp = { "siocspgrp", NULL, OPT_SIOCSPGRP, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, SIOCSPGRP };
  175. #endif
  176. const struct optdesc opt_bind = { "bind", NULL, OPT_BIND, GROUP_SOCKET, PH_BIND, TYPE_STRING,OFUNC_SPEC };
  177. const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.connect_timeout) };
  178. const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
  179. const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
  180. /* generic setsockopt() options */
  181. const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SOCKOPT_GENERIC, 0, 0 };
  182. const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
  183. const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
  184. const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.null_eof) };
  185. #if WITH_GENERICSOCKET
  186. static
  187. int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
  188. int xioflags, xiofile_t *xxfd, unsigned groups,
  189. int dummy1, int dummy2, int dummy3) {
  190. struct single *xfd = &xxfd->stream;
  191. const char *pfname = argv[1];
  192. const char *protname = argv[2];
  193. const char *address = argv[3];
  194. char *garbage;
  195. int pf;
  196. int proto;
  197. int socktype = SOCK_STREAM;
  198. int needbind = 0;
  199. union sockaddr_union them; socklen_t themlen; size_t themsize;
  200. union sockaddr_union us; socklen_t uslen = sizeof(us);
  201. int result;
  202. if (argc != 4) {
  203. Error2("%s: wrong number of parameters (%d instead of 3)",
  204. argv[0], argc-1);
  205. return STAT_NORETRY;
  206. }
  207. pf = strtoul(pfname, &garbage, 0);
  208. if (*garbage != '\0') {
  209. Warn1("garbage in parameter: \"%s\"", garbage);
  210. }
  211. proto = strtoul(protname, &garbage, 0);
  212. if (*garbage != '\0') {
  213. Warn1("garbage in parameter: \"%s\"", garbage);
  214. }
  215. retropt_socket_pf(opts, &pf);
  216. retropt_int(opts, OPT_SO_TYPE, &socktype);
  217. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  218. xfd->howtoend = END_SHUTDOWN;
  219. if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
  220. applyopts(-1, opts, PH_INIT);
  221. applyopts(-1, opts, PH_EARLY);
  222. themsize = 0;
  223. if ((result =
  224. dalan(address, (char *)&them.soa.sa_data, &themsize, sizeof(them)))
  225. < 0) {
  226. Error1("data too long: \"%s\"", address);
  227. } else if (result > 0) {
  228. Error1("syntax error in \"%s\"", address);
  229. }
  230. them.soa.sa_family = pf;
  231. themlen = themsize +
  232. #if HAVE_STRUCT_SOCKADDR_SALEN
  233. sizeof(them.soa.sa_len) +
  234. #endif
  235. sizeof(them.soa.sa_family);
  236. xfd->dtype = XIOREAD_STREAM|XIOWRITE_STREAM;
  237. socket_init(0, &us);
  238. if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3,
  239. 0, 0)
  240. != STAT_NOACTION) {
  241. needbind = true;
  242. us.soa.sa_family = pf;
  243. }
  244. if ((result =
  245. xioopen_connect(xfd,
  246. needbind?(struct sockaddr *)&us:NULL, uslen,
  247. (struct sockaddr *)&them, themlen,
  248. opts, pf, socktype, proto, false)) != 0) {
  249. return result;
  250. }
  251. if ((result = _xio_openlate(xfd, opts)) < 0) {
  252. return result;
  253. }
  254. return STAT_OK;
  255. }
  256. #if WITH_LISTEN
  257. static
  258. int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
  259. int xioflags, xiofile_t *xxfd, unsigned groups,
  260. int dummy1, int dummy2, int dummy3) {
  261. struct single *xfd = &xxfd->stream;
  262. const char *pfname = argv[1];
  263. const char *protname = argv[2];
  264. const char *usname = argv[3];
  265. char *garbage;
  266. int pf;
  267. int proto;
  268. int socktype = SOCK_STREAM;
  269. union sockaddr_union us; socklen_t uslen; size_t ussize;
  270. struct opt *opts0;
  271. int result;
  272. if (argc != 4) {
  273. Error2("%s: wrong number of parameters (%d instead of 3)",
  274. argv[0], argc-1);
  275. return STAT_NORETRY;
  276. }
  277. pf = strtoul(pfname, &garbage, 0);
  278. if (*garbage != '\0') {
  279. Warn1("garbage in parameter: \"%s\"", garbage);
  280. }
  281. proto = strtoul(protname, &garbage, 0);
  282. if (*garbage != '\0') {
  283. Warn1("garbage in parameter: \"%s\"", garbage);
  284. }
  285. retropt_socket_pf(opts, &pf);
  286. retropt_int(opts, OPT_SO_TYPE, &socktype);
  287. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  288. xfd->howtoend = END_SHUTDOWN;
  289. socket_init(0, &us);
  290. ussize = 0;
  291. if ((result =
  292. dalan(usname, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
  293. < 0) {
  294. Error1("data too long: \"%s\"", usname);
  295. } else if (result > 0) {
  296. Error1("syntax error in \"%s\"", usname);
  297. }
  298. uslen = ussize + sizeof(us.soa.sa_family)
  299. #if HAVE_STRUCT_SOCKADDR_SALEN
  300. + sizeof(us.soa.sa_len)
  301. #endif
  302. ;
  303. us.soa.sa_family = pf;
  304. if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
  305. applyopts(-1, opts, PH_INIT);
  306. applyopts(-1, opts, PH_EARLY);
  307. opts0 = copyopts(opts, GROUP_ALL);
  308. if ((result =
  309. xioopen_listen(xfd, xioflags,
  310. (struct sockaddr *)&us, uslen,
  311. opts, opts0, 0/*instead of pf*/, socktype, proto))
  312. != STAT_OK)
  313. return result;
  314. return STAT_OK;
  315. }
  316. #endif /* WITH_LISTEN */
  317. /* we expect the form: ...:domain:type:protocol:remote-address */
  318. static
  319. int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
  320. int xioflags, xiofile_t *xxfd, unsigned groups,
  321. int dummy1, int dummy2, int dummy3) {
  322. int result;
  323. if (argc != 5) {
  324. Error2("%s: wrong number of parameters (%d instead of 4)",
  325. argv[0], argc-1);
  326. return STAT_NORETRY;
  327. }
  328. if ((result =
  329. _xioopen_socket_sendto(argv[1], argv[2], argv[3], argv[4],
  330. opts, xioflags, xxfd, groups))
  331. != STAT_OK) {
  332. return result;
  333. }
  334. _xio_openlate(&xxfd->stream, opts);
  335. return STAT_OK;
  336. }
  337. static
  338. int _xioopen_socket_sendto(const char *pfname, const char *type,
  339. const char *protname, const char *address,
  340. struct opt *opts, int xioflags, xiofile_t *xxfd,
  341. unsigned groups) {
  342. xiosingle_t *xfd = &xxfd->stream;
  343. char *garbage;
  344. union sockaddr_union us = {{0}};
  345. socklen_t uslen = 0; size_t ussize;
  346. size_t themsize;
  347. int pf;
  348. int socktype = SOCK_RAW;
  349. int proto;
  350. bool needbind = false;
  351. char *bindstring = NULL;
  352. int result;
  353. pf = strtoul(pfname, &garbage, 0);
  354. if (*garbage != '\0') {
  355. Warn1("garbage in parameter: \"%s\"", garbage);
  356. }
  357. socktype = strtoul(type, &garbage, 0);
  358. if (*garbage != '\0') {
  359. Warn1("garbage in parameter: \"%s\"", garbage);
  360. }
  361. proto = strtoul(protname, &garbage, 0);
  362. if (*garbage != '\0') {
  363. Warn1("garbage in parameter: \"%s\"", garbage);
  364. }
  365. retropt_socket_pf(opts, &pf);
  366. retropt_int(opts, OPT_SO_TYPE, &socktype);
  367. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  368. xfd->howtoend = END_SHUTDOWN;
  369. xfd->peersa.soa.sa_family = pf;
  370. themsize = 0;
  371. if ((result =
  372. dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
  373. sizeof(xfd->peersa)))
  374. < 0) {
  375. Error1("data too long: \"%s\"", address);
  376. } else if (result > 0) {
  377. Error1("syntax error in \"%s\"", address);
  378. }
  379. xfd->salen = themsize + sizeof(sa_family_t)
  380. #if HAVE_STRUCT_SOCKADDR_SALEN
  381. + sizeof(xfd->peersa.soa.sa_len)
  382. #endif
  383. ;
  384. #if HAVE_STRUCT_SOCKADDR_SALEN
  385. xfd->peersa.soa.sa_len =
  386. sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
  387. themsize;
  388. #endif
  389. /* ...res_opts[] */
  390. if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
  391. applyopts(-1, opts, PH_INIT);
  392. if (pf == PF_UNSPEC) {
  393. pf = xfd->peersa.soa.sa_family;
  394. }
  395. xfd->dtype = XIODATA_RECVFROM;
  396. if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
  397. ussize = 0;
  398. if ((result =
  399. dalan(bindstring, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
  400. < 0) {
  401. Error1("data too long: \"%s\"", bindstring);
  402. } else if (result > 0) {
  403. Error1("syntax error in \"%s\"", bindstring);
  404. }
  405. us.soa.sa_family = pf;
  406. uslen = ussize + sizeof(sa_family_t)
  407. #if HAVE_STRUCT_SOCKADDR_SALEN
  408. + sizeof(us.soa.sa_len)
  409. #endif
  410. ;
  411. needbind = true;
  412. }
  413. return
  414. _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
  415. opts, xioflags, xfd, groups, pf, socktype, proto);
  416. }
  417. /* we expect the form: ...:domain:socktype:protocol:local-address */
  418. static
  419. int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
  420. int xioflags, xiofile_t *xxfd, unsigned groups,
  421. int dummy, int summy2, int dummy3) {
  422. struct single *xfd = &xxfd->stream;
  423. const char *pfname = argv[1];
  424. const char *typename = argv[2];
  425. const char *protname = argv[3];
  426. const char *address = argv[4];
  427. char *garbage;
  428. union sockaddr_union *us = &xfd->para.socket.la;
  429. socklen_t uslen; size_t ussize;
  430. int pf, socktype, proto;
  431. char *rangename;
  432. int result;
  433. if (argc != 5) {
  434. Error2("%s: wrong number of parameters (%d instead of 4)",
  435. argv[0], argc-1);
  436. return STAT_NORETRY;
  437. }
  438. pf = strtoul(pfname, &garbage, 0);
  439. if (*garbage != '\0') {
  440. Warn1("garbage in parameter: \"%s\"", garbage);
  441. }
  442. socktype = strtoul(typename, &garbage, 0);
  443. if (*garbage != '\0') {
  444. Warn1("garbage in parameter: \"%s\"", garbage);
  445. }
  446. proto = strtoul(protname, &garbage, 0);
  447. if (*garbage != '\0') {
  448. Warn1("garbage in parameter: \"%s\"", garbage);
  449. }
  450. retropt_socket_pf(opts, &pf);
  451. retropt_int(opts, OPT_SO_TYPE, &socktype);
  452. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  453. xfd->howtoend = END_NONE;
  454. ussize = 0;
  455. if ((result =
  456. dalan(address, (char *)&us->soa.sa_data, &ussize, sizeof(*us)))
  457. < 0) {
  458. Error1("data too long: \"%s\"", address);
  459. } else if (result > 0) {
  460. Error1("syntax error in \"%s\"", address);
  461. }
  462. us->soa.sa_family = pf;
  463. uslen = ussize + sizeof(us->soa.sa_family)
  464. #if HAVE_STRUCT_SOCKADDR_SALEN
  465. + sizeof(us->soa.sa_len);
  466. #endif
  467. ;
  468. xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
  469. if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
  470. if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
  471. return STAT_NORETRY;
  472. }
  473. xfd->para.socket.dorange = true;
  474. free(rangename);
  475. }
  476. if ((result =
  477. _xioopen_dgram_recvfrom(xfd, xioflags, &us->soa, uslen,
  478. opts, pf, socktype, proto, E_ERROR))
  479. != STAT_OK) {
  480. return result;
  481. }
  482. _xio_openlate(xfd, opts);
  483. return STAT_OK;
  484. }
  485. /* we expect the form: ...:domain:type:protocol:local-address */
  486. static
  487. int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
  488. int xioflags, xiofile_t *xxfd, unsigned groups,
  489. int dummy1, int dummy2, int dummy3) {
  490. struct single *xfd = &xxfd->stream;
  491. const char *pfname = argv[1];
  492. const char *typename = argv[2];
  493. const char *protname = argv[3];
  494. const char *address = argv[4];
  495. char *garbage;
  496. union sockaddr_union us;
  497. socklen_t uslen; size_t ussize;
  498. int pf, socktype, proto;
  499. char *rangename;
  500. int result;
  501. if (argc != 5) {
  502. Error2("%s: wrong number of parameters (%d instead of 4)",
  503. argv[0], argc-1);
  504. return STAT_NORETRY;
  505. }
  506. pf = strtoul(pfname, &garbage, 0);
  507. if (*garbage != '\0') {
  508. Warn1("garbage in parameter: \"%s\"", garbage);
  509. }
  510. socktype = strtoul(typename, &garbage, 0);
  511. if (*garbage != '\0') {
  512. Warn1("garbage in parameter: \"%s\"", garbage);
  513. }
  514. proto = strtoul(protname, &garbage, 0);
  515. if (*garbage != '\0') {
  516. Warn1("garbage in parameter: \"%s\"", garbage);
  517. }
  518. retropt_socket_pf(opts, &pf);
  519. retropt_int(opts, OPT_SO_TYPE, &socktype);
  520. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  521. xfd->howtoend = END_NONE;
  522. ussize = 0;
  523. if ((result =
  524. dalan(address, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
  525. < 0) {
  526. Error1("data too long: \"%s\"", address);
  527. } else if (result > 0) {
  528. Error1("syntax error in \"%s\"", address);
  529. }
  530. us.soa.sa_family = pf;
  531. uslen = ussize + sizeof(sa_family_t)
  532. #if HAVE_STRUCT_SOCKADDR_SALEN
  533. +sizeof(us.soa.sa_len)
  534. #endif
  535. ;
  536. xfd->dtype = XIOREAD_RECV;
  537. xfd->para.socket.la.soa.sa_family = pf;
  538. if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
  539. if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
  540. return STAT_NORETRY;
  541. }
  542. xfd->para.socket.dorange = true;
  543. free(rangename);
  544. }
  545. if ((result =
  546. _xioopen_dgram_recv(xfd, xioflags, &us.soa,
  547. uslen, opts, pf, socktype, proto, E_ERROR))
  548. != STAT_OK) {
  549. return result;
  550. }
  551. _xio_openlate(xfd, opts);
  552. return STAT_OK;
  553. }
  554. /* we expect the form: ...:domain:type:protocol:remote-address */
  555. static
  556. int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
  557. int xioflags, xiofile_t *xxfd, unsigned groups,
  558. int dummy1, int dummy2, int dummy3) {
  559. xiosingle_t *xfd = &xxfd->stream;
  560. const char *pfname = argv[1];
  561. const char *typename = argv[2];
  562. const char *protname = argv[3];
  563. const char *address = argv[4];
  564. char *garbage;
  565. char *rangename;
  566. size_t themsize;
  567. int pf;
  568. int result;
  569. if (argc != 5) {
  570. Error2("%s: wrong number of parameters (%d instead of 4)",
  571. argv[0], argc-1);
  572. return STAT_NORETRY;
  573. }
  574. pf = strtoul(pfname, &garbage, 0);
  575. if (*garbage != '\0') {
  576. Warn1("garbage in parameter: \"%s\"", garbage);
  577. }
  578. retropt_socket_pf(opts, &pf);
  579. /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
  580. xfd->howtoend = END_SHUTDOWN;
  581. xfd->peersa.soa.sa_family = pf;
  582. themsize = 0;
  583. if ((result =
  584. dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
  585. sizeof(xfd->peersa)))
  586. < 0) {
  587. Error1("data too long: \"%s\"", address);
  588. } else if (result > 0) {
  589. Error1("syntax error in \"%s\"", address);
  590. }
  591. xfd->salen = themsize + sizeof(sa_family_t);
  592. #if HAVE_STRUCT_SOCKADDR_SALEN
  593. xfd->peersa.soa.sa_len =
  594. sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
  595. themsize;
  596. #endif
  597. if ((result =
  598. _xioopen_socket_sendto(pfname, typename, protname, address,
  599. opts, xioflags, xxfd, groups))
  600. != STAT_OK) {
  601. return result;
  602. }
  603. xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
  604. xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
  605. /* which reply sockets will accept - determine by range option */
  606. if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
  607. if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
  608. free(rangename);
  609. return STAT_NORETRY;
  610. }
  611. xfd->para.socket.dorange = true;
  612. xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
  613. free(rangename);
  614. }
  615. _xio_openlate(xfd, opts);
  616. return STAT_OK;
  617. }
  618. #endif /* WITH_GENERICSOCKET */
  619. /* a subroutine that is common to all socket addresses that want to connect
  620. to a peer address.
  621. might fork.
  622. applies and consumes the following options:
  623. PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
  624. PH_CONNECTED, PH_LATE,
  625. OFUNC_OFFSET,
  626. OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
  627. returns 0 on success.
  628. */
  629. int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
  630. struct sockaddr *them, size_t themlen,
  631. struct opt *opts, int pf, int socktype, int protocol,
  632. bool alt, int level) {
  633. int fcntl_flags = 0;
  634. char infobuff[256];
  635. union sockaddr_union la;
  636. socklen_t lalen = themlen;
  637. int _errno;
  638. int result;
  639. if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
  640. return STAT_RETRYLATER;
  641. }
  642. applyopts_offset(xfd, opts);
  643. applyopts(xfd->fd, opts, PH_PASTSOCKET);
  644. applyopts(xfd->fd, opts, PH_FD);
  645. applyopts_cloexec(xfd->fd, opts);
  646. applyopts(xfd->fd, opts, PH_PREBIND);
  647. applyopts(xfd->fd, opts, PH_BIND);
  648. #if WITH_TCP || WITH_UDP
  649. if (alt) {
  650. union sockaddr_union sin, *sinp;
  651. unsigned short *port, i, N;
  652. div_t dv;
  653. /* prepare sockaddr for bind probing */
  654. if (us) {
  655. sinp = (union sockaddr_union *)us;
  656. } else {
  657. if (them->sa_family == AF_INET) {
  658. socket_in_init(&sin.ip4);
  659. #if WITH_IP6
  660. } else {
  661. socket_in6_init(&sin.ip6);
  662. #endif
  663. }
  664. sinp = &sin;
  665. }
  666. if (them->sa_family == AF_INET) {
  667. port = &sin.ip4.sin_port;
  668. #if WITH_IP6
  669. } else if (them->sa_family == AF_INET6) {
  670. port = &sin.ip6.sin6_port;
  671. #endif
  672. } else {
  673. port = 0; /* just to make compiler happy */
  674. }
  675. /* combine random+step variant to quickly find a free port when only
  676. few are in use, and certainly find a free port in defined time even
  677. if there are almost all in use */
  678. /* dirt 1: having tcp/udp code in socket function */
  679. /* dirt 2: using a time related system call for init of random */
  680. {
  681. /* generate a random port, with millisecond random init */
  682. #if 0
  683. struct timeb tb;
  684. ftime(&tb);
  685. srandom(tb.time*1000+tb.millitm);
  686. #else
  687. struct timeval tv;
  688. struct timezone tz;
  689. tz.tz_minuteswest = 0;
  690. tz.tz_dsttime = 0;
  691. if ((result = Gettimeofday(&tv, &tz)) < 0) {
  692. Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
  693. }
  694. srandom(tv.tv_sec*1000000+tv.tv_usec);
  695. #endif
  696. }
  697. dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
  698. i = N = XIO_IPPORT_LOWER + dv.rem;
  699. do { /* loop over lowport bind() attempts */
  700. *port = htons(i);
  701. if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
  702. Msg4(errno==EADDRINUSE?E_INFO:level,
  703. "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
  704. sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
  705. sizeof(*sinp), strerror(errno));
  706. if (errno != EADDRINUSE) {
  707. Close(xfd->fd);
  708. return STAT_RETRYLATER;
  709. }
  710. } else {
  711. break; /* could bind to port, good, continue past loop */
  712. }
  713. --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
  714. if (i == N) {
  715. Msg(level, "no low port available");
  716. /*errno = EADDRINUSE; still assigned */
  717. Close(xfd->fd);
  718. return STAT_RETRYLATER;
  719. }
  720. } while (i != N);
  721. } else
  722. #endif /* WITH_TCP || WITH_UDP */
  723. if (us) {
  724. if (Bind(xfd->fd, us, uslen) < 0) {
  725. Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
  726. xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
  727. uslen, strerror(errno));
  728. Close(xfd->fd);
  729. return STAT_RETRYLATER;
  730. }
  731. }
  732. applyopts(xfd->fd, opts, PH_PASTBIND);
  733. applyopts(xfd->fd, opts, PH_CONNECT);
  734. if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
  735. xfd->para.socket.connect_timeout.tv_usec != 0) {
  736. fcntl_flags = Fcntl(xfd->fd, F_GETFL);
  737. Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
  738. }
  739. result = Connect(xfd->fd, (struct sockaddr *)them, themlen);
  740. _errno = errno;
  741. la.soa.sa_family = them->sa_family; lalen = sizeof(la);
  742. if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
  743. Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
  744. xfd->fd, &la.soa, lalen, strerror(errno));
  745. }
  746. errno = _errno;
  747. if (result < 0) {
  748. if (errno == EINPROGRESS) {
  749. if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
  750. xfd->para.socket.connect_timeout.tv_usec != 0) {
  751. struct timeval timeout;
  752. struct pollfd writefd;
  753. int result;
  754. Info4("connect(%d, %s, "F_Zd"): %s",
  755. xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  756. themlen, strerror(errno));
  757. timeout = xfd->para.socket.connect_timeout;
  758. writefd.fd = xfd->fd;
  759. writefd.events = (POLLOUT|POLLERR);
  760. result = xiopoll(&writefd, 1, &timeout);
  761. if (result < 0) {
  762. Msg4(level, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec"."F_tv_usec"): %s",
  763. xfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
  764. return STAT_RETRYLATER;
  765. }
  766. if (result == 0) {
  767. Msg2(level, "connecting to %s: %s",
  768. sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  769. strerror(ETIMEDOUT));
  770. return STAT_RETRYLATER;
  771. }
  772. if (writefd.revents & POLLERR) {
  773. #if 0
  774. unsigned char dummy[1];
  775. Read(xfd->fd, &dummy, 1); /* get error message */
  776. Msg2(level, "connecting to %s: %s",
  777. sockaddr_info(them, infobuff, sizeof(infobuff)),
  778. strerror(errno));
  779. #else
  780. Connect(xfd->fd, them, themlen); /* get error message */
  781. Msg4(level, "connect(%d, %s, "F_Zd"): %s",
  782. xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  783. themlen, strerror(errno));
  784. #endif
  785. return STAT_RETRYLATER;
  786. }
  787. /* otherwise OK */
  788. Fcntl_l(xfd->fd, F_SETFL, fcntl_flags);
  789. } else {
  790. Warn4("connect(%d, %s, "F_Zd"): %s",
  791. xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  792. themlen, strerror(errno));
  793. }
  794. } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
  795. /* this is for UNIX domain sockets: a connect attempt seems to be
  796. the only way to distinguish stream and datagram sockets */
  797. int _errno = errno;
  798. Info4("connect(%d, %s, "F_Zd"): %s",
  799. xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  800. themlen, strerror(errno));
  801. #if 0
  802. Info("assuming datagram socket");
  803. xfd->dtype = DATA_RECVFROM;
  804. xfd->salen = themlen;
  805. memcpy(&xfd->peersa.soa, them, xfd->salen);
  806. #endif
  807. /*!!! and remove bind socket */
  808. Close(xfd->fd); xfd->fd = -1;
  809. errno = _errno;
  810. return -1;
  811. } else {
  812. Msg4(level, "connect(%d, %s, "F_Zd"): %s",
  813. xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
  814. themlen, strerror(errno));
  815. Close(xfd->fd);
  816. return STAT_RETRYLATER;
  817. }
  818. } else { /* result >= 0 */
  819. Notice1("successfully connected from local address %s",
  820. sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
  821. }
  822. applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */
  823. applyopts(xfd->fd, opts, PH_CONNECTED);
  824. applyopts(xfd->fd, opts, PH_LATE);
  825. return STAT_OK;
  826. }
  827. /* a subroutine that is common to all socket addresses that want to connect
  828. to a peer address.
  829. might fork.
  830. applies and consumes the following option:
  831. PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
  832. PH_CONNECTED, PH_LATE,
  833. OFUNC_OFFSET,
  834. OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
  835. returns 0 on success.
  836. */
  837. int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
  838. struct sockaddr *them, size_t themlen,
  839. struct opt *opts, int pf, int socktype, int protocol,
  840. bool alt) {
  841. bool dofork = false;
  842. struct opt *opts0;
  843. char infobuff[256];
  844. int level;
  845. int result;
  846. retropt_bool(opts, OPT_FORK, &dofork);
  847. opts0 = copyopts(opts, GROUP_ALL);
  848. Notice1("opening connection to %s",
  849. sockaddr_info(them, themlen, infobuff, sizeof(infobuff)));
  850. do { /* loop over retries and forks */
  851. #if WITH_RETRY
  852. if (xfd->forever || xfd->retry) {
  853. level = E_INFO;
  854. } else
  855. #endif /* WITH_RETRY */
  856. level = E_ERROR;
  857. result =
  858. _xioopen_connect(xfd, us, uslen, them, themlen, opts,
  859. pf, socktype, protocol, alt, level);
  860. switch (result) {
  861. case STAT_OK: break;
  862. #if WITH_RETRY
  863. case STAT_RETRYLATER:
  864. if (xfd->forever || xfd->retry) {
  865. --xfd->retry;
  866. if (result == STAT_RETRYLATER) {
  867. Nanosleep(&xfd->intervall, NULL);
  868. }
  869. dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
  870. continue;
  871. }
  872. return STAT_NORETRY;
  873. #endif /* WITH_RETRY */
  874. default:
  875. return result;
  876. }
  877. if (dofork) {
  878. xiosetchilddied(); /* set SIGCHLD handler */
  879. }
  880. #if WITH_RETRY
  881. if (dofork) {
  882. pid_t pid;
  883. int level = E_ERROR;
  884. if (xfd->forever || xfd->retry) {
  885. level = E_WARN; /* most users won't expect a problem here,
  886. so Notice is too weak */
  887. }
  888. while ((pid = xio_fork(false, level)) < 0) {
  889. --xfd->retry;
  890. if (xfd->forever || xfd->retry) {
  891. dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
  892. Nanosleep(&xfd->intervall, NULL); continue;
  893. }
  894. return STAT_RETRYLATER;
  895. }
  896. if (pid == 0) { /* child process */
  897. break;
  898. }
  899. /* parent process */
  900. Close(xfd->fd);
  901. /* with and without retry */
  902. Nanosleep(&xfd->intervall, NULL);
  903. dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
  904. continue; /* with next socket() bind() connect() */
  905. } else
  906. #endif /* WITH_RETRY */
  907. {
  908. break;
  909. }
  910. #if 0
  911. if ((result = _xio_openlate(fd, opts)) < 0)
  912. return result;
  913. #endif
  914. } while (true);
  915. return 0;
  916. }
  917. /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip
  918. applies and consumes the following option:
  919. PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
  920. OFUNC_OFFSET
  921. OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
  922. */
  923. int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
  924. union sockaddr_union *us, socklen_t uslen,
  925. struct opt *opts,
  926. int xioflags, xiosingle_t *xfd, unsigned groups,
  927. int pf, int socktype, int ipproto) {
  928. int level = E_ERROR;
  929. union sockaddr_union la; socklen_t lalen = sizeof(la);
  930. char infobuff[256];
  931. if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
  932. return STAT_RETRYLATER;
  933. }
  934. applyopts_offset(xfd, opts);
  935. applyopts_single(xfd, opts, PH_PASTSOCKET);
  936. applyopts(xfd->fd, opts, PH_PASTSOCKET);
  937. applyopts(xfd->fd, opts, PH_FD);
  938. applyopts_cloexec(xfd->fd, opts);
  939. applyopts(xfd->fd, opts, PH_PREBIND);
  940. applyopts(xfd->fd, opts, PH_BIND);
  941. if (us) {
  942. if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
  943. Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
  944. xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
  945. uslen, strerror(errno));
  946. Close(xfd->fd);
  947. return STAT_RETRYLATER;
  948. }
  949. }
  950. applyopts(xfd->fd, opts, PH_PASTBIND);
  951. /*applyopts(xfd->fd, opts, PH_CONNECT);*/
  952. if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
  953. Warn4("getsockname(%d, %p, {%d}): %s",
  954. xfd->fd, &la.soa, lalen, strerror(errno));
  955. }
  956. applyopts_fchown(xfd->fd, opts);
  957. applyopts(xfd->fd, opts, PH_CONNECTED);
  958. applyopts(xfd->fd, opts, PH_LATE);
  959. /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
  960. Notice1("successfully prepared local socket %s",
  961. sockaddr_info(&la.soa, lalen, infobuff, sizeof(infobuff)));
  962. return STAT_OK;
  963. }
  964. /* when the recvfrom address (with option fork) receives a packet it keeps this
  965. packet in the IP stacks input queue and forks a sub process. The sub process
  966. then reads this packet for processing its data.
  967. There is a problem because the parent process would find the same packet
  968. again if it calls select()/poll() before the child process reads the
  969. packet.
  970. To solve this problem we implement the following mechanism:
  971. The sub process sends a SIGUSR1 when it has read the packet (or a SIGCHLD if
  972. it dies before). The parent process waits until it receives that signal and
  973. only then continues to listen.
  974. To prevent a signal from another process to trigger our loop, we pass the
  975. pid of the sub process to the signal handler in xio_waitingfor. The signal
  976. handler sets xio_hashappened if the pid matched.
  977. */
  978. static pid_t xio_waitingfor; /* info from recv loop to signal handler:
  979. indicates the pid that of the child process
  980. that should send us the USR1 signal */
  981. static bool xio_hashappened; /* info from signal handler to loop: child
  982. process has read ("consumed") the packet */
  983. /* this is the signal handler for USR1 and CHLD */
  984. void xiosigaction_hasread(int signum
  985. #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
  986. , siginfo_t *siginfo, void *ucontext
  987. #endif
  988. ) {
  989. pid_t pid;
  990. int _errno;
  991. int status = 0;
  992. bool wassig = false;
  993. #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
  994. Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )",
  995. signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code,
  996. siginfo->si_pid);
  997. #else
  998. Debug1("xiosigaction_hasread(%d)", signum);
  999. #endif
  1000. if (signum == SIGCHLD) {
  1001. _errno = errno;
  1002. do {
  1003. pid = Waitpid(-1, &status, WNOHANG);
  1004. if (pid == 0) {
  1005. Msg(wassig?E_INFO:E_WARN,
  1006. "waitpid(-1, {}, WNOHANG): no child has exited");
  1007. Info("xiosigaction_hasread() finished");
  1008. errno = _errno;
  1009. Debug("xiosigaction_hasread() ->");
  1010. return;
  1011. } else if (pid < 0 && errno == ECHILD) {
  1012. Msg1(wassig?E_INFO:E_WARN,
  1013. "waitpid(-1, {}, WNOHANG): %s", strerror(errno));
  1014. Info("xiosigaction_hasread() finished");
  1015. errno = _errno;
  1016. Debug("xiosigaction_hasread() ->");
  1017. return;
  1018. }
  1019. wassig = true;
  1020. if (pid < 0) {
  1021. Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno));
  1022. Info("xiosigaction_hasread() finished");
  1023. errno = _errno;
  1024. Debug("xiosigaction_hasread() ->");
  1025. return;
  1026. }
  1027. if (pid == xio_waitingfor) {
  1028. xio_hashappened = true;
  1029. Debug("xiosigaction_hasread() ->");
  1030. return;
  1031. }
  1032. } while (1);
  1033. }
  1034. #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
  1035. if (xio_waitingfor == siginfo->si_pid) {
  1036. xio_hashappened = true;
  1037. }
  1038. #else
  1039. xio_hashappened = true;
  1040. #endif
  1041. Debug("xiosigaction_hasread() ->");
  1042. return;
  1043. }
  1044. /* waits for incoming packet, checks its source address and port. Depending
  1045. on fork option, it may fork a subprocess.
  1046. Returns STAT_OK if a the packet was accepted; with fork option, this is already in
  1047. a new subprocess!
  1048. Other return values indicate a problem; this can happen in the master
  1049. process or in a subprocess.
  1050. This function does not retry. If you need retries, handle this is a
  1051. loop in the calling function.
  1052. after fork, we set the forever/retry of the child process to 0
  1053. applies and consumes the following options:
  1054. PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
  1055. PH_CONNECTED, PH_LATE, PH_LATE2
  1056. OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
  1057. */
  1058. int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
  1059. struct sockaddr *us, socklen_t uslen,
  1060. struct opt *opts,
  1061. int pf, int socktype, int proto, int level) {
  1062. char *rangename;
  1063. bool dofork = false;
  1064. pid_t pid; /* mostly int; only used with fork */
  1065. char infobuff[256];
  1066. char lisname[256];
  1067. bool drop = false; /* true if current packet must be dropped */
  1068. int result;
  1069. retropt_bool(opts, OPT_FORK, &dofork);
  1070. if (dofork) {
  1071. if (!(xioflags & XIO_MAYFORK)) {
  1072. Error("option fork not allowed here");
  1073. return STAT_NORETRY;
  1074. }
  1075. xfd->flags |= XIO_DOESFORK;
  1076. }
  1077. if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
  1078. if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) {
  1079. return STAT_RETRYLATER;
  1080. }
  1081. applyopts_single(xfd, opts, PH_PASTSOCKET);
  1082. applyopts(xfd->fd, opts, PH_PASTSOCKET);
  1083. applyopts_cloexec(xfd->fd, opts);
  1084. applyopts(xfd->fd, opts, PH_PREBIND);
  1085. applyopts(xfd->fd, opts, PH_BIND);
  1086. if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
  1087. Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
  1088. sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
  1089. strerror(errno));
  1090. Close(xfd->fd);
  1091. return STAT_RETRYLATER;
  1092. }
  1093. #if WITH_UNIX
  1094. if (pf == AF_UNIX && us != NULL) {
  1095. applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
  1096. }
  1097. #endif
  1098. applyopts(xfd->fd, opts, PH_PASTBIND);
  1099. #if WITH_UNIX
  1100. if (pf == AF_UNIX && us != NULL) {
  1101. /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
  1102. applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
  1103. applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
  1104. }
  1105. #endif /* WITH_UNIX */
  1106. /* for generic sockets, this has already been retrieved */
  1107. if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
  1108. if (xioparserange(rangename, pf, &xfd->para.socket.range)
  1109. < 0) {
  1110. free(rangename);
  1111. return STAT_NORETRY;
  1112. }
  1113. free(rangename);
  1114. xfd->para.socket.dorange = true;
  1115. }
  1116. #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
  1117. xio_retropt_tcpwrap(xfd, opts);
  1118. #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
  1119. if (xioopts.logopt == 'm') {
  1120. Info("starting recvfrom loop, switching to syslog");
  1121. diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';
  1122. } else {
  1123. Info("starting recvfrom loop");
  1124. }
  1125. if (dofork) {
  1126. #if HAVE_SIGACTION
  1127. {
  1128. struct sigaction act;
  1129. memset(&act, 0, sizeof(struct sigaction));
  1130. act.sa_flags = SA_NOCLDSTOP|SA_RESTART
  1131. #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
  1132. |SA_SIGINFO
  1133. #endif
  1134. #ifdef SA_NOMASK
  1135. |SA_NOMASK
  1136. #endif
  1137. ;
  1138. #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
  1139. act.sa_sigaction = xiosigaction_hasread;
  1140. #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
  1141. act.sa_handler = xiosigaction_hasread;
  1142. #endif
  1143. if (Sigaction(SIGUSR1, &act, NULL) < 0) {
  1144. /*! Linux man does not explicitely say that errno is defined */
  1145. Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
  1146. }
  1147. if (Sigaction(SIGCHLD, &act, NULL) < 0) {
  1148. /*! Linux man does not explicitely say that errno is defined */
  1149. Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
  1150. }
  1151. }
  1152. #else /* !HAVE_SIGACTION */
  1153. /*!!!*/
  1154. if (Signal(SIGUSR1, xiosigaction_hasread) == SIG_ERR) {
  1155. Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno));
  1156. }
  1157. if (Signal(SIGCHLD, xiosigaction_hasread) == SIG_ERR) {
  1158. Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno));
  1159. }
  1160. #endif /* !HAVE_SIGACTION */
  1161. }
  1162. while (true) { /* but we only loop if fork option is set */
  1163. char peername[256];
  1164. union sockaddr_union _peername;
  1165. union sockaddr_union _sockname;
  1166. union sockaddr_union *pa = &_peername; /* peer address */
  1167. union sockaddr_union *la = &_sockname; /* local address */
  1168. socklen_t palen = sizeof(_peername); /* peer address size */
  1169. char ctrlbuff[1024]; /* ancillary messages */
  1170. struct msghdr msgh = {0};
  1171. socket_init(pf, pa);
  1172. if (drop) {
  1173. char *dummy[2];
  1174. Recv(xfd->fd, dummy, sizeof(dummy), 0);
  1175. drop = true;
  1176. }
  1177. /* loop until select()/poll() returns valid */
  1178. do {
  1179. struct pollfd readfd;
  1180. /*? int level = E_ERROR;*/
  1181. if (us != NULL) {
  1182. Notice1("receiving on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
  1183. } else {
  1184. Notice1("receiving IP protocol %u", proto);
  1185. }
  1186. readfd.fd = xfd->fd;
  1187. readfd.events = POLLIN;
  1188. if (xiopoll(&readfd, 1, NULL) > 0) {
  1189. break;
  1190. }
  1191. if (errno == EINTR) {
  1192. continue;
  1193. }
  1194. Msg2(level, "poll({%d,,},,-1): %s", xfd->fd, strerror(errno));
  1195. Close(xfd->fd);
  1196. return STAT_RETRYLATER;
  1197. } while (true);
  1198. msgh.msg_name = pa;
  1199. msgh.msg_namelen = palen;
  1200. #if HAVE_STRUCT_MSGHDR_MSGCONTROL
  1201. msgh.msg_control = ctrlbuff;
  1202. #endif
  1203. #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
  1204. msgh.msg_controllen = sizeof(ctrlbuff);
  1205. #endif
  1206. if (xiogetpacketsrc(xfd->fd, &msgh) < 0) {
  1207. return STAT_RETRYLATER;
  1208. }
  1209. palen = msgh.msg_namelen;
  1210. Notice1("receiving packet from %s"/*"src"*/,
  1211. sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*,
  1212. sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
  1213. xiodopacketinfo(&msgh, true, true);
  1214. if (xiocheckpeer(xfd, pa, la) < 0) {
  1215. /* drop packet */
  1216. char buff[512];
  1217. Recv(xfd->fd, buff, sizeof(buff), 0);
  1218. continue;
  1219. }
  1220. Info1("permitting packet from %s",
  1221. sockaddr_info((struct sockaddr *)pa, palen,
  1222. infobuff, sizeof(infobuff)));
  1223. /* set the env vars describing the local and remote sockets */
  1224. /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
  1225. xiosetsockaddrenv("PEER", pa, palen, proto);
  1226. applyopts(xfd->fd, opts, PH_FD);
  1227. applyopts(xfd->fd, opts, PH_CONNECTED);
  1228. xfd->peersa = *(union sockaddr_union *)pa;
  1229. xfd->salen = palen;
  1230. if (dofork) {
  1231. sigset_t mask_sigchldusr1;
  1232. /* we must prevent that the current packet triggers another fork;
  1233. therefore we wait for a signal from the recent child: USR1
  1234. indicates that is has consumed the last packet; CHLD means it has
  1235. terminated */
  1236. /* block SIGCHLD and SIGUSR1 until parent is ready to react */
  1237. sigemptyset(&mask_sigchldusr1);
  1238. sigaddset(&mask_sigchldusr1, SIGCHLD);
  1239. sigaddset(&mask_sigchldusr1, SIGUSR1);
  1240. Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL);
  1241. if ((pid = xio_fork(false, level)) < 0) {
  1242. Close(xfd->fd);
  1243. Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
  1244. return STAT_RETRYLATER;
  1245. }
  1246. if (pid == 0) { /* child */
  1247. /* no reason to block SIGCHLD in child process */
  1248. Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
  1249. xfd->ppid = Getppid(); /* send parent a signal when packet has
  1250. been consumed */
  1251. #if WITH_RETRY
  1252. /* !? */
  1253. xfd->retry = 0;
  1254. xfd->forever = 0;
  1255. level = E_ERROR;
  1256. #endif /* WITH_RETRY */
  1257. #if WITH_UNIX
  1258. /* with UNIX sockets: only listening parent is allowed to remove
  1259. the socket file */
  1260. xfd->opt_unlink_close = false;
  1261. #endif /* WITH_UNIX */
  1262. break;
  1263. }
  1264. /* server: continue loop with listen */
  1265. xio_waitingfor = pid;
  1266. /* now we are ready to handle signals */
  1267. Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
  1268. while (!xio_hash

Large files files are truncated, but you can click here to view the full file