mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 21:25:11 +00:00
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.
213 lines
4.6 KiB
C
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);
|
|
}
|