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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.