From: Greg Minshall <minshall@umich.edu>
To: Alejandro Colomar <alx@kernel.org>
Cc: linux-man@vger.kernel.org
Subject: Re: getaddrinfo_a man page: add notification example?
Date: Sun, 25 Aug 2024 14:29:13 +0300 [thread overview]
Message-ID: <864874.1724585353@archlinux> (raw)
In-Reply-To: <4vdd7x3bdhpomg5epf4huwbdsytvgd2qqgohyavpsjmqgwperv@tx2ytsol5ymv>
Alex,
> Would you mind sending the extracted files? That way I can comment on
> those directly.
here you go.
cheers, Greg
----
#define _GNU_SOURCE
#include <assert.h>
#include <err.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CALLOC(n, type) ((type *) calloc(n, sizeof(type)))
#define REALLOCF(ptr, n, type) \
({ \
static_assert(__builtin_types_compatible_p(typeof(ptr), type *)); \
\
(type *) reallocarrayf(ptr, n, sizeof(type)); \
})
static struct gaicb **reqs = NULL;
static size_t nreqs = 0;
/* default is "no notification" ('n') */
static char notification = 'n';
/* forward declaration for callback routines */
static void list_requests(void);
static inline void *
reallocarrayf(void *p, size_t nmemb, size_t size)
{
void *q;
q = reallocarray(p, nmemb, size);
if (q == NULL && nmemb != 0 && size != 0)
free(p);
return q;
}
static char *
getcmd(void)
{
static char buf[256];
fputs("> ", stdout); fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
return buf;
}
/* Set notification type: none (default), signal, callback */
static void
notification_type(void)
{
char *type = strtok(NULL, " ");
switch (type[0]) {
case 'c':
case 'n':
case 's':
notification = type[0];
break;
default:
fprintf(stderr, "Bad type: '%c' (expecting 'c', 's', or 'n')\n", type[0]);
break;
}
}
/* callback routine for signal notifications */
static void
signal_handler(int signo) {
fprintf(stdout, "notified by signal\n");
list_requests();
fprintf(stdout, "> ");
fflush(stdout);
}
/* callback routine for thread/callback notifications */
static void
callback_handler(union sigval sev_value) {
fprintf(stdout, "notified by callback\n");
list_requests();
fprintf(stdout, "> ");
fflush(stdout);
}
/* Add requests for specified hostnames. */
static void
add_requests(void)
{
static struct sigevent senull; /* static, so initialized to zero */
static struct sigaction sanull; /* static, so intitialized to zero */
struct sigevent se = senull;
struct sigaction sa = sanull;
size_t nreqs_base = nreqs;
char *host;
int ret;
while ((host = strtok(NULL, " "))) {
nreqs++;
reqs = REALLOCF(reqs, nreqs, struct gaicb *);
if (reqs == NULL)
err(EXIT_FAILURE, "reallocf");
reqs[nreqs - 1] = CALLOC(1, struct gaicb);
if (reqs[nreqs - 1] == NULL)
err(EXIT_FAILURE, "calloc");
reqs[nreqs - 1]->ar_name = strdup(host);
}
switch (notification) {
case 'c':
/* notify via a callback */
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = callback_handler;
break;
case 'n':
/* nothing to do */
break;
case 's':
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = SIGUSR1;
sa.sa_handler = signal_handler;
/* set SA_RESTART so read(2) in main doesn't get an EINTR */
sa.sa_flags = SA_RESTART;
ret = sigaction(SIGUSR1, &sa, NULL);
if (ret) {
err(EXIT_FAILURE, "sigaction");
}
break;
default:
fprintf(stderr, "program error: `notification` not one of [cns]: %c\n",
notification);
exit(4);
}
/* Queue nreqs_base..nreqs requests. */
ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
nreqs - nreqs_base, notification == 'n' ? NULL : &se);
if (ret) {
fprintf(stderr, "getaddrinfo_a() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
}
/* Wait until at least one of specified requests completes. */
static void
wait_requests(void)
{
char *id;
int ret;
size_t n;
struct gaicb const **wait_reqs;
wait_reqs = CALLOC(nreqs, const struct gaicb *);
if (wait_reqs == NULL)
err(EXIT_FAILURE, "calloc");
/* NULL elements are ignored by gai_suspend(). */
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >= nreqs) {
printf("Bad request number: %s\n", id);
return;
}
wait_reqs[n] = reqs[n];
}
ret = gai_suspend(wait_reqs, nreqs, NULL);
if (ret) {
printf("gai_suspend(): %s\n", gai_strerror(ret));
return;
}
for (size_t i = 0; i < nreqs; i++) {
if (wait_reqs[i] == NULL)
continue;
ret = gai_error(reqs[i]);
if (ret == EAI_INPROGRESS)
continue;
printf("[%02zu] %s: %s\n", i, reqs[i]->ar_name,
ret == 0 ? "Finished" : gai_strerror(ret));
}
}
/* Cancel specified requests. */
static void
cancel_requests(void)
{
char *id;
int ret;
size_t n;
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >= nreqs) {
printf("Bad request number: %s\n", id);
return;
}
ret = gai_cancel(reqs[n]);
printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
gai_strerror(ret));
}
}
/* List all requests. */
static void
list_requests(void)
{
int ret;
char host[NI_MAXHOST];
struct addrinfo *res;
for (size_t i = 0; i < nreqs; i++) {
printf("[%02zu] %s: ", i, reqs[i]->ar_name);
ret = gai_error(reqs[i]);
if (!ret) {
res = reqs[i]->ar_result;
ret = getnameinfo(res->ai_addr, res->ai_addrlen,
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret) {
fprintf(stderr, "getnameinfo() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
}
}
int
main(void)
{
char *cmdline;
char *cmd;
while ((cmdline = getcmd()) != NULL) {
cmd = strtok(cmdline, " ");
if (cmd == NULL) {
list_requests();
} else {
switch (cmd[0]) {
case 'a':
add_requests();
break;
case 'w':
wait_requests();
break;
case 'c':
cancel_requests();
break;
case 'l':
list_requests();
break;
case 'n':
notification_type();
break;
default:
fprintf(stderr, "Bad command: %c\n", cmd[0]);
break;
}
}
}
exit(EXIT_SUCCESS);
}
next prev parent reply other threads:[~2024-08-25 11:32 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-21 8:50 getaddrinfo_a man page: add notification example? Greg Minshall
2024-08-21 10:36 ` Alejandro Colomar
2024-08-21 13:09 ` Greg Minshall
2024-08-25 10:17 ` Greg Minshall
2024-08-25 10:48 ` Alejandro Colomar
2024-08-25 11:29 ` Greg Minshall [this message]
2024-11-01 13:46 ` Alejandro Colomar
2024-11-01 17:57 ` Greg Minshall
2024-11-01 20:01 ` Alejandro Colomar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=864874.1724585353@archlinux \
--to=minshall@umich.edu \
--cc=alx@kernel.org \
--cc=linux-man@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox