📄 lwld.c
字号:
else if (bcmp(p + 8, "SFms", 4) == 0) {
#ifdef HEXDUMP
if (hexdump) {
fprintf(stderr, "%s: %d bytes sent to socket.\n",
prog, messagel);
xd(stderr, message, messagel, TRUE);
}
#endif
if (prolix) {
printf("%s: %s server message request\n", prog, inet_ntoa(from.sin_addr));
}
if (send(csock, message, messagel, 0) < 0) {
perror("sending server message");
}
}
break;
default:
if (debugging || verbose) {
fprintf(stderr, "Bogus payload type %d\n",
#ifdef RationalWorld
rp->common.pt
#else
((unsigned char *) rp)[1]
#endif
);
}
break;
}
}
close(csock);
}
#ifdef THREADS
/* Thread processing functions. */
#ifdef DBTHREAD
/* EDIT_THREAD -- Edit information about a service thread from
its packet in the ballOstring chain. */
static char *edit_thread(b)
struct ballOstring *b;
{
static char s[80];
sprintf(s, "%d %s %s", b->thread, inet_ntoa(b->site), ctime(&b->startTime));
s[strlen(s) - 1] = 0;
return s;
}
#endif
/* TIMEOUT_THREAD -- Handle timeout of sites that go away without
sending a "Bye" message. */
static void *timeout_thread(arg)
void *arg;
{
long ct;
struct ballOstring *b;
#ifdef DBTHREAD
fprintf(stderr, "Timeout thread running\n");
#endif
while (TRUE) {
sleep(120); /* Wait for next awake interval */
time(&ct);
#ifdef DBTHREAD
fprintf(stderr, "Timeout thread scanning connections\n");
#endif
Lock(bsLock);
b = bshead.next;
while (b != &bshead) {
#ifdef DBTHREAD
fprintf(stderr, " Thread %s\n", edit_thread(b));
#endif
if ((b->startTime + ServiceThreadTimeout) < ct) {
#ifdef DBTHREAD
fprintf(stderr, " Kill sent due to timeout.\n");
#endif
pthread_kill(b->thread, SIGUSR1);
}
b = b->next;
}
Unlock(bsLock);
release();
}
}
/* HTML_THREAD -- Update the HTML database(s) if something has
changed since the last time. */
static void *html_thread(arg)
void *arg;
{
#ifdef DBTHREAD
fprintf(stderr, "HTML update thread running\n");
#endif
while (TRUE) {
#ifdef DBTHREAD
fprintf(stderr, "HTML update thread examining connections\n");
#endif
updHTML();
/* In the threaded version, consider every 15 seconds as
equivalent to "immediate update on every change".
We could accomplish immediate update with a
semaphore signalling mechanism, but that would
cause the threaded and non-threaded versions to
diverge much more. Besides, nobody runs in immediate
update mode anyway, as far as I can determine. */
sleep((unsigned int) (htmlTime <= 0 ? 15 : htmlTime));
}
}
/* SERVICE_THREAD -- Thread to process user packet. One of
these is created every time a connection is
accepted. */
struct service_arg {
int sa_csock;
struct sockaddr_in sa_from;
struct ballOstring *sa_b;
};
static void killserv()
{
pthread_t us = pthread_self();
struct ballOstring *b;
#ifdef DBTHREAD
fprintf(stderr, "Gaaaak!!! Killserv received by thread %d.\n", us);
#endif
/* We're being killed by the timeout handler. Search for
our entry in the ballOstring chain. */
Lock(bsLock);
b = bshead.next;
while (b != &bshead) {
if (b->thread == us) {
/* Dechain from active thread list. */
b->prev->next = b->next;
b->next->prev = b->prev;
break;
}
b = b->next;
}
Unlock(bsLock);
if (b != &bshead) {
if (b->sa->sa_csock != -1) {
close(b->sa->sa_csock);
}
#ifdef DBTHREAD
fprintf(stderr, "Thread killed by timeout: %s\n", edit_thread(b));
#endif
free(b->sa);
free(b);
pthread_exit(NULL);
} else {
#ifdef DBTHREAD
fprintf(stderr, "Oops!!! Timeout kill request to thread %d, not in ballOstring.\n", us);
#endif
}
}
static void *service_thread(arg)
void *arg;
{
struct service_arg *sa = arg;
#ifdef DBTHREAD
fprintf(stderr, "Server thread %d for host %s launched\n", pthread_self(), inet_ntoa(sa->sa_from.sin_addr));
#endif
signal(SIGUSR1, killserv); /* Set signal to handle timeout */
sa->sa_b->thread = pthread_self();
servicePacket(sa->sa_csock, sa->sa_from);
#ifdef DBTHREAD
fprintf(stderr, "Server thread %d for host %s exiting\n", pthread_self(), inet_ntoa(sa->sa_from.sin_addr));
#endif
/* Dechain this thread's item from the ballOstring list. */
#ifdef DBTHREAD
fprintf(stderr, "Thread exiting: %s\n", edit_thread(sa->sa_b));
#endif
Lock(bsLock);
sa->sa_b->prev->next = sa->sa_b->next;
sa->sa_b->next->prev = sa->sa_b->prev;
free(sa->sa_b);
Unlock(bsLock);
free(sa); /* Release request packet */
pthread_exit(NULL);
}
#endif
/* Main program. */
main(argc, argv)
int argc;
char *argv[];
{
int i, length;
struct sockaddr_in name;
#ifdef THREADS
pthread_t timeout_tid, html_tid;
pthread_attr_init(&detached);
pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&detached, (size_t) 65536);
bshead.next = bshead.prev = &bshead;
#endif
/* Process command line options. */
prog = prog_name(argv[0]);
#ifdef PRUNEFACE
{ /* Interctive debugging of text pruning logic. */
char s[132], p[132];
char *zap;
while (TRUE) {
printf("--> ");
if (fgets(s, sizeof s, stdin) == NULL) {
break;
}
zap = p;
add_sdes_item(1, s, &zap);
*zap = 0;
printf( "\"%s\"\n", p + 2);
}
exit(0);
}
#endif
for (i = 1; i < argc; i++) {
char *op, opt;
op = argv[i];
if (*op == '-') {
opt = *(++op);
if (islower(opt)) {
opt = toupper(opt);
}
switch (opt) {
case 'D': /* -D -- Debug output to stderr */
debugging = TRUE;
break;
case 'F': /* -Fserv,... -- Forward to listed servers. */
forwardList(op + 1);
break;
case 'H': /* -Hname -- HTML file name base path */
htmlFile = op + 1;
break;
case 'I': /* -Isec -- Interval between HTML updates */
htmlTime = atoi(op + 1);
break;
case 'M': /* -Mfile -- Load server message from file */
{
FILE *fp = fopen(op + 1, "r");
long fl;
if (fp == NULL) {
fprintf(stderr, "%s: can't open server message file %s\n", prog, op + 1);
return 2;
}
fseek(fp, 0L, 2);
fl = ftell(fp);
rewind(fp);
messagel = ((int) fl) + 13;
message = (char *) malloc(messagel);
if (message != NULL) {
rtcp_t *rp = (rtcp_t *) message;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_APP;
#else
*((short *) rp) = htons((RTP_VERSION << 14) |
RTCP_APP | (1 << 8));
#endif
rp->r.sdes.src = 0;
bcopy("SFmr", message + 8, 4);
fread(message + 12, (int) fl, 1, fp);
message[messagel - 1] = 0;
}
fclose(fp);
}
break;
case 'P': /* -Pport -- Port to listen on */
lwlport = atoi(op + 1);
break;
case 'U': /* -U -- Print usage information */
case '?': /* -? -- Print usage information */
usage();
return 0;
case 'V': /* -V -- Show connects/disconnects */
verbose = TRUE;
if (op[1] == 'v' || op[1] == 'V') {
prolix = TRUE;
}
break;
#ifdef HEXDUMP
case 'X': /* -X -- Dump packets in hex */
hexdump = TRUE;
break;
#endif
case 'Z': /* -Zname -- HTML private file name base path */
htmlPrivateFile = op + 1;
break;
}
} else {
usage();
return 2;
}
}
/* If no server message has been loaded, create a void one. */
if (message == NULL) {
rtcp_t *rp;
messagel = 13;
message = (char *) malloc(messagel);
rp = (rtcp_t *) message;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_APP;
#else
*((short *) rp) = htons((RTP_VERSION << 14) | RTCP_APP | (1 << 8));
#endif
rp->r.sdes.src = 0;
bcopy("SFmr", message + 8, 4);
message[messagel - 1] = 0;
}
/* Create the socket from which to read */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
return 1;
}
/* Create name with wildcards. */
name.sin_family = AF_INET;
name.sin_addr.s_addr = INADDR_ANY;
name.sin_port = htons(lwlport);
if (bind(sock, (struct sockaddr *) &name, sizeof name) < 0) {
perror("binding stream socket");
return 1;
}
signal(SIGHUP, exiting); /* Set signal to handle termination */
signal(SIGINT, exiting); /* Set signal to handle termination */
signal(SIGTERM, exiting); /* Set signal to handle termination */
signal(SIGPIPE, plumber); /* Catch "broken pipe" signals from disconnects */
if (listen(sock, 25) < 0) {
perror("calling listen for socket");
}
/* Find assigned port value and print it. */
length = sizeof(name);
if (getsockname(sock, (struct sockaddr *) &name, &length) < 0) {
perror("getting socket name");
return 1;
}
#ifdef SHOW_SOCKET
fprintf(stderr, "%s: socket port #%d\n", prog, ntohs(name.sin_port));
#endif
#ifdef THREADS
pthread_create(&timeout_tid, &detached, timeout_thread, NULL);
if (htmlFile != NULL || htmlPrivateFile != NULL) {
pthread_create(&html_tid, &detached, html_thread, NULL);
}
#else
signal(SIGALRM, release); /* Set signal to handle timeout */
alarm(TockTock); /* Set alarm clock to purge idle hosts */
#endif
changed(); /* Create initial HTML file */
setlinebuf(stdout); /* Set stdout to line buffering for log */
/* Process requests from the socket. */
while (TRUE) {
int csock;
struct sockaddr_in from; /* Sending host address */
int fromlen; /* Length of sending host address */
#ifdef THREADS
struct service_arg *sap;
pthread_t service_tid;
#endif
errno = 0;
do {
fromlen = sizeof from;
csock = accept(sock, (struct sockaddr *) &from, &fromlen);
#ifdef DBTHREAD
fprintf(stderr, "Accept %d\n", csock);
#endif
if (csock >= 0) {
break;
}
} while (errno == EINTR);
if (csock < 0) {
perror("accepting connection to socket");
continue;
}
if (prolix) {
printf("%s: %s accept\n", prog, inet_ntoa(from.sin_addr));
}
#ifdef THREADS
sap = (struct service_arg *) malloc(sizeof(struct service_arg));
if (sap != NULL) {
struct ballOstring *b;
sap->sa_csock = csock;
sap->sa_from = from;
b = (struct ballOstring *) malloc(sizeof(struct ballOstring));
if (b != NULL) {
sap->sa_b = b;
b->sa = sap;
Lock(bsLock);
b->next = bshead.next;
b->prev = &bshead;
bshead.next = b;
b->next->prev = b;
b->thread = -1;
time(&(b->startTime));
b->site = from.sin_addr;
Unlock(bsLock);
if (pthread_create(&service_tid, &detached, service_thread, sap) != 0) {
fprintf(stderr, "%s: Cannot launch server thread for request from %s: %s",
prog, inet_ntoa(from.sin_addr), strerror(errno));
close(csock);
}
} else {
free(sap);
fprintf(stderr, "Unable to allocate memory for ballOstring packet.\n");
close(csock);
}
} else {
fprintf(stderr, "Unable to allocate memory for service_arg packet.\n");
close(csock);
}
#else
servicePacket(csock, from);
#endif
}
#ifdef MEANS_OF_EXIT
close(sock);
return 0;
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -