📄 lwld.c
字号:
}
}
*op = 0;
/* Drop trailing blanks. */
while (strlen(prune) > 0 && isspace(op[-1])) {
*(--op) = 0;
}
l = strlen(prune);
if (l == 0) {
return TRUE;
} else if (l > 48) {
int n;
/* String is too long. Try to trim it at a word boundary,
but if that fails just brutally lop it off. */
for (n = 47; n > 31; n--) {
if (isspace(prune[n])) {
prune[n] = 0;
n = 0;
break;
}
}
if (n > 0) {
prune[47] = 0;
}
}
*ap++ = item;
*ap++ = l = strlen(prune);
bcopy(prune, ap, l);
ap += l;
*app = ap;
}
/* SERVICEPACKET -- Process a packet from a connection. */
static void servicePacket(csock, from)
int csock;
struct sockaddr_in from; /* Sending host address */
{
int rll, forward, pvalid;
char zp[1024];
rtcp_t *rp;
short srp;
struct lwl *lw; /* Parsed packet */
char *p, *pend;
struct sockaddr_in fwdh;
forward = FALSE;
rll = recv(csock, zp, sizeof zp, 0);
#ifdef HEXDUMP
if (hexdump) {
fprintf(stderr, "%s: %d bytes read from socket.\n", prog, rll);
xd(stderr, zp, rll, TRUE);
}
#endif
/* If packet was forwarded from another server, extract the
embedded original source address and make the packet
look like it came directly from the sender. */
if (rll > 4 && (zp[0] & 0xC0) == 0xC0) {
forward = TRUE;
zp[0] &= ~0x40;
bcopy(zp + (rll - 4), &fwdh.sin_addr, 4);
rll -= 4;
if (debugging) {
fprintf(stderr, "%s: received forwarded packet from %s.\n",
prog, inet_ntoa(from.sin_addr));
}
from.sin_addr = fwdh.sin_addr ;
}
/* Some version of Speak Freely for Windows don't always
pad request packets to a multiple of four bytes. If
this is the case, insert the pad ourselves. */
while (((zp[1] & 0xFF) == RTCP_APP) && ((rll & 3) != 0)) {
zp[rll++] = 0;
}
/* Validate this packet. If it fails the validity check,
ignore it do it can't crash the code below. */
if (!gardol((unsigned char *) zp, rll)) {
if (debugging) {
fprintf(stderr, "%s: discarded invalid RTCP packet from %s.\n",
prog, inet_ntoa(from.sin_addr));
}
close(csock);
return;
}
/* Walk through the individual items in a possibly composite
packet until we locate an item we're interested in. This
allows us to accept packets that comply with the RTP standard
that all RTCP packets begin with an SR or RR. */
p = zp;
pend = p + rll;
pvalid = FALSE;
while ((p < pend) && (p[0] >> 6 & 3) == RTP_VERSION) {
int pt = p[1] & 0xFF;
if (pt == RTCP_SDES || pt == RTCP_BYE || pt == RTCP_APP) {
pvalid = TRUE;
break;
}
/* If not of interest to us, skip to next subpacket. */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
}
if (!pvalid) {
if (debugging) {
fprintf(stderr, "%s: discarded RTCP packet with unknown payload from %s.\n",
prog, inet_ntoa(from.sin_addr));
}
close(csock);
return;
}
/* Examine the packet to see what kind of request it is.
Note that since all the packets we're interested in can
be parsed without knowing their actual length in bytes, we
can ignore the possible presence of padding. */
rp = (rtcp_t *) p;
srp = ntohs(*((short *) p));
if (
#ifdef RationalWorld
rp->common.version == RTP_VERSION && /* Version ID correct */
rp->common.count == 1
#else
(((srp >> 14) & 3) == RTP_VERSION) &&
(((srp >> 8) & 0x1F) == 1)
#endif
) {
switch (
#ifdef RationalWorld
rp->common.pt
#else
srp & 0xFF
#endif
) {
/* SDES packet. This is a notification by a listening
that it's just started or is still
listening. If the host was previously
active we replace the old parameters
with the new in case something has
changed. The timeout is reset. Identity
of host is by canonical name, not SSRC,
since the host may have restarted with
a new SSRC without having sent us a BYE. */
case RTCP_SDES:
/* Parse the fields out of the SDES packet. */
{
char *cp = (char *) rp->r.sdes.item,
*lp = cp + (ntohs(rp->common.length) * 4);
struct lwl *lr, *llr;
lw = (struct lwl *) malloc(sizeof(struct lwl));
if (lw != NULL) {
bzero((char *) lw, sizeof(struct lwl));
lw->ssrc = rp->r.sdes.src;
lw->naddr = from.sin_addr.s_addr;
lw->port = from.sin_port;
lw->ltime = time(NULL);
if (prolix) {
printf("%s: %s SDES %08X\n", prog,
inet_ntoa(from.sin_addr), lw->ssrc);
}
while (cp < lp) {
switch ((*cp) & 0xFF) {
case RTCP_SDES_CNAME:
lw->cname = dupSdesItem(&cp);
break;
case RTCP_SDES_NAME:
lw->name = dupSdesItem(&cp);
break;
case RTCP_SDES_EMAIL:
lw->email = dupSdesItem(&cp);
break;
case RTCP_SDES_PHONE:
lw->phone = dupSdesItem(&cp);
break;
case RTCP_SDES_LOC:
lw->loc = dupSdesItem(&cp);
break;
case RTCP_SDES_TOOL:
lw->tool = dupSdesItem(&cp);
break;
case RTCP_SDES_PRIV:
{
char *zp = dupSdesItem(&cp);
if (zp != NULL) {
if (zp[0] == 1 &&
zp[1] == 'P') {
lw->port = atoi(zp + 2);
}
free(zp);
}
}
break;
case RTCP_SDES_END:
cp = lp;
break;
default:
{
char *zp = dupSdesItem(&cp);
if (zp != NULL) {
free(zp);
}
}
break;
}
}
if (debugging) {
dumpLwl(stderr, lw);
}
/* Search chain and see if a user with this
name is already know. If so, replace the
entry with this one. */
if (lw->cname != NULL) {
lr = conn;
llr = NULL;
while (lr != NULL) {
char *p = lw->cname, *q = lr->cname;
if (*p == '*') {
p++;
}
if (*q == '*') {
q++;
}
if (strcmp(p, q) == 0) {
lw->next = lr->next;
if (llr == NULL) {
conn = lw;
} else {
llr->next = lw;
}
destroyLwl(lr);
lw = NULL;
break;
}
llr = lr;
lr = lr->next;
}
/* If we didn't find an entry already in the
chain, link in the new entry. */
if (lw != NULL) {
lw->next = conn;
conn = lw;
if (verbose) {
logLwl(lw, "Connect: ");
}
changed();
}
if (!forward && lwl_nsites > 0) {
forwardLwlMessage(zp, rll, from.sin_addr);
}
} else {
/* Bogus item with no CNAME -- discard. */
if (debugging || verbose) {
fprintf(stderr, "Bogus SDES with no CNAME.\n");
if (!debugging) {
dumpLwl(stderr, lw);
}
}
destroyLwl(lw);
}
}
}
break;
/* BYE packet. This is sent when a listening host is
ceasing to listen in an orderly manner.
Identity here is by SSRC, since the
host is assumed to have properly announced
itself. Besides, that's the only ID in
the RTCP BYE packet, so it had darned
well be sufficient. */
case RTCP_BYE:
{
struct lwl *lr = conn, *llr = NULL;
if (prolix) {
printf("%s: %s BYE %08X\n", prog,
inet_ntoa(from.sin_addr), rp->r.bye.src[0]);
}
while (lr != NULL) {
if (rp->r.bye.src[0] == lr->ssrc) {
if (llr == NULL) {
conn = lr->next;
} else {
llr->next = lr->next;
}
if (debugging) {
fprintf(stderr, "Releasing:\n");
dumpLwl(stderr, lr);
}
if (verbose) {
logLwl(lr, "Bye: ");
}
changed();
destroyLwl(lr);
break;
}
llr = lr;
lr = lr->next;
}
if (!forward && lwl_nsites > 0) {
forwardLwlMessage(zp, rll, from.sin_addr);
}
}
break;
/* Application request packets. The following application
extensions implement the various queries a client can make
regarding the current state of the listening host list. */
case RTCP_APP:
if (prolix) {
printf("%s: %s APP %.4s\n", prog,
inet_ntoa(from.sin_addr), p + 8);
}
/* SFlq -- Pattern match in cname and name and
return matches, up to the maximum
packet size. If either the query string
or the canonical name begins with an
asterisk, the asterisk(s) is(/are) ignored
and a precise match with the canonical
name is required. */
if (bcmp(p + 8, "SFlq", 4) == 0) {
struct lwl *lr = conn;
char b[1500];
rtcp_t *rp = (rtcp_t *) b;
char *ap, *pap;
int l, scandex = 0;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 0;
rp->common.pt = RTCP_SDES;
#else
*((short *) rp) = htons((RTP_VERSION << 14) |
RTCP_SDES | (0 << 8));
#endif
ap = (char *) &(rp->r.sdes.src);
if (prolix) {
printf("%s: %s query \"%s\"\n", prog, inet_ntoa(from.sin_addr), p + 12);
}
lcase(p + 12);
while (lr != NULL) {
if (queryMatch(p + 12, lr)) {
char s[20];
pap = ap;
*((unsigned long *) ap) = lr->ssrc;
ap += sizeof(unsigned long);
addSDES(RTCP_SDES_CNAME, lr->cname +
(lr->cname[0] == '*' ? 1 : 0));
if (lr->name != NULL) {
addSDES(RTCP_SDES_NAME, lr->name);
}
if (lr->email != NULL) {
addSDES(RTCP_SDES_EMAIL, lr->email +
(lr->email[0] == '*' ? 1 : 0));
}
if (lr->phone != NULL) {
addSDES(RTCP_SDES_PHONE, lr->phone);
}
if (lr->loc != NULL) {
addSDES(RTCP_SDES_LOC, lr->loc);
}
if (lr->tool != NULL) {
addSDES(RTCP_SDES_TOOL, lr->tool);
}
sprintf(s, "\001P%d", lr->port);
addSDES(RTCP_SDES_PRIV, s);
{
struct sockaddr_in u;
u.sin_addr.s_addr = lr->naddr;
sprintf(s, "\001I%s", inet_ntoa(u.sin_addr));
addSDES(RTCP_SDES_PRIV, s);
}
sprintf(s, "\001T%lu", lr->ltime);
addSDES(RTCP_SDES_PRIV, s);
#ifdef NEEDED
/* If we're over the packet size limit,
let the user know there's more to be
retrieved starting at the given offset. */
if ((ap - b) > MaxReplyPacket) {
sprintf(s, "\001M%d", scandex);
addSDES(RTCP_SDES_PRIV, s);
}
#endif
*ap++ = RTCP_SDES_END;
/* Pad to next 32 bit boundary. */
while (((ap - b) & 3) != 0) {
*ap++ = RTCP_SDES_END;
}
if ((ap - b) > MaxReplyPacket) {
ap = pap;
break;
}
#ifdef RationalWorld
rp->common.count++;
#else
(((unsigned char *) rp)[0])++;
#endif
}
lr = lr->next;
scandex++;
}
l = ap - b;
rp->common.length = htons(((l + 3) / 4) - 1);
l = (ntohs(rp->common.length) + 1) * 4;
#ifdef HEXDUMP
if (hexdump) {
fprintf(stderr, "%s: %d bytes sent to socket.\n", prog, l);
xd(stderr, b, l, TRUE);
}
#endif
if (send(csock, b, l, 0) < 0) {
perror("sending query match reply");
}
}
/* SFms -- Retrieve the server's information
message, if any. If the server doesn't
publish a message, a null string is
returned in the reply packet. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -