- Remove $Id line from md5.h. I really really hate those things.
- Remove all that locking crap. It never worked right anyway.
- Add conn->inside for things that should never ever be seen by clients
- Store supported groups list for each connection
- Support migrations.
- faimtest now theoretically supports doing this. It happens so rarely
that it makes it difficult to test. For more complicated clients, a
flag will have to be kept so that some things that happen during login
don't get triggered the second time around. But faimtest doesn't have
such problems.
- Added some random commentary.
No release numbers
------------------
+ - Mon Sep 10 06:15:43 PDT 2001
+ - Remove $Id line from md5.h. I really really hate those things.
+ - Remove all that locking crap. It never worked right anyway.
+ - Add conn->inside for things that should never ever be seen by clients
+ - Store supported groups list for each connection
+ - Support migrations.
+ - faimtest now theoretically supports doing this. It happens so rarely
+ that it makes it difficult to test. For more complicated clients, a
+ flag will have to be kept so that some things that happen during login
+ don't get triggered the second time around. But faimtest doesn't have
+ such problems.
+ - Added some random commentary.
+
- Sun Sep 9 03:01:28 PDT 2001
- Three fixes in directim for gaim. It works now. Yay.
#include <faimconfig.h>
#include <aim_cbtypes.h>
-#if !defined(FAIM_USEPTHREADS) && !defined(FAIM_USEFAKELOCKS) && !defined(FAIM_USENOPLOCKS)
-#error pthreads, fakelocks, or noplocks are currently required.
-#endif
-
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
typedef fu32_t aim_snacid_t;
typedef fu16_t flap_seqnum_t;
-#ifdef FAIM_USEPTHREADS
-#include <pthread.h>
-#define faim_mutex_t pthread_mutex_t
-#define faim_mutex_init(x) pthread_mutex_init(x, NULL)
-#define faim_mutex_lock(x) pthread_mutex_lock(x)
-#define faim_mutex_unlock(x) pthread_mutex_unlock(x)
-#define faim_mutex_destroy(x) pthread_mutex_destroy(x)
-#elif defined(FAIM_USEFAKELOCKS)
-/*
- * For platforms without pthreads, we also assume
- * we're not linking against a threaded app. Which
- * means we don't have to do real locking. The
- * macros below do nothing really. They're a joke.
- * But they get it to compile.
- *
- * XXX NOTE that locking hasn't really been tested in a long time,
- * and most code written after dec2000 --is not thread safe--. You'll
- * want to audit locking use before you use less-than-library level
- * concurrency.
- *
- */
-#define faim_mutex_t fu8_t
-#define faim_mutex_init(x) *x = 0
-#define faim_mutex_lock(x) while(*x != 0) {/* spin */}; *x = 1;
-#define faim_mutex_unlock(x) while(*x != 0) {/* spin spin spin */}; *x = 0;
-#define faim_mutex_destroy(x) while(*x != 0) {/* spiiiinnn */}; *x = 0;
-#elif defined(FAIM_USENOPLOCKS)
-#define faim_mutex_t fu8_t
-#define faim_mutex_init(x)
-#define faim_mutex_lock(x)
-#define faim_mutex_unlock(x)
-#define faim_mutex_destroy(x)
-#endif
-
/* Portability stuff (DMP) */
#ifdef _WIN32
time_t lastactivity; /* time of last transmit */
int forcedlatency;
void *handlerlist;
- faim_mutex_t active; /* lock around read/writes */
- faim_mutex_t seqnum_lock; /* lock around ->seqnum changes */
void *sessv; /* pointer to parent session */
+ void *inside; /* only accessible from inside libfaim */
struct aim_conn_s *next;
} aim_conn_t;
/* Connection information */
aim_conn_t *connlist;
- faim_mutex_t connlistlock;
/*
* Transmit/receive queues.
* XXX: Should these be per-connection? -mid
*/
void *snac_hash[FAIM_SNAC_HASH_SIZE];
- faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE];
aim_snacid_t snacid_next;
struct {
faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags);
faim_export int aim_clearhandlers(aim_conn_t *conn);
+faim_export aim_conn_t *aim_conn_findbygroup(aim_session_t *sess, fu16_t group);
faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn);
faim_export void aim_conn_close(aim_conn_t *deadconn);
faim_export aim_conn_t *aim_newconn(aim_session_t *, int type, const char *dest);
#define AIM_WARN_ANON 0x01
+faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn);
faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags);
faim_export int aim_bos_nop(aim_session_t *, aim_conn_t *);
faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn);
fu16_t toolversion;
};
+/*
+ * In SNACland, the terms 'family' and 'group' are synonymous -- the former
+ * is my term, the latter is AOL's.
+ */
+struct snacgroup {
+ fu16_t group;
+ struct snacgroup *next;
+};
+
+/*
+ * This is inside every connection. But it is a void * to anything
+ * outside of libfaim. It should remain that way. It's called data
+ * abstraction. Maybe you've heard of it. (Probably not if you're a
+ * libfaim user.)
+ *
+ */
+typedef struct aim_conn_inside_s {
+ struct snacgroup *groups;
+} aim_conn_inside_t;
+
+faim_internal void aim_conn_addgroup(aim_conn_t *conn, fu16_t group);
+
faim_internal fu16_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len);
faim_internal int aim_putcap(aim_bstream_t *bs, fu16_t caps);
#define FAIM_LOGIN_SERVER "login.oscar.aol.com"
#define FAIM_LOGIN_PORT 5190
-/*
- * What type of synchronisation to use.
- *
- * We don't actually use threads, but can use the POSIX mutex
- * in order to maintain thread safety. You can use the fake locking
- * if you really don't like pthreads (which I don't) or if you don't
- * have it.
- *
- * USEPTHREADS - Use POSIX mutecies
- * USEFAKELOCKS - Use little stub spinners to help find locking bugs
- * USENOPLOCKS - No-op out all synchro calls at compile time
- *
- * Default: use noplocks by default.
- *
- * !!!NOTE: Even with USEPTHREADS turned on, libfaim is not fully thread
- * safe. It will still take some effort to add locking calls to
- * the places that need them. In fact, this feature in general
- * is in danger of being officially deprecated and removed from
- * the code.
- *
- */
-#undef FAIM_USEPTHREADS
-#undef FAIM_USEFAKELOCKS
-#define FAIM_USENOPLOCKS
-
/*
* Size of the SNAC caching hash.
*
ghost@aladdin.com
*/
-/*$Id$ */
/*
Independent implementation of MD5 (RFC 1321).
return (char *)conn->priv; /* yuck ! */
}
+/* XXX get this into conn.c -- evil!! */
faim_export aim_conn_t *aim_chat_getconn(aim_session_t *sess, const char *name)
{
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
if (cur->type != AIM_CONN_TYPE_CHAT)
continue;
if (strcmp((char *)cur->priv, name) == 0)
break;
}
- faim_mutex_unlock(&sess->connlistlock);
return cur;
}
/*
- * aim_conn.c
+ * conn.c
*
* Does all this gloriously nifty connection handling stuff...
*
#include <netinet/in.h>
#endif
+/*
+ * In OSCAR, every connection has a set of SNAC groups associated
+ * with it. These are the groups that you can send over this connection
+ * without being guarenteed a "Not supported" SNAC error.
+ *
+ * The grand theory of things says that these associations transcend
+ * what libfaim calls "connection types" (conn->type). You can probably
+ * see the elegance here, but since I want to revel in it for a bit, you
+ * get to hear it all spelled out.
+ *
+ * So let us say that you have your core BOS connection running. One
+ * of your modules has just given you a SNAC of the group 0x0004 to send
+ * you. Maybe an IM destined for some twit in Greenland. So you start
+ * at the top of your connection list, looking for a connection that
+ * claims to support group 0x0004. You find one. Why, that neat BOS
+ * connection of yours can do that. So you send it on its way.
+ *
+ * Now, say, that fellow from Greenland has friends and they all want to
+ * meet up with you in a lame chat room. This has landed you a SNAC
+ * in the family 0x000e and you have to admit you're a bit lost. You've
+ * searched your connection list for someone who wants to make your life
+ * easy and deliver this SNAC for you, but there isn't one there.
+ *
+ * Here comes the good bit. Without even letting anyone know, particularly
+ * the module that decided to send this SNAC, and definitly not that twit
+ * in Greenland, you send out a service request. In this request, you have
+ * marked the need for a connection supporting group 0x000e. A few seconds
+ * later, you receive a service redirect with an IP address and a cookie in
+ * it. Great, you say. Now I have something to do. Off you go, making
+ * that connection. One of the first things you get from this new server
+ * is a message saying that indeed it does support the group you were looking
+ * for. So you continue and send rate confirmation and all that.
+ *
+ * Then you remember you had that SNAC to send, and now you have a means to
+ * do it, and you do, and everyone is happy. Except the Greenlander, who is
+ * still stuck in the bitter cold.
+ *
+ * Oh, and this is useful for building the Migration SNACs, too. In the
+ * future, this may help convince me to implement rate limit mitigation
+ * for real. We'll see.
+ *
+ * Just to make me look better, I'll say that I've known about this great
+ * scheme for quite some time now. But I still haven't convinced myself
+ * to make libfaim work that way. It would take a fair amount of effort,
+ * and probably some client API changes as well. (Whenever I don't want
+ * to do something, I just say it would change the client API. Then I
+ * instantly have a couple of supporters of not doing it.)
+ *
+ * Generally, addgroup is only called by the internal handling of the
+ * server ready SNAC. So if you want to do something before that, you'll
+ * have to be more creative. That is done rather early, though, so I don't
+ * think you have to worry about it. Unless you're me. I care deeply
+ * about such inane things.
+ *
+ */
+faim_internal void aim_conn_addgroup(aim_conn_t *conn, fu16_t group)
+{
+ aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
+ struct snacgroup *sg;
+
+ if (!(sg = malloc(sizeof(struct snacgroup))))
+ return;
+
+ faimdprintf(aim_conn_getsess(conn), 1, "adding group 0x%04x\n", group);
+ sg->group = group;
+
+ sg->next = ins->groups;
+ ins->groups = sg;
+
+ return;
+}
+
+faim_export aim_conn_t *aim_conn_findbygroup(aim_session_t *sess, fu16_t group)
+{
+ aim_conn_t *cur;
+
+ for (cur = sess->connlist; cur; cur = cur->next) {
+ aim_conn_inside_t *ins = (aim_conn_inside_t *)cur->inside;
+ struct snacgroup *sg;
+
+ for (sg = ins->groups; sg; sg = sg->next) {
+ if (sg->group == group)
+ return cur;
+ }
+ }
+
+ return NULL;
+}
+
+static struct snacgroup *connkill_snacgroups(struct snacgroup *sg)
+{
+
+ while (sg) {
+ struct snacgroup *tmp;
+
+ tmp = sg->next;
+ free(sg);
+ sg = tmp;
+ }
+
+ return NULL;
+}
+
static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn)
{
if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS)
aim_conn_kill_rend(sess, *deadconn);
+ if ((*deadconn)->inside) {
+ aim_conn_inside_t *inside = (aim_conn_inside_t *)(*deadconn)->inside;
+
+ inside->groups = connkill_snacgroups(inside->groups);
+
+ free(inside);
+ }
+
free(*deadconn);
deadconn = NULL;
static void aim_connrst(aim_session_t *sess)
{
- faim_mutex_init(&sess->connlistlock);
-
if (sess->connlist) {
aim_conn_t *cur = sess->connlist, *tmp;
deadconn->forcedlatency = 0;
deadconn->handlerlist = NULL;
deadconn->priv = NULL;
- faim_mutex_init(&deadconn->active);
- faim_mutex_init(&deadconn->seqnum_lock);
+ memset(deadconn->inside, 0, sizeof(aim_conn_inside_t));
return;
}
return NULL;
memset(newconn, 0, sizeof(aim_conn_t));
+ if (!(newconn->inside = malloc(sizeof(aim_conn_inside_t)))) {
+ free(newconn);
+ return NULL;
+ }
+ memset(newconn->inside, 0, sizeof(aim_conn_inside_t));
+
aim_conn_init(newconn);
newconn->next = sess->connlist;
faim_export void aim_conn_close(aim_conn_t *deadconn)
{
- faim_mutex_destroy(&deadconn->active);
- faim_mutex_destroy(&deadconn->seqnum_lock);
if (deadconn->fd >= 3)
close(deadconn->fd);
deadconn->fd = -1;
if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS)
aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn);
-
return;
}
* specified session. Returns the first connection of that
* type found.
*
+ * XXX except for RENDEZVOUS, all uses of this should be removed and
+ * use aim_conn_findbygroup() instead.
*/
faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type)
{
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
if ((cur->type == type) &&
!(cur->status & AIM_CONN_STATUS_INPROGRESS))
break;
}
- faim_mutex_unlock(&sess->connlistlock);
return cur;
}
{
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
if (cur->type == type)
break;
}
- faim_mutex_unlock(&sess->connlistlock);
return cur;
}
{
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
if (cur->fd == fd)
break;
}
- faim_mutex_unlock(&sess->connlistlock);
return cur;
}
if (!(conn = aim_conn_getnext(sess)))
return NULL;
- faim_mutex_lock(&conn->active);
-
conn->fd = src->fd;
conn->type = src->type;
conn->subtype = src->subtype;
conn->sessv = src->sessv;
aim_clonehandlers(sess, conn, src);
- faim_mutex_unlock(&conn->active);
+ if (src->inside) {
+ /*
+ * XXX should clone this section as well, but since currently
+ * this function only gets called for some of that rendezvous
+ * crap, and not on SNAC connections, its probably okay for
+ * now.
+ *
+ */
+ }
return conn;
}
if (!(connstruct = aim_conn_getnext(sess)))
return NULL;
- faim_mutex_lock(&connstruct->active);
-
connstruct->sessv = (void *)sess;
connstruct->type = type;
if (!dest) { /* just allocate a struct */
connstruct->fd = -1;
connstruct->status = 0;
- faim_mutex_unlock(&connstruct->active);
return connstruct;
}
connstruct->fd = -1;
connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
free(host);
- faim_mutex_unlock(&connstruct->active);
return connstruct;
} else
connstruct->fd = ret;
- faim_mutex_unlock(&connstruct->active);
-
free(host);
return connstruct;
int j;
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist, j = 0; cur; cur = cur->next) {
if (cur->fd > j)
j = cur->fd;
}
- faim_mutex_unlock(&sess->connlistlock);
return j;
}
{
aim_conn_t *cur;
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
- if (cur == conn) {
- faim_mutex_unlock(&sess->connlistlock);
+ if (cur == conn)
return 1;
- }
}
- faim_mutex_unlock(&sess->connlistlock);
return 0;
}
* 1 outgoing data pending (%NULL returned)
* 2 incoming data pending (connection with pending data returned)
*
- * XXX: we could probably stand to do a little courser locking here.
- *
*/
faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status)
{
fd_set fds, wfds;
int maxfd, i, haveconnecting = 0;
- faim_mutex_lock(&sess->connlistlock);
if (!sess->connlist) {
- faim_mutex_unlock(&sess->connlistlock);
*status = -1;
return NULL;
}
- faim_mutex_unlock(&sess->connlistlock);
FD_ZERO(&fds);
FD_ZERO(&wfds);
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) {
if (cur->fd == -1) {
/* don't let invalid/dead connections sit around */
*status = 2;
- faim_mutex_unlock(&sess->connlistlock);
return cur;
} else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
FD_SET(cur->fd, &wfds);
if (cur->fd > maxfd)
maxfd = cur->fd;
}
- faim_mutex_unlock(&sess->connlistlock);
/*
* If we have data waiting to be sent, return
}
if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
- faim_mutex_lock(&sess->connlistlock);
for (cur = sess->connlist; cur; cur = cur->next) {
if ((FD_ISSET(cur->fd, &fds)) ||
((cur->status & AIM_CONN_STATUS_INPROGRESS) &&
FD_ISSET(cur->fd, &wfds))) {
*status = 2;
- faim_mutex_unlock(&sess->connlistlock);
- return cur; /* XXX race condition here -- shouldnt unlock connlist */
+ return cur;
}
}
*status = 0; /* shouldn't happen */
else
*status = i; /* can be 0 or -1 */
- faim_mutex_unlock(&sess->connlistlock);
-
return NULL; /* no waiting or error, return */
}
if (!conn)
return -1;
- faim_mutex_lock(&conn->active);
conn->forcedlatency = newval;
conn->lastactivity = 0; /* reset this just to make sure */
- faim_mutex_unlock(&conn->active);
return 0;
}
/*
* Send Server Ready. (Non-client)
+ *
+ * XXX If anyone cares, this should be made to use the conn-stored group
+ * system.
+ *
*/
faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn)
{
return 0;
}
-
/*
* Send service redirect. (Non-Client)
*/
return 0;
}
-
+/*
+ * See comments in conn.c about how the group associations are supposed
+ * to work, and how they really work.
+ *
+ * This info probably doesn't even need to make it to the client.
+ *
+ */
static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
aim_rxcallback_t userfunc;
if (!(families = malloc(aim_bstream_empty(bs))))
return 0;
- for (famcount = 0; aim_bstream_empty(bs); famcount++)
+ for (famcount = 0; aim_bstream_empty(bs); famcount++) {
families[famcount] = aimbs_get16(bs);
+ aim_conn_addgroup(rx->conn, families[famcount]);
+ }
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
ret = userfunc(sess, rx, famcount, families);
return 0;
}
+/*
+ * How Migrations work.
+ *
+ * The server sends a Server Pause message, which the client should respond to
+ * with a Server Pause Ack, which contains the families it needs on this
+ * connection. The server will send a Migration Notice with an IP address, and
+ * then disconnect. Next the client should open the connection and send the
+ * cookie. Repeat the normal login process and pretend this never happened.
+ *
+ * The Server Pause contains no data.
+ *
+ */
+static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
+{
+ aim_rxcallback_t userfunc;
+
+ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+ return userfunc(sess, rx);
+
+ return 0;
+}
+
+/*
+ * It is rather important that aim_sendpauseack() gets called for the exact
+ * same connection that the Server Pause callback was called for, since
+ * libfaim extracts the data for the SNAC from the connection structure.
+ *
+ * Of course, if you don't do that, more bad things happen than just what
+ * libfaim can cause.
+ *
+ */
+faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn)
+{
+ aim_frame_t *fr;
+ aim_snacid_t snacid;
+ aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
+ struct snacgroup *sg;
+
+ if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1024)))
+ return -ENOMEM;
+
+ snacid = aim_cachesnac(sess, 0x0001, 0x000c, 0x0000, NULL, 0);
+ aim_putsnac(&fr->data, 0x0001, 0x000c, 0x0000, snacid);
+
+ /*
+ * This list should have all the groups that the original
+ * Host Online / Server Ready said this host supports. And
+ * we want them all back after the migration.
+ */
+ for (sg = ins->groups; sg; sg = sg->next)
+ aimbs_put16(&fr->data, sg->group);
+
+ aim_tx_enqueue(sess, fr);
+
+ return 0;
+}
+
+/*
+ * This is the final SNAC sent on the original connection during a migration.
+ * It contains the IP and cookie used to connect to the new server, and
+ * optionally a list of the SNAC groups being migrated.
+ *
+ */
+static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
+{
+ aim_rxcallback_t userfunc;
+ int ret = 0;
+ fu16_t groupcount, i;
+ aim_tlvlist_t *tl;
+ char *ip = NULL;
+ aim_tlv_t *cktlv;
+
+ /*
+ * Apparently there's some fun stuff that can happen right here. The
+ * migration can actually be quite selective about what groups it
+ * moves to the new server. When not all the groups for a connection
+ * are migrated, or they are all migrated but some groups are moved
+ * to a different server than others, it is called a bifurcated
+ * migration.
+ *
+ * Let's play dumb and not support that.
+ *
+ */
+ groupcount = aimbs_get16(bs);
+ for (i = 0; i < groupcount; i++) {
+ fu16_t group;
+
+ group = aimbs_get16(bs);
+
+ faimdprintf(sess, 0, "bifurcated migration unsupported -- group 0x%04x\n", group);
+ }
+
+ tl = aim_readtlvchain(bs);
+
+ if (aim_gettlv(tl, 0x0005, 1))
+ ip = aim_gettlv_str(tl, 0x0005, 1);
+
+ cktlv = aim_gettlv(tl, 0x0006, 1);
+
+ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+ ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL);
+
+ aim_freetlvchain(&tl);
+ free(ip);
+
+ return ret;
+}
+
static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
aim_rxcallback_t userfunc;
return rateresp(sess, mod, rx, snac, bs);
else if (snac->subtype == 0x000a)
return ratechange(sess, mod, rx, snac, bs);
+ else if (snac->subtype == 0x000b)
+ return serverpause(sess, mod, rx, snac, bs);
else if (snac->subtype == 0x000f)
return selfinfo(sess, mod, rx, snac, bs);
else if (snac->subtype == 0x0010)
return evilnotify(sess, mod, rx, snac, bs);
+ else if (snac->subtype == 0x0012)
+ return migrate(sess, mod, rx, snac, bs);
else if (snac->subtype == 0x0013)
return motd(sess, mod, rx, snac, bs);
else if (snac->subtype == 0x0018)
* 2 short -- Sequence number
* 4 short -- Number of data bytes that follow.
*/
- faim_mutex_lock(&conn->active);
if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
aim_conn_close(conn);
- faim_mutex_unlock(&conn->active);
return -1;
}
if (aimbs_get8(&flaphdr) != 0x2a) {
faimdprintf(sess, 0, "FLAP framing disrupted");
aim_conn_close(conn);
- faim_mutex_unlock(&conn->active);
return -1;
}
/* allocate a new struct */
- if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) {
- faim_mutex_unlock(&conn->active);
+ if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
return -1;
- }
memset(newrx, 0, sizeof(aim_frame_t));
/* we're doing FLAP if we're here */
if (!(payload = (fu8_t *) malloc(payloadlen))) {
aim_frame_destroy(newrx);
- faim_mutex_unlock(&conn->active);
return -1;
}
free(payload);
aim_frame_destroy(newrx);
aim_conn_close(conn);
- faim_mutex_unlock(&conn->active);
return -1;
}
} else
aim_bstream_init(&newrx->data, NULL, 0);
- faim_mutex_unlock(&conn->active);
aim_bstream_rewind(&newrx->data);
{
int i;
- for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
+ for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++)
sess->snac_hash[i] = NULL;
- faim_mutex_init(&sess->snac_hash_locks[i]);
- }
return;
}
index = snac->id % FAIM_SNAC_HASH_SIZE;
- faim_mutex_lock(&sess->snac_hash_locks[index]);
snac->next = (aim_snac_t *)sess->snac_hash[index];
sess->snac_hash[index] = (void *)snac;
- faim_mutex_unlock(&sess->snac_hash_locks[index]);
return snac->id;
}
index = id % FAIM_SNAC_HASH_SIZE;
- faim_mutex_lock(&sess->snac_hash_locks[index]);
for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) {
if (cur->id == id) {
*prev = cur->next;
} else
prev = &cur->next;
}
- faim_mutex_unlock(&sess->snac_hash_locks[index]);
return cur;
}
aim_snac_t *cur, **prev;
time_t curtime;
- faim_mutex_lock(&sess->snac_hash_locks[i]);
- if (!sess->snac_hash[i]) {
- faim_mutex_unlock(&sess->snac_hash_locks[i]);
+ if (!sess->snac_hash[i])
continue;
- }
curtime = time(NULL); /* done here in case we waited for the lock */
} else
prev = &cur->next;
}
- faim_mutex_unlock(&sess->snac_hash_locks[i]);
}
return;
{
flap_seqnum_t ret;
- faim_mutex_lock(&conn->seqnum_lock);
ret = ++conn->seqnum;
- faim_mutex_unlock(&conn->seqnum_lock);
return ret;
}
return 1;
}
+static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+
+ aim_sendpauseack(sess, fr->conn);
+
+ return 1;
+}
+
+static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+ va_list ap;
+ aim_conn_t *bosconn;
+ char *bosip;
+ fu8_t *cookie;
+
+ va_start(ap, fr);
+ bosip = va_arg(ap, char *);
+ cookie = va_arg(ap, fu8_t *);
+ va_end(ap);
+
+ dvprintf("migration in progress -- new BOS is %s -- disconnecting\n", bosip);
+ aim_conn_kill(sess, &fr->conn);
+
+ if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
+ dprintf("migrate: could not connect to BOS: internal error\n");
+ return 1;
+ } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
+ dprintf("migrate: could not connect to BOS\n");
+ aim_conn_kill(sess, &bosconn);
+ return 1;
+ }
+
+ /* Login will happen all over again. */
+ addcb_bos(sess, bosconn);
+
+ aim_auth_sendcookie(sess, bosconn, cookie);
+
+ return 1;
+}
+
void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
{
aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
+ aim_conn_addhandler(sess, bosconn, 0x0001, 0x000b, serverpause, 0);
+ aim_conn_addhandler(sess, bosconn, 0x0001, 0x0012, migrate, 0);
#ifdef MID_REWROTE_ALL_THE_CRAP
aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
regstatus = va_arg(ap, int);
email = va_arg(ap, char *);
bosip = va_arg(ap, char *);
- cookie = va_arg(ap, unsigned char *);
+ cookie = va_arg(ap, fu8_t *);
latestrelease = va_arg(ap, char *);
latestbuild = va_arg(ap, int);