mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-09 02:29:07 +08:00
159 lines
4.5 KiB
C
159 lines
4.5 KiB
C
/*************************************************************************\
|
|
* Copyright (C) Michael Kerrisk, 2018. *
|
|
* *
|
|
* This program is free software. You may use, modify, and redistribute it *
|
|
* under the terms of the GNU General Public License as published by the *
|
|
* Free Software Foundation, either version 3 or (at your option) any *
|
|
* later version. This program is distributed without any warranty. See *
|
|
* the file COPYING.gpl-v3 for details. *
|
|
\*************************************************************************/
|
|
|
|
/* is_seqnum_v3_sv.c (KB)
|
|
|
|
A simple Internet stream socket server. Our service is to provide unique
|
|
sequence numbers to the client.
|
|
|
|
This program is the same as is_seqnum_v2.c, except that it forks a
|
|
subprocess to do the work, and it sends the connection fd to the
|
|
child over an AF_UNIX socket. Invoke it with --debug to allow time
|
|
to attach gdb to the child. (KB)
|
|
|
|
Usage: is_seqnum_sv [init-seq-num] (default = 0)
|
|
|
|
See also is_seqnum_v2_cl.c.
|
|
*/
|
|
#include "af_unix_hdr.h"
|
|
#include "is_seqnum_v2.h"
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
uint32_t seqNum;
|
|
char reqLenStr[INT_LEN]; /* Length of requested sequence */
|
|
char seqNumStr[INT_LEN]; /* Start of granted sequence */
|
|
struct sockaddr *claddr;
|
|
int lfd, reqLen;
|
|
socklen_t addrlen, alen;
|
|
char addrStr[IS_ADDR_STR_LEN];
|
|
Boolean debug = FALSE;
|
|
pid_t pid;
|
|
int pipefd[2];
|
|
int pfd; /* parent's end */
|
|
int cfd; /* child's end */
|
|
|
|
if (argc > 1 && strcmp (argv[1], "--help") == 0)
|
|
usageErr ("%s [--debug] [init-seq-num]\n", argv[0]);
|
|
if (argc > 1 && strcmp (argv[1], "--debug") == 0)
|
|
debug = TRUE;
|
|
|
|
if (!debug)
|
|
seqNum = (argc > 1) ? getInt (argv[1], 0, "init-seq-num") : 0;
|
|
else
|
|
seqNum = (argc > 2) ? getInt (argv[2], 0, "init-seq-num") : 0;
|
|
|
|
/* Ignore the SIGPIPE signal, so that we find out about broken connection
|
|
errors via a failure from write(). */
|
|
|
|
if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
|
|
errExit("signal");
|
|
|
|
lfd = inetListen (PORT_NUM_STR, 5, &addrlen);
|
|
if (lfd == -1)
|
|
fatal ("inetListen() failed");
|
|
|
|
/* Allocate a buffer large enough to hold the client's socket address */
|
|
|
|
claddr = malloc (addrlen);
|
|
if (claddr == NULL)
|
|
errExit ("malloc");
|
|
|
|
/* Fork a child to handle client request. */
|
|
|
|
if (socketpair (AF_UNIX, SOCK_STREAM, 0, pipefd) < 0)
|
|
errExit ("socketpair");
|
|
pfd = pipefd[1];
|
|
cfd = pipefd[0];
|
|
|
|
if ((pid = fork ()) < 0)
|
|
errExit ("fork");
|
|
else if (pid > 0) /* parent */
|
|
{
|
|
int connfd, junk;
|
|
|
|
if (close (cfd) < 0)
|
|
errExit ("close");
|
|
if (debug)
|
|
{
|
|
printf ("parent pid %d, child pid %d, sleeping...\n", getpid (), pid);
|
|
sleep (30);
|
|
}
|
|
|
|
/* Accept a client connection, obtaining client's address */
|
|
|
|
alen = addrlen;
|
|
connfd = accept (lfd, (struct sockaddr *) claddr, &alen);
|
|
if (connfd == -1)
|
|
errExit ("accept");
|
|
printf ("Connection from %s\n", inetAddressStr (claddr, alen, addrStr,
|
|
IS_ADDR_STR_LEN));
|
|
printf ("Sending fd %d to child\n", connfd);
|
|
if (sendfd (pfd, connfd) < 0)
|
|
errExit ("sendfd");
|
|
if (close (connfd) < 0)
|
|
errExit ("close");
|
|
/* Wait for child. */
|
|
if (read (pfd, &junk, sizeof junk) != sizeof junk)
|
|
errMsg ("read");
|
|
if (close (pfd) < 0)
|
|
errMsg ("close");
|
|
if (close (lfd) < 0)
|
|
errExit ("close");
|
|
}
|
|
else /* child */
|
|
{
|
|
int connfd, junk;
|
|
|
|
if (close (pfd) < 0)
|
|
errExit ("close");
|
|
if (close (lfd) < 0)
|
|
errExit ("close");
|
|
if (debug)
|
|
sleep (30);
|
|
|
|
/* Get connection fd from parent. */
|
|
|
|
connfd = recvfd (cfd);
|
|
if (connfd < 0)
|
|
errExit ("recvfd");
|
|
|
|
/* Read client request, send sequence number back */
|
|
|
|
if (readLine (connfd, reqLenStr, INT_LEN) <= 0)
|
|
{
|
|
close (connfd);
|
|
errExit ("readLine");
|
|
}
|
|
|
|
reqLen = atoi (reqLenStr);
|
|
if (reqLen <= 0)
|
|
{
|
|
close(cfd);
|
|
errExit ("Bad request");
|
|
}
|
|
|
|
snprintf (seqNumStr, INT_LEN, "%d\n", seqNum);
|
|
if (write (connfd, seqNumStr, strlen (seqNumStr)) != strlen(seqNumStr))
|
|
errExit ("write");
|
|
|
|
seqNum += reqLen; /* Update sequence number */
|
|
|
|
if (close (connfd) == -1) /* Close connection */
|
|
errMsg ("close");
|
|
/* Tell parent we're done. */
|
|
if (write (cfd, &junk, sizeof junk) != sizeof junk)
|
|
errMsg ("write");
|
|
if (close (cfd) < 0)
|
|
errExit ("close");
|
|
}
|
|
}
|