Parsee/src/XMPP/Component.c

207 lines
4.4 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 <Parsee.h>
#include <XML.h>
/* The default component port Prosody uses. */
#define DEFAULT_PROSODY_PORT 5347
XMPPComponent *
XMPPInitialiseCompStream(char *host, int port)
{
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;
char *sha;
source = StrConcat(2, stream, shared);
sha = ParseeSHA1(source);
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_DEBUG, "- 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_lock(&comp->write_lock);
StreamClose(comp->stream);
comp->stream = NULL;
pthread_mutex_unlock(&comp->write_lock);
pthread_mutex_destroy(&comp->write_lock);
Free(comp->host);
Free(comp);
}