{
struct addrinfo aihint = { 0 }, *ai0, *ai1;
int len = PKBUFSZ, yes = 1;
+ const char *outf, *serv;
+ FILE *fp;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ socklen_t salen;
int err;
peer *p;
- int fd;
+ int fd, port;
if (ac != 4) die(1, "syntax: %s:NAME:PORT:ADDR:PORT", cmd);
if (!key_bytag(&keys, av[0])) die(1, "no key named `%s'", av[0]);
aihint.ai_flags = AI_ADDRCONFIG;
if ((err = getaddrinfo(av[2], av[3], &aihint, &ai1)) != 0)
die(1, "getaddrinfo(`%s', `%s'): %s", av[2], av[3], gai_strerror(err));
+ if (*av[1] == '?') { serv = "0"; outf = av[1] + 1; }
+ else { serv = av[1]; outf = 0; }
aihint.ai_family = ai1->ai_family;
aihint.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
- if ((err = getaddrinfo(0, av[1], &aihint, &ai0)) != 0)
+ if ((err = getaddrinfo(0, serv, &aihint, &ai0)) != 0)
die(1, "getaddrinfo(passive, `%s'): %s", av[1], gai_strerror(err));
if ((fd = socket(ai1->ai_family, SOCK_DGRAM, ai1->ai_protocol)) < 0)
die(1, "socket: %s", strerror(errno));
die(1, "setsockopt: %s", strerror(errno));
if (connect(fd, ai1->ai_addr, ai1->ai_addrlen))
die(1, "connect: %s", strerror(errno));
+ if (outf) {
+ salen = sizeof(addr);
+ if (getsockname(fd, &addr.sa, &salen))
+ die(1, "getsockname: %s", strerror(errno));
+ switch (addr.sa.sa_family) {
+ case AF_INET: port = ntohs(addr.sin.sin_port); break;
+ case AF_INET6: port = ntohs(addr.sin6.sin6_port); break;
+ default: assert(0);
+ }
+ fp = fopen(outf, "w");
+ if (!fp) die(1, "fopen(%s): %s", outf, strerror(errno));
+ fprintf(fp, "%d\n", port);
+ fclose(fp);
+ }
sel_initfile(&sel, &p->sf, fd, SEL_READ, dopacket, p);
sel_addfile(&p->sf);
freeaddrinfo(ai0); freeaddrinfo(ai1);