📄 lwld.c
字号:
/*
Speak Freely for Win32
Look Who's Listening Server
This is the Win32 of the LWL daemon.
*/
#include "speakfree.h"
#ifdef THREADS
#include <pthread.h>
#define Lock(x) pthread_mutex_lock(&(x))
#define Unlock(x) pthread_mutex_unlock(&(x))
#define LockConn() Lock(connLock)
#define UnlockConn() Unlock(connLock)
#else
#define LockConn()
#define UnlockConn()
#endif
#define TockTock 120 /* Timeout check frequency, seconds */
#define TimeoutTime 15 * 60 /* No-response timeout interval, seconds */
#define ServiceThreadTimeout 60 /* Service thread timeout interval, seconds */
#define MaxReplyPacket 512 /* Maximum length of reply data */
static int sock; /* Our socket */
static char *prog; /* Program name */
static int lwlport = Internet_Port + 2; /* Look Who's Listening port */
static int debugging = FALSE; /* Debug mode enabled */
static int verbose = FALSE; /* Show connections/disconnects */
static int prolix = FALSE; /* Extremely verbose (show queries) */
#ifdef HEXDUMP
static int hexdump = FALSE; /* Dump received packets in hex ? */
#endif
static char *htmlFile = NULL; /* HTML file name base */
static char *htmlPrivateFile = NULL; /* HTML private directory file name base */
static int htmlTime = 1 * 60; /* HTML file update time */
static time_t htmlLast = 0; /* HTML last update time */
static int htmlChange = TRUE; /* Change since last HTML update ? */
static char *message = NULL; /* Server information message */
static int messagel; /* Length of server information message */
#ifdef THREADS
#define ForwarderSleep 30 /* How often to update forwarded hosts */
#define ForwarderMaxQ 15 /* Maximum items in forward queue */
struct lwl_queueitem {
struct lwl_queueitem *next; /* Next item in LWL queue */
int q_rll; /* Length of message */
char q_pkt[2]; /* Message body */
};
struct forwarder {
struct forwarder *next; /* Next forwarder in chain */
int status; /* Site status (0 = normal) */
char *sitename; /* Site name specification */
struct in_addr site; /* Internet address of target host */
long port; /* Destination port on that host */
pthread_t thread; /* ID of forwarder thread */
int queuelen; /* Length of queue for forwarder */
struct lwl_queueitem *head, *tail;/* Queue of messages to be forwarded */
};
static pthread_attr_t detached; /* Attributes for our detached threads */
static pthread_mutex_t fwdlistLock = PTHREAD_MUTEX_INITIALIZER;
static struct forwarder *fwdlist = NULL; /* List of forwarding destinations */
#define lwl_nsites 1 /* Threaded version driven from list */
struct ballOstring {
struct ballOstring *next, *prev; /* Forward and back queue links */
pthread_t thread; /* Service thread ID */
time_t startTime; /* When did thread start ? */
struct in_addr site; /* Internet address of requesting site */
struct service_arg *sa; /* Service thread argument */
};
static struct ballOstring bshead; /* Ball of string queue head */
static pthread_mutex_t bsLock = PTHREAD_MUTEX_INITIALIZER;
#else
static struct sockaddr_in lookhost; /* Look who's listening host, if any */
static struct in_addr lwl_sites[LWL_MAX_SITES]; /* LWL site addresses */
static long lwl_ports[LWL_MAX_SITES]; /* Ports for LWL hosts */
static int lwl_nsites = 0; /* Number of LWL sites published on */
#endif
struct lwl {
struct lwl *next; /* Next connection */
time_t ltime; /* Time of last update */
unsigned long ssrc; /* Session source descriptor */
long naddr; /* Internet address */
short port; /* Port address */
char *cname; /* Canonical name */
char *name; /* User name */
char *email; /* Electronic mail address */
char *phone; /* Telephone number */
char *loc; /* Geographic location */
char *tool; /* Application name */
};
#ifdef THREADS
/* Connection chain critical section */
static pthread_mutex_t connLock = PTHREAD_MUTEX_INITIALIZER;
#endif
static struct lwl *conn = NULL; /* Chain of current connections */
/* ETIME -- Edit time and date for log messages. */
static char *etime(gmt)
int gmt;
{
struct tm *t;
time_t clock;
static char s[20];
time(&clock);
if (gmt) {
t = gmtime(&clock);
} else {
t = localtime(&clock);
}
sprintf(s, "%02d-%02d %02d:%02d", t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min);
return s;
}
/* ESTIME -- Edit short time. */
static char *estime()
{
struct tm *t;
time_t clock;
static char s[20];
time(&clock);
t = localtime(&clock);
sprintf(s, "%02d:%02d", t->tm_hour, t->tm_min);
return s;
}
/* DUPSDESITEM -- Make a copy of an SDES item and advance the pointer
past it. */
static char *dupSdesItem(cp)
char **cp;
{
char *ip = *cp, *bp;
int l = ip[1] & 0xFF;
bp = malloc(l + 1);
if (bp != NULL) {
bcopy(ip + 2, bp, l);
bp[l] = 0;
}
*cp = ip + l + 2;
return bp;
}
/* DESTROYLWL -- Release storage associated with an LWL list item. */
static void destroyLwl(lw)
struct lwl *lw;
{
if (lw->cname != NULL) {
free(lw->cname);
}
if (lw->name != NULL) {
free(lw->name);
}
if (lw->email != NULL) {
free(lw->email);
}
if (lw->phone != NULL) {
free(lw->phone);
}
if (lw->loc != NULL) {
free(lw->loc);
}
if (lw->tool != NULL) {
free(lw->tool);
}
free(lw);
}
/* DUMPLWL -- Dump an LWL on the specified stream. */
static void dumpLwl(fo, lw)
FILE *fo;
struct lwl *lw;
{
struct sockaddr_in s;
s.sin_addr.s_addr = lw->naddr;
fprintf(fo, "SSRC = %X IP = %s Port %d %s", lw->ssrc, inet_ntoa(s.sin_addr),
lw->port, ctime(&(lw->ltime)));
if (lw->cname != NULL) {
fprintf(fo, " CNAME = %s\n", lw->cname);
}
if (lw->name != NULL) {
fprintf(fo, " NAME = %s\n", lw->name);
}
if (lw->email != NULL) {
fprintf(fo, " EMAIL = %s\n", lw->email);
}
if (lw->phone != NULL) {
fprintf(fo, " PHONE = %s\n", lw->phone);
}
if (lw->loc != NULL) {
fprintf(fo, " LOC = %s\n", lw->loc);
}
if (lw->tool != NULL) {
fprintf(fo, " TOOL = %s\n", lw->tool);
}
}
#ifdef NEEDED
/* DUMPLWLCHAIN -- Dump all current connections. */
static void dumpLwlChain(fo)
FILE *fo;
{
struct lwl *lw;
LockConn();
lw = conn;
fprintf(fo, "\n========== %s ==========\n", etime(FALSE));
while (lw != NULL) {
fprintf(fo, "\n");
dumpLwl(fo, lw);
lw = lw->next;
}
UnlockConn();
}
#endif
/* LOGLWL -- Generate log entry for LWL event. */
static void logLwl(lw, event)
struct lwl *lw;
char *event;
{
char ipport[40], deef[256];
struct sockaddr_in u;
u.sin_addr.s_addr = lw->naddr;
sprintf(ipport, "%s:%d", inet_ntoa(u.sin_addr), lw->port);
sprintf(deef, "%s %s", ipport, lw->email ? lw->email : lw->cname);
if (lw->name) {
sprintf(deef + strlen(deef), " (%s)", lw->name);
}
printf("%s %s%s\n", estime(), event, deef);
}
/* GARDOL -- Validity-check an RTCP packet to make sure we don't
crash if some bozo sends us garbage. */
static int gardol(p, len)
unsigned char *p;
int len;
{
unsigned char *end;
if ((((p[0] >> 6) & 3) != RTP_VERSION) || /* Version incorrect ? */
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR) &&
(p[1] != RTCP_SDES) && (p[1] != RTCP_BYE) &&
(p[1] != RTCP_APP))) { /* Item type valid ? */
return FALSE;
}
end = p + len;
do {
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return p == end;
}
/* MAKEHTML -- Create an HTML file showing current connections. If
"private" is set, exact-match names are included
in the HTML file; this allows creation of a non-exported
active site file for the system manager's use. */
static int makeHTML(fname, private)
char *fname;
int private;
{
FILE *of;
char f[132], fn[132];
strcpy(f, fname);
strcat(f, ".new");
of = fopen(f, "w");
if (of != NULL) {
struct lwl *lw;
#define P(x) fprintf(of, x)
LockConn();
lw = conn;
P("<html>\n<head>\n<title>\nSpeak Freely: Active Sites\n");
P("</title>\n</head>\n\n<body>\n<center>\n<h1>");
P("Speak Freely: Active Sites</h1>\n<h2>");
fprintf(of, "As of %s UTC</h2>\n</center>\n<p>\n", etime(TRUE));
if (lw == NULL) {
P("<h2>No sites active.</h2>\n");
} else {
int i = 0;
while (lw != NULL) {
if (private || ((lw->email == NULL || lw->email[0] != '*') &&
(lw->cname[0] != '*'))) {
i++;
}
lw = lw->next;
}
lw = conn;
if (i == 0) {
/* Fib about number of sites active if all active sites
don't want a directory listing. */
P("<h2>No sites active.</h2>\n");
} else {
fprintf(of, "<h2>%d site%s active.</h2>\n",
i, i == 1 ? "" : "s");
P("<pre>\n");
while (lw != NULL) {
if (private || ((lw->email == NULL || lw->email[0] != '*') &&
(lw->cname[0] != '*'))) {
char ipport[40];
struct tm *lt;
struct sockaddr_in u;
lt = localtime(&lw->ltime);
u.sin_addr.s_addr = lw->naddr;
sprintf(ipport, "%s:%d", inet_ntoa(u.sin_addr), lw->port);
fprintf(of, "\n%-24s %-48s %02d:%02d\n", ipport, lw->cname,
lt->tm_hour, lt->tm_min);
if (lw->name != NULL) {
fprintf(of, "%25s%s\n", "", lw->name);
}
if (lw->loc != NULL) {
fprintf(of, "%25s%s\n", "", lw->loc);
}
if (lw->phone != NULL) {
fprintf(of, "%25sPhone: %s\n", "", lw->phone);
}
if (lw->email != NULL) {
fprintf(of, "%25sE-mail: %s\n", "", lw->email);
}
}
lw = lw->next;
}
P("</pre>\n");
}
}
UnlockConn();
P("</body>\n</html>\n");
fclose(of);
strcpy(fn, fname);
strcat(fn, ".html");
rename(f, fn);
if (debugging) {
fprintf(stderr, "%s: updated %s\n", prog, fn);
}
return TRUE;
}
return FALSE;
}
/* UPDHTML -- Update HTML if necessary. */
static void updHTML()
{
time_t now;
if (((htmlFile != NULL) || (htmlPrivateFile != NULL)) && htmlChange &&
((htmlTime <= 0) || (((now = time(NULL)) - htmlLast) > htmlTime))) {
htmlLast = now;
htmlChange = FALSE;
if (htmlFile != NULL) {
makeHTML(htmlFile, FALSE);
}
if (htmlPrivateFile != NULL) {
makeHTML(htmlPrivateFile, TRUE);
}
}
}
/* CHANGED -- Indicate a change which may require updating
the HTML file. */
static void changed()
{
htmlChange = TRUE;
#ifndef THREADS
updHTML();
#endif
}
/* LCASE -- Convert a string to lower case. */
static void lcase(s)
char *s;
{
while (*s) {
if (isupper(*s)) {
*s = tolower(*s);
}
s++;
}
}
#ifdef THREADS
/* FORWARDER_THREAD -- Thread which manages forwarding to a given
destination. */
static void *forwarder_thread(arg)
void *arg;
{
struct forwarder *f = (struct forwarder *) arg;
struct hostent *h;
long iadr;
#ifdef DBTHREAD
fprintf(stderr, "Started forwarder thread for %s\n", f->sitename);
#endif
if (isdigit(f->sitename[0]) && (iadr = inet_addr(f->sitename)) != -1) {
bcopy((char *) &iadr, (char *) (&(f->site)),
sizeof iadr);
f->status = 0;
} else {
h = gethostbyname(f->sitename);
if (h != NULL) {
bcopy((char *) (h->h_addr),
(char *) (&(f->site)),
sizeof(unsigned long));
f->status = 0;
} else {
fprintf(stderr, "%s: warning, forward destination %s unknown.\n",
prog, f->sitename);
f->status = -2;
return NULL;
}
}
if (debugging && f->status == 0) {
fprintf(stderr, "%s: forwarding to LWL server %s: %s.\n", prog,
inet_ntoa(f->site), f->sitename);
}
while (f->status == 0) {
struct lwl_queueitem *q;
int sock = -1;
while ((q = f->head) != NULL) {
int cstat;
struct sockaddr_in lookhost;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening forwarding socket");
break;
}
lookhost.sin_port = htons(f->port);
bcopy((char *) (&(f->site)), (char *) &lookhost.sin_addr.s_addr,
sizeof lookhost.sin_addr.s_addr);
errno = 0;
do {
cstat = connect(sock, (struct sockaddr *) &(lookhost), sizeof lookhost);
if (cstat >= 0) {
break;
}
} while (errno == EINTR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -