⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 conn.c

📁 oscar message protocol stack
💻 C
📖 第 1 页 / 共 2 页
字号:
			return -1;		}	} else { /* connecting directly */		struct sockaddr_in sa;		struct hostent *hp;		if (!(hp = gethostbyname(host))) {			*statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR);			return -1;		}		memset(&sa, 0, sizeof(struct sockaddr_in));		sa.sin_port = htons(port);		memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);		sa.sin_family = hp->h_addrtype;		fd = socket(hp->h_addrtype, SOCK_STREAM, 0);		if (sess->nonblocking)			fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */		if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {			if (sess->nonblocking) {				if ((errno == EINPROGRESS) || (errno == EINTR)) {					if (statusret)						*statusret |= AIM_CONN_STATUS_INPROGRESS;					return fd;				}			}			close(fd);			fd = -1;		}	}	return fd;}/** * Clone an aim_conn_t. * * A new connection is allocated, and the values are filled in * appropriately. Note that this function sets the new connnection's * ->priv pointer to be equal to that of its parent: only the pointer * is copied, not the data it points to. * * @param sess The session containing this connection. * @param src The connection to clone. * @return Returns a pointer to the new aim_conn_t, or %NULL on error. */faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src){	aim_conn_t *conn;	if (!(conn = aim_conn_getnext(sess)))		return NULL;	conn->fd = src->fd;	conn->type = src->type;	conn->subtype = src->subtype;	conn->seqnum = src->seqnum;	conn->priv = src->priv;	conn->internal = src->internal;	conn->lastactivity = src->lastactivity;	conn->forcedlatency = src->forcedlatency;	conn->sessv = src->sessv;	aim_clonehandlers(sess, conn, src);	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;}/** * Opens a new connection to the specified dest host of specified * type, using the proxy settings if available.  If @host is %NULL, * the connection is allocated and returned, but no connection  * is made. * * FIXME: Return errors in a more sane way. * * @param sess Session to create connection in * @param type Type of connection to create * @param dest Host to connect to (in "host:port" syntax) */faim_export aim_conn_t *aim_newconn(aim_session_t *sess, int type, const char *dest){	aim_conn_t *connstruct;	fu16_t port = FAIM_LOGIN_PORT;	char *host;	int i, ret;	if (!(connstruct = aim_conn_getnext(sess)))		return NULL;	connstruct->sessv = (void *)sess;	connstruct->type = type;	if (!dest) { /* just allocate a struct */		connstruct->fd = -1;		connstruct->status = 0;		return connstruct;	}	/* 	 * As of 23 Jul 1999, AOL now sends the port number, preceded by a 	 * colon, in the BOS redirect.  This fatally breaks all previous 	 * libfaims.  Bad, bad AOL.	 *	 * We put this here to catch every case. 	 *	 */	for(i = 0; i < (int)strlen(dest); i++) {		if (dest[i] == ':') {			port = atoi(&(dest[i+1]));			break;		}	}	host = (char *)malloc(i+1);	strncpy(host, dest, i);	host[i] = '\0';	if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) {		connstruct->fd = -1;		connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);		free(host);		return connstruct;	} else		connstruct->fd = ret;	free(host);	return connstruct;}/** * Searches @sess for the passed connection. * * @param sess Session in which to look. * @param conn Connection to look for. * @return Returns 1 if the passed connection is present, zero otherwise. */faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn){	aim_conn_t *cur;	for (cur = sess->connlist; cur; cur = cur->next) {		if (cur == conn)			return 1;	}	return 0;}/** * Waits for a socket with data or for timeout, whichever comes first. * See select(2). *  * Return codes in *status: *   -1  error in select() (%NULL returned) *    0  no events pending (%NULL returned) *    1  outgoing data pending (%NULL returned) *    2  incoming data pending (connection with pending data returned) * * @param sess Session to wait on * @param timeout How long to wait * @param status Return status * @return If @status is 2, returns connection with pending data, otherwise %NULL */ faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status){	aim_conn_t *cur;	fd_set fds, wfds;	int maxfd, i, haveconnecting = 0;	if (!sess->connlist) {		*status = -1;		return NULL;	}	FD_ZERO(&fds);	FD_ZERO(&wfds);	for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) {		if (cur->fd == -1) {			/* don't let invalid/dead connections sit around */			*status = 2;			return cur;		} else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {			FD_SET(cur->fd, &wfds);			haveconnecting++;		}		FD_SET(cur->fd, &fds);		if (cur->fd > maxfd)			maxfd = cur->fd;	}	/* 	 * If we have data waiting to be sent, return	 *	 * We have to not do this if theres at least one	 * connection thats still connecting, since that connection	 * may have queued data and this return would prevent	 * the connection from ever completing!  This is a major	 * inadequacy of the libfaim way of doing things.  It means	 * that nothing can transmit as long as there's connecting	 * sockets. Evil.	 *	 * But its still better than having blocking connects.	 *	 */	if (!haveconnecting && sess->queue_outgoing) {		*status = 1;		return NULL;	} 	if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {		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;				return cur;			}		}		*status = 0; /* shouldn't happen */	} else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */		*status = 0;	else		*status = i; /* can be 0 or -1 */	return NULL;  /* no waiting or error, return */}/** * Set a forced latency value for connection.  Basically causes  * @newval seconds to be spent between transmits on a connection. * * This is my lame attempt at overcoming not understanding the rate * limiting.  * * XXX: This should really be replaced with something that scales and * backs off like the real rate limiting does. * * @param conn Conn to set latency for. * @param newval Number of seconds to force between transmits. * @return Returns -1 if the connection does not exist, zero otherwise. */faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval){	if (!conn)		return -1;	conn->forcedlatency = newval;	conn->lastactivity = 0; /* reset this just to make sure */	return 0;}/** * Configure a proxy for this session. * * Call this with your SOCKS5 proxy server parameters before * the first call to aim_newconn().  If called with all %NULL * args, it will clear out a previously set proxy.   * * Set username and password to %NULL if not applicable. * * @param sess Session to set proxy for. * @param server SOCKS server. * @param username SOCKS username. * @param password SOCKS password. */faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password){	/* clear out the proxy info */	if (!server || !strlen(server)) {		memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server));		memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username));		memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password));		return;	}	strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server));	if (username && strlen(username)) 		strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username));	if (password && strlen(password))		strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password));	return;}static void defaultdebugcb(aim_session_t *sess, int level, const char *format, va_list va){	vfprintf(stderr, format, va);	return;}/** * Initializes a session structure by setting the initial values  * stuff in the aim_session_t struct. * * @param sess Session to initialize. * @param nonblocking Set to true if you want connections to be non-blocking. * @param debuglevel Level of debugging output (zero is least). */faim_export void aim_session_init(aim_session_t *sess, bool nonblocking, int debuglevel){	if (!sess)		return;	memset(sess, 0, sizeof(aim_session_t));	aim_connrst(sess);	sess->queue_outgoing = NULL;	sess->queue_incoming = NULL;	aim_initsnachash(sess);	sess->msgcookies = NULL;	sess->nonblocking = nonblocking;	sess->debug = debuglevel;	sess->debugcb = defaultdebugcb;	sess->modlistv = NULL;	sess->snacid_next = 0x00000001;	sess->locate.userinfo = NULL;	sess->locate.torequest = NULL;	sess->locate.requested = NULL;	sess->locate.waiting_for_response = FALSE;	sess->ssi.received_data = 0;	sess->ssi.numitems = 0;	sess->ssi.official = NULL;	sess->ssi.local = NULL;	sess->ssi.pending = NULL;	sess->ssi.timestamp = (time_t)0;	sess->ssi.waiting_for_ack = 0;	sess->icq_info = NULL;	sess->authinfo = NULL;	sess->emailinfo = NULL;	sess->oft_info = NULL;	/*	 * This must always be set.  Default to the queue-based	 * version for back-compatibility.  	 */	aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);	/*	 * Register all the modules for this session...	 */	aim__registermodule(sess, misc_modfirst); /* load the catch-all first */	aim__registermodule(sess, service_modfirst);	aim__registermodule(sess, locate_modfirst);	aim__registermodule(sess, buddylist_modfirst);	aim__registermodule(sess, msg_modfirst);	aim__registermodule(sess, adverts_modfirst);	aim__registermodule(sess, invite_modfirst);	aim__registermodule(sess, admin_modfirst);	aim__registermodule(sess, popups_modfirst);	aim__registermodule(sess, bos_modfirst);	aim__registermodule(sess, search_modfirst);	aim__registermodule(sess, stats_modfirst);	aim__registermodule(sess, translate_modfirst);	aim__registermodule(sess, chatnav_modfirst);	aim__registermodule(sess, chat_modfirst);	aim__registermodule(sess, odir_modfirst);	aim__registermodule(sess, bart_modfirst);	/* missing 0x11 - 0x12 */	aim__registermodule(sess, ssi_modfirst);	/* missing 0x14 */	aim__registermodule(sess, icq_modfirst); /* XXX - Make sure this isn't sent for AIM */	/* missing 0x16 */	aim__registermodule(sess, auth_modfirst);	aim__registermodule(sess, email_modfirst);	return;}/** * Logoff and deallocate a session. * * @param sess Session to kill */faim_export void aim_session_kill(aim_session_t *sess){	aim_cleansnacs(sess, -1);	aim_logoff(sess);	aim__shutdownmodules(sess);	return;}/** * Set the function to call when outputting debugging info. * * The function specified is called whenever faimdprintf() is used within * libfaim, and the session's debugging level is greater tha nor equal to * the value faimdprintf was called with. * * @param sess Session to change. * @param cb Function to call. * @return Returns -1 if the session does not exist, zero otherwise. */faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t cb){	if (!sess)		return -1;	sess->debugcb = cb;	return 0;}/** * Determine if a connection is connecting. * * @param conn Connection to examine. * @return Returns nonzero if the connection is in the process of *         connecting (or if it just completed and *         aim_conn_completeconnect() has yet to be called on it). */faim_export int aim_conn_isconnecting(aim_conn_t *conn){	if (!conn)		return 0;	return !!(conn->status & AIM_CONN_STATUS_INPROGRESS);}/* * XXX this is nearly as ugly as proxyconnect(). */faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn){	aim_rxcallback_t userfunc;	if (!conn || (conn->fd == -1))		return -1;	if (!(conn->status & AIM_CONN_STATUS_INPROGRESS))		return -1;	fcntl(conn->fd, F_SETFL, 0);	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;}faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn){	if (!conn)		return NULL;	return (aim_session_t *)conn->sessv;}/** * Close -ALL- open connections. * * @param sess The session. * @return Zero. */faim_export int aim_logoff(aim_session_t *sess){	aim_connrst(sess);  /* in case we want to connect again */	return 0;}/** * No-op.  This sends an empty channel 5 SNAC.  WinAIM 4.x and higher * sends these _every minute_ to keep the connection alive. */faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn){	aim_frame_t *fr;	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x05, 0)))		return -ENOMEM;	aim_tx_enqueue(sess, fr);	/* clean out SNACs over 60sec old */	aim_cleansnacs(sess, 60);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -