5 * Does all this gloriously nifty connection handling stuff...
12 * Clears out connection list, killing remaining connections.
14 void aim_connrst(struct aim_session_t *sess)
16 faim_mutex_init(&sess->connlistlock, NULL);
18 struct aim_conn_t *cur = sess->connlist, *tmp;
27 sess->connlist = NULL;
32 * Gets a new connection structure.
34 struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
36 struct aim_conn_t *newconn, *cur;
38 if (!(newconn = malloc(sizeof(struct aim_conn_t))))
41 memset(newconn, 0, sizeof(struct aim_conn_t));
42 aim_conn_close(newconn);
45 faim_mutex_lock(&sess->connlistlock);
46 if (sess->connlist == NULL)
47 sess->connlist = newconn;
49 for (cur = sess->connlist; cur->next; cur = cur->next)
53 faim_mutex_unlock(&sess->connlistlock);
58 static void aim_conn_init(struct aim_conn_t *deadconn)
66 deadconn->lastactivity = 0;
67 deadconn->forcedlatency = 0;
68 deadconn->handlerlist = NULL;
69 deadconn->priv = NULL;
70 faim_mutex_init(&deadconn->active, NULL);
71 faim_mutex_init(&deadconn->seqnum_lock, NULL);
76 void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn)
78 struct aim_conn_t *cur;
80 if (!deadconn || !*deadconn)
83 faim_mutex_lock(&sess->connlistlock);
84 if (sess->connlist == NULL)
86 else if (sess->connlist->next == NULL) {
87 if (sess->connlist == *deadconn)
88 sess->connlist = NULL;
92 if (cur->next == *deadconn) {
93 cur->next = cur->next->next;
99 faim_mutex_unlock(&sess->connlistlock);
101 /* XXX: do we need this for txqueue too? */
102 aim_rxqueue_cleanbyconn(sess, *deadconn);
104 aim_conn_init(*deadconn);
111 void aim_conn_close(struct aim_conn_t *deadconn)
115 faim_mutex_destroy(&deadconn->active);
116 faim_mutex_destroy(&deadconn->seqnum_lock);
117 if (deadconn->fd >= 3)
119 typesav = deadconn->type;
120 if (deadconn->handlerlist)
121 aim_clearhandlers(deadconn);
123 free(deadconn->priv);
125 aim_conn_init(deadconn);
127 deadconn->type = typesav;
132 struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
135 struct aim_conn_t *cur;
137 faim_mutex_lock(&sess->connlistlock);
138 for (cur = sess->connlist; cur; cur = cur->next) {
139 if (cur->type == type)
142 faim_mutex_unlock(&sess->connlistlock);
147 * aim_newconn(type, dest)
149 * Opens a new connection to the specified dest host of type type.
151 * TODO: fix for proxies
152 * FIXME: Return errors in a more sane way.
155 struct aim_conn_t *aim_newconn(struct aim_session_t *sess,
156 int type, char *dest)
158 struct aim_conn_t *connstruct;
160 struct sockaddr_in sa;
162 u_short port = FAIM_LOGIN_PORT;
166 if ((connstruct=aim_conn_getnext(sess))==NULL)
169 faim_mutex_lock(&connstruct->active);
171 connstruct->type = type;
173 if (!dest) { /* just allocate a struct */
175 connstruct->status = 0;
176 faim_mutex_unlock(&connstruct->active);
181 * As of 23 Jul 1999, AOL now sends the port number, preceded by a
182 * colon, in the BOS redirect. This fatally breaks all previous
183 * libfaims. Bad, bad AOL.
185 * We put this here to catch every case.
189 for(i=0;i<strlen(dest);i++) {
190 if (dest[i] == ':') {
191 port = atoi(&(dest[i+1]));
195 host = (char *)malloc(i+1);
196 strncpy(host, dest, i);
199 hp = gethostbyname(host);
203 connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR);
204 faim_mutex_unlock(&connstruct->active);
208 memset(&sa.sin_zero, 0, 8);
209 sa.sin_port = htons(port);
210 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
211 sa.sin_family = hp->h_addrtype;
213 connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
214 ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
217 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
218 faim_mutex_unlock(&connstruct->active);
222 faim_mutex_unlock(&connstruct->active);
227 int aim_conngetmaxfd(struct aim_session_t *sess)
230 struct aim_conn_t *cur;
232 faim_mutex_lock(&sess->connlistlock);
233 for (cur = sess->connlist; cur; cur = cur->next) {
237 faim_mutex_unlock(&sess->connlistlock);
242 int aim_countconn(struct aim_session_t *sess)
245 struct aim_conn_t *cur;
247 faim_mutex_lock(&sess->connlistlock);
248 for (cur = sess->connlist; cur; cur = cur->next)
250 faim_mutex_unlock(&sess->connlistlock);
256 * aim_select(timeout)
258 * Waits for a socket with data or for timeout, whichever comes first.
261 * Return codes in *status:
262 * -1 error in select() (NULL returned)
263 * 0 no events pending (NULL returned)
264 * 1 outgoing data pending (NULL returned)
265 * 2 incoming data pending (connection with pending data returned)
267 * XXX: we could probably stand to do a little courser locking here.
270 struct aim_conn_t *aim_select(struct aim_session_t *sess,
271 struct timeval *timeout, int *status)
273 struct aim_conn_t *cur;
278 faim_mutex_lock(&sess->connlistlock);
279 if (sess->connlist == NULL) {
280 faim_mutex_unlock(&sess->connlistlock);
284 faim_mutex_unlock(&sess->connlistlock);
287 * If we have data waiting to be sent, return immediatly
289 if (sess->queue_outgoing != NULL) {
297 faim_mutex_lock(&sess->connlistlock);
298 for (cur = sess->connlist; cur; cur = cur->next) {
299 FD_SET(cur->fd, &fds);
303 faim_mutex_unlock(&sess->connlistlock);
305 if ((i = select(maxfd+1, &fds, NULL, NULL, timeout))>=1) {
306 faim_mutex_lock(&sess->connlistlock);
307 for (cur = sess->connlist; cur; cur = cur->next) {
308 if (FD_ISSET(cur->fd, &fds)) {
310 faim_mutex_unlock(&sess->connlistlock);
316 faim_mutex_unlock(&sess->connlistlock);
317 *status = i; /* may be 0 or -1 */
318 return NULL; /* no waiting or error, return */
321 int aim_conn_isready(struct aim_conn_t *conn)
324 return (conn->status & 0x0001);
328 int aim_conn_setstatus(struct aim_conn_t *conn, int status)
335 faim_mutex_lock(&conn->active);
336 val = conn->status ^= status;
337 faim_mutex_unlock(&conn->active);
341 int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
346 faim_mutex_lock(&conn->active);
347 conn->forcedlatency = newval;
348 conn->lastactivity = 0; /* reset this just to make sure */
349 faim_mutex_unlock(&conn->active);
354 void aim_session_init(struct aim_session_t *sess)
359 memset(sess, 0, sizeof(struct aim_session_t));
361 sess->queue_outgoing = NULL;
362 sess->queue_incoming = NULL;
363 sess->pendingjoin = NULL;
364 sess->outstanding_snacs = NULL;
365 sess->snac_nextid = 0x00000001;
368 * This must always be set. Default to the queue-based
369 * version for back-compatibility.
371 sess->tx_enqueue = &aim_tx_enqueue__queuebased;