Parsee/src/XMPP/Component.c
LDA 3eae6c15ed [DEL] Remove killstanzas
Shinobis are no longer allowed, we're no longer on the Heian era, and as
such, we get rid of weird things like Heian Aliens.

In other, more serious news, this should increase reliability, as Parsee
now cleans after itself gracefully, instead of just killing off the
stream.
2024-07-06 02:55:11 +02:00

213 lines
4.6 KiB
C

#include <XMPP.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <XML.h>
/* TODO: Write the stream system once we have our XML implementation
* checked out.
*
* Did I mention I _hate_ writing XML SAX parsers? Oh, well, they're
* easier than making a DOM directly, so eeh. */
/* The default component port Prosody uses. */
#define DEFAULT_PROSODY_PORT 5347
XMPPComponent *
XMPPInitialiseCompStream(char *host, int port)
{
/* TODO */
int sd = -1;
struct addrinfo hints, *res, *res0;
int error;
char serv[8];
Stream *stream;
XMPPComponent *comp;
snprintf(serv, sizeof(serv), "%hu", port ? port : DEFAULT_PROSODY_PORT);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(host, serv, &hints, &res0);
for (res = res0; res; res = res->ai_next)
{
sd = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
if (sd < 0)
{
continue;
}
if (connect(sd, res->ai_addr, res->ai_addrlen) < 0)
{
close(sd);
sd = -1;
continue;
}
break;
}
if (sd < 0)
{
return NULL;
}
freeaddrinfo(res0);
stream = StreamFd(sd);
if (!stream)
{
close(sd);
return NULL;
}
comp = Malloc(sizeof(*comp));
comp->host = StrDuplicate(host);
comp->stream = stream;
pthread_mutex_init(&comp->write_lock, NULL);
(void) error;
return comp;
}
#include <Cytoplasm/Sha.h>
static char *
ComputeHandshake(char *shared, char *stream)
{
char *source;
unsigned char *raw_sha;
char *sha;
source = StrConcat(2, stream, shared);
raw_sha = Sha1(source);
sha = ShaToHex(raw_sha);
Free(raw_sha);
Free(source);
return sha;
}
bool
XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared)
{
/* TODO */
XMLexer *sax;
XMLEvent *ev;
char *stream_id, *handshake;
bool ret = false;
Stream *stream;
char *as;
if (!comp || !shared)
{
return false;
}
pthread_mutex_lock(&comp->write_lock);
stream = comp->stream;
as = comp->host;
StreamPrintf(stream,
"<stream:stream "
"xmlns='jabber:component:accept' "
"xmlns:stream='http://etherx.jabber.org/streams' "
"to='%s'>", as
);
StreamFlush(stream);
sax = XMLCreateLexer(stream, false);
while ((ev = XMLCrank(sax)))
{
if (ev->type == XML_RELAX)
{
XMLFreeEvent(ev);
continue;
}
break;
}
if (ev->type != XML_LEXER_STARTELEM ||
!StrEquals(ev->element, "stream:stream"))
{
Log(LOG_ERR, "Excepted stream:stream element.");
XMLFreeEvent(ev);
goto end;
}
stream_id = StrDuplicate(HashMapGet(ev->attrs, "id"));
handshake = ComputeHandshake(shared, stream_id);
Log(LOG_NOTICE, "- sID='%s'", stream_id);
StreamPrintf(stream, "<handshake>%s</handshake>", handshake);
StreamFlush(stream);
XMLFreeEvent(ev);
while ((ev = XMLCrank(sax)))
{
if (ev->type == XML_RELAX)
{
XMLFreeEvent(ev);
continue;
}
break;
}
if (ev->type != XML_LEXER_ELEM ||
!StrEquals(ev->element, "handshake"))
{
Log(LOG_ERR, "Excepted empty handshake reply, got nonsense.");
Log(LOG_ERR, "Another service (possibly Parsee) may have taken over.");
Log(LOG_ERR, "");
Log(LOG_ERR, "Simply jealous of that other service...");
Free(stream_id);
Free(handshake);
XMLFreeEvent(ev);
goto end;
}
ret = true;
/* We can uhh, send stanzas, and receive them! */
Log(LOG_INFO, "Communications to '%s' established.", as);
XMLFreeEvent(ev);
Free(stream_id);
Free(handshake);
end:
XMLFreeLexer(sax);
pthread_mutex_unlock(&comp->write_lock);
return ret;
}
void
XMPPFinishCompStream(XMPPComponent *comp)
{
if (!comp)
{
return;
}
pthread_mutex_lock(&comp->write_lock);
StreamPrintf(comp->stream, "<stream:stream/>");
StreamFlush(comp->stream);
pthread_mutex_unlock(&comp->write_lock);
}
void
XMPPEndCompStream(XMPPComponent *comp)
{
if (!comp)
{
return;
}
pthread_mutex_destroy(&comp->write_lock);
StreamClose(comp->stream);
Free(comp->host);
Free(comp);
}