/* * XXX this is nearly as ugly as proxyconnect(). */ int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn) { fd_set fds, wfds; struct timeval tv; int res, error = ETIMEDOUT; aim_rxcallback_t userfunc; if (!conn || (conn->fd == -1)) return -1; if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) return -1; FD_ZERO(&fds); FD_SET(conn->fd, &fds); FD_ZERO(&wfds); FD_SET(conn->fd, &wfds); tv.tv_sec = 0; tv.tv_usec = 0; if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { error = errno; aim_conn_close(conn); errno = error; return -1; } else if (res == 0) { return 0; /* hasn't really completed yet... */ } if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { socklen_t len = sizeof(error); if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) error = errno; } if (error) { aim_conn_close(conn); errno = error; return -1; } sock_make_blocking(conn->fd); conn->status &= ~AIM_CONN_STATUS_INPROGRESS; if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) userfunc(sess, NULL, conn); /* Flush out the queues if there was something waiting for this conn */ aim_tx_flushqueue(sess); return 0; }
static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn) { aim_rxqueue_cleanbyconn(sess, *deadconn); aim_tx_cleanqueue(sess, *deadconn); if ((*deadconn)->fd != -1) aim_conn_close(*deadconn); /* * This will free ->internal if it necessary... */ if ((*deadconn)->type == AIM_CONN_TYPE_CHAT) aim_conn_kill_chat(sess, *deadconn); if ((*deadconn)->inside) { aim_conn_inside_t *inside = (aim_conn_inside_t *)(*deadconn)->inside; connkill_snacgroups(&inside->groups); connkill_rates(&inside->rates); free(inside); } free(*deadconn); *deadconn = NULL; return; }
/* * Read a FLAP header from conn into fr, and return the number of bytes in the payload. */ static int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) { fu8_t flaphdr_raw[6]; aim_bstream_t flaphdr; fu16_t payloadlen; aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); /* * Read FLAP header. Six bytes: * 0 char -- Always 0x2a * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. * 2 short -- Sequence number * 4 short -- Number of data bytes that follow. */ if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) { aim_conn_close(conn); return -1; } aim_bstream_rewind(&flaphdr); /* * This shouldn't happen unless the socket breaks, the server breaks, * or we break. We must handle it just in case. */ if (aimbs_get8(&flaphdr) != 0x2a) { fu8_t start; aim_bstream_rewind(&flaphdr); start = aimbs_get8(&flaphdr); faimdprintf(sess, 0, "FLAP framing disrupted (0x%02x)", start); aim_conn_close(conn); return -1; } /* we're doing FLAP if we're here */ fr->hdrtype = AIM_FRAMETYPE_FLAP; fr->hdr.flap.type = aimbs_get8(&flaphdr); fr->hdr.flap.seqnum = aimbs_get16(&flaphdr); payloadlen = aimbs_get16(&flaphdr); /* length of payload */ return payloadlen; }
faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name) { aim_conn_t *conn; if (!(conn = aim_chat_getconn(sess, name))) return -ENOENT; aim_conn_close(conn); return 0; }
/** * aim_connrst - Clears out connection list, killing remaining connections. * @sess: Session to be cleared * * Clears out the connection list and kills any connections left. * */ static void aim_connrst(aim_session_t *sess) { if (sess->connlist) { aim_conn_t *cur = sess->connlist, *tmp; while (cur) { tmp = cur->next; aim_conn_close(cur); connkill_real(sess, &cur); cur = tmp; } } sess->connlist = NULL; return; }
/* * Read a rendezvous header from conn into fr, and return the number of bytes in the payload. */ static int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) { fu8_t rendhdr_raw[8]; aim_bstream_t rendhdr; aim_bstream_init(&rendhdr, rendhdr_raw, sizeof(rendhdr_raw)); if (aim_bstream_recv(&rendhdr, conn->fd, 8) < 8) { aim_conn_close(conn); return -1; } aim_bstream_rewind(&rendhdr); fr->hdrtype = AIM_FRAMETYPE_OFT; /* a misnomer--rendezvous */ aimbs_getrawbuf(&rendhdr, fr->hdr.rend.magic, 4); fr->hdr.rend.hdrlen = aimbs_get16(&rendhdr) - 8; fr->hdr.rend.type = aimbs_get16(&rendhdr); return fr->hdr.rend.hdrlen; }
static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn) { aim_rxqueue_cleanbyconn(sess, *deadconn); aim_tx_cleanqueue(sess, *deadconn); if ((*deadconn)->fd != -1) aim_conn_close(*deadconn); /* * XXX ->priv should never be touched by the library. I know * it used to be, but I'm getting rid of all that. Use * ->internal instead. */ if ((*deadconn)->priv) free((*deadconn)->priv); /* * This will free ->internal if it necessary... */ if ((*deadconn)->type == AIM_CONN_TYPE_CHAT) aim_conn_kill_chat(sess, *deadconn); if ((*deadconn)->inside) { aim_conn_inside_t *inside = (aim_conn_inside_t *)(*deadconn)->inside; connkill_snacgroups(&inside->groups); connkill_rates(&inside->rates); free(inside); } free(*deadconn); *deadconn = NULL; return; }
/* * Grab a single command sequence off the socket, and enqueue * it in the incoming event queue in a seperate struct. */ faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) { fu8_t flaphdr_raw[6]; aim_bstream_t flaphdr; aim_frame_t *newrx; fu16_t payloadlen; if (!sess || !conn) return 0; if (conn->fd == -1) return -1; /* its a aim_conn_close()'d connection */ if (conn->fd < 3) /* can happen when people abuse the interface */ return 0; if (conn->status & AIM_CONN_STATUS_INPROGRESS) return aim_conn_completeconnect(sess, conn); /* * Rendezvous (client-client) connections do not speak * FLAP, so this function will break on them. */ if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) return aim_get_command_rendezvous(sess, conn); else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd); return 0; } aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); /* * Read FLAP header. Six bytes: * * 0 char -- Always 0x2a * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. * 2 short -- Sequence number * 4 short -- Number of data bytes that follow. */ if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) { aim_conn_close(conn); return -1; } aim_bstream_rewind(&flaphdr); /* * This shouldn't happen unless the socket breaks, the server breaks, * or we break. We must handle it just in case. */ if (aimbs_get8(&flaphdr) != 0x2a) { fu8_t start; aim_bstream_rewind(&flaphdr); start = aimbs_get8(&flaphdr); faimdprintf(sess, 0, "FLAP framing disrupted (0x%02x)", start); aim_conn_close(conn); return -1; } /* allocate a new struct */ 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 */ newrx->hdrtype = AIM_FRAMETYPE_FLAP; newrx->hdr.flap.type = aimbs_get8(&flaphdr); newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr); payloadlen = aimbs_get16(&flaphdr); newrx->nofree = 0; /* free by default */ if (payloadlen) { fu8_t *payload = NULL; if (!(payload = (fu8_t *) malloc(payloadlen))) { aim_frame_destroy(newrx); return -1; } aim_bstream_init(&newrx->data, payload, payloadlen); /* read the payload */ if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) { free(payload); aim_frame_destroy(newrx); aim_conn_close(conn); return -1; } } else aim_bstream_init(&newrx->data, NULL, 0); aim_bstream_rewind(&newrx->data); newrx->conn = conn; newrx->next = NULL; /* this will always be at the bottom */ if (!sess->queue_incoming) sess->queue_incoming = newrx; else { aim_frame_t *cur; for (cur = sess->queue_incoming; cur->next; cur = cur->next) ; cur->next = newrx; } newrx->conn->lastactivity = time(NULL); return 0; }
/* * Grab a single command sequence off the socket, and enqueue * it in the incoming event queue in a seperate struct. */ int aim_get_command(aim_session_t *sess, aim_conn_t *conn) { guint8 flaphdr_raw[6]; aim_bstream_t flaphdr; aim_frame_t *newrx; guint16 payloadlen; if (!sess || !conn) return 0; if (conn->fd == -1) return -1; /* its a aim_conn_close()'d connection */ /* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON! And wouldn't it make sense to return something that prevents this function from being called again IMMEDIATELY (and making the program suck up all CPU time)?... if (conn->fd < 3) return 0; */ if (conn->status & AIM_CONN_STATUS_INPROGRESS) return aim_conn_completeconnect(sess, conn); aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); /* * Read FLAP header. Six bytes: * * 0 char -- Always 0x2a * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. * 2 short -- Sequence number * 4 short -- Number of data bytes that follow. */ if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) { aim_conn_close(conn); return -1; } aim_bstream_rewind(&flaphdr); /* * This shouldn't happen unless the socket breaks, the server breaks, * or we break. We must handle it just in case. */ if (aimbs_get8(&flaphdr) != 0x2a) { aim_bstream_rewind(&flaphdr); aimbs_get8(&flaphdr); imcb_error(sess->aux_data, "FLAP framing disrupted"); aim_conn_close(conn); return -1; } /* allocate a new struct */ if (!(newrx = (aim_frame_t *)g_new0(aim_frame_t,1))) return -1; /* we're doing FLAP if we're here */ newrx->hdrtype = AIM_FRAMETYPE_FLAP; newrx->hdr.flap.type = aimbs_get8(&flaphdr); newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr); payloadlen = aimbs_get16(&flaphdr); newrx->nofree = 0; /* free by default */ if (payloadlen) { guint8 *payload = NULL; if (!(payload = (guint8 *) g_malloc(payloadlen))) { aim_frame_destroy(newrx); return -1; } aim_bstream_init(&newrx->data, payload, payloadlen); /* read the payload */ if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) { aim_frame_destroy(newrx); /* free's payload */ aim_conn_close(conn); return -1; } } else aim_bstream_init(&newrx->data, NULL, 0); aim_bstream_rewind(&newrx->data); newrx->conn = conn; newrx->next = NULL; /* this will always be at the bottom */ if (!sess->queue_incoming) sess->queue_incoming = newrx; else { aim_frame_t *cur; for (cur = sess->queue_incoming; cur->next; cur = cur->next) ; cur->next = newrx; } newrx->conn->lastactivity = time(NULL); return 0; }
/* struct command_struct * get_generic( struct connection_info struct *, struct command_struct * ) Grab as many command sequences as we can off the socket, and enqueue each command in the incoming event queue in a seperate struct. */ int aim_get_command(void) { int i, readgood, j, isav, err; int s; fd_set fds; struct timeval tv; char generic[6]; struct command_rx_struct *workingStruct = NULL; struct command_rx_struct *workingPtr = NULL; struct aim_conn_t *conn = NULL; #if debug > 0 printf("Reading generic/unknown response..."); #endif /* dont wait at all (ie, never call this unless something is there) */ tv.tv_sec = 0; tv.tv_usec = 0; conn = aim_select(&tv); if (conn==NULL) return 0; /* nothing waiting */ s = conn->fd; FD_ZERO(&fds); FD_SET(s, &fds); tv.tv_sec = 0; /* wait, but only for 10us */ tv.tv_usec = 10; generic[0] = 0x00; readgood = 0; i = 0; j = 0; /* read first 6 bytes (the FLAP header only) off the socket */ while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6)) { if ((err = Read(s, &(generic[i]), 1)) < 0) { /* error is probably not recoverable...(must be a pessimistic day) */ aim_conn_close(conn); return err; } if (readgood == 0) { if (generic[i] == 0x2a) { readgood = 1; #if debug > 1 printf("%x ", generic[i]); fflush(stdout); #endif i++; } else { #if debug > 1 printf("skipping 0x%d ", generic[i]); fflush(stdout); #endif j++; } } else { #if debug > 1 printf("%x ", generic[i]); #endif i++; } FD_ZERO(&fds); FD_SET(s, &fds); tv.tv_sec= 2; tv.tv_usec= 2; } if (generic[0] != 0x2a) { /* this really shouldn't happen, since the main loop select() should protect us from entering this function without data waiting */ printf("Bad incoming data!"); return -1; } isav = i; /* allocate a new struct */ workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct)); workingStruct->lock = 1; /* lock the struct */ /* store type -- byte 2 */ workingStruct->type = (char) generic[1]; /* store seqnum -- bytes 3 and 4 */ workingStruct->seqnum = ( (( (unsigned int) generic[2]) & 0xFF) << 8); workingStruct->seqnum += ( (unsigned int) generic[3]) & 0xFF; /* store commandlen -- bytes 5 and 6 */ workingStruct->commandlen = ( (( (unsigned int) generic[4]) & 0xFF ) << 8); workingStruct->commandlen += ( (unsigned int) generic[5]) & 0xFF; /* malloc for data portion */ workingStruct->data = (char *) malloc(workingStruct->commandlen); /* read the data portion of the packet */ i = Read(s, workingStruct->data, workingStruct->commandlen); if (i < 0) { aim_conn_close(conn); return i; } #if debug > 0 printf(" done. (%db+%db read, %db skipped)\n", isav, i, j); #endif workingStruct->conn = conn; workingStruct->next = NULL; /* this will always be at the bottom */ workingStruct->lock = 0; /* unlock */ /* enqueue this packet */ if (aim_queue_incoming == NULL) aim_queue_incoming = workingStruct; else { workingPtr = aim_queue_incoming; while (workingPtr->next != NULL) workingPtr = workingPtr->next; workingPtr->next = workingStruct; } return 0; }
/* * Grab a single command sequence off the socket, and enqueue it in the incoming event queue * in a separate struct. */ faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) { aim_frame_t *newrx; fu16_t payloadlen; if (!sess || !conn) return -EINVAL; if (conn->fd == -1) return -1; /* it's an aim_conn_close()'d connection */ if (conn->fd < 3) /* can happen when people abuse the interface */ return -1; if (conn->status & AIM_CONN_STATUS_INPROGRESS) return aim_conn_completeconnect(sess, conn); if (!(newrx = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1))) return -ENOMEM; /* * Rendezvous (client to client) connections do not speak FLAP, so this * function will break on them. */ if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { int ret = aim_get_command_rendezvous(sess, conn, newrx); if (ret < 0) { free(newrx); return -1; } payloadlen = ret; } else if (conn->type == AIM_CONN_TYPE_LISTENER) { faimdprintf(sess, 0, "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd); free(newrx); return -1; } else payloadlen = aim_get_command_flap(sess, conn, newrx); newrx->nofree = 0; /* free by default */ if (payloadlen) { fu8_t *payload = NULL; if (!(payload = (fu8_t *)malloc(payloadlen))) { aim_frame_destroy(newrx); return -1; } aim_bstream_init(&newrx->data, payload, payloadlen); /* read the payload */ if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) { aim_frame_destroy(newrx); /* free's payload */ aim_conn_close(conn); return -1; } } else aim_bstream_init(&newrx->data, NULL, 0); aim_bstream_rewind(&newrx->data); newrx->conn = conn; newrx->next = NULL; /* this will always be at the bottom */ if (!sess->queue_incoming) sess->queue_incoming = newrx; else { aim_frame_t *cur; for (cur = sess->queue_incoming; cur->next; cur = cur->next) ; cur->next = newrx; } newrx->conn->lastactivity = time(NULL); return 0; }