comparison src/protocols/oscar/conn.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents 424a40f12a6c
children d82efea341ef
comparison
equal deleted inserted replaced
2245:31157c54fe6e 2246:933346315b9b
13 #include <netdb.h> 13 #include <netdb.h>
14 #include <sys/socket.h> 14 #include <sys/socket.h>
15 #include <netinet/in.h> 15 #include <netinet/in.h>
16 #endif 16 #endif
17 17
18 static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn)
19 {
20
21 aim_rxqueue_cleanbyconn(sess, *deadconn);
22 aim_tx_cleanqueue(sess, *deadconn);
23
24 if ((*deadconn)->fd != -1)
25 aim_conn_close(*deadconn);
26
27 /*
28 * XXX ->priv should never be touched by the library. I know
29 * it used to be, but I'm getting rid of all that. Use
30 * ->internal instead.
31 */
32 if ((*deadconn)->priv)
33 free((*deadconn)->priv);
34
35 /*
36 * This will free ->internal if it necessary...
37 */
38 if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS)
39 aim_conn_kill_rend(sess, *deadconn);
40
41 free(*deadconn);
42 deadconn = NULL;
43
44 return;
45 }
46
18 /** 47 /**
19 * aim_connrst - Clears out connection list, killing remaining connections. 48 * aim_connrst - Clears out connection list, killing remaining connections.
20 * @sess: Session to be cleared 49 * @sess: Session to be cleared
21 * 50 *
22 * Clears out the connection list and kills any connections left. 51 * Clears out the connection list and kills any connections left.
23 * 52 *
24 */ 53 */
25 static void aim_connrst(struct aim_session_t *sess) 54 static void aim_connrst(aim_session_t *sess)
26 { 55 {
27 faim_mutex_init(&sess->connlistlock); 56
28 if (sess->connlist) { 57 faim_mutex_init(&sess->connlistlock);
29 struct aim_conn_t *cur = sess->connlist, *tmp; 58
30 59 if (sess->connlist) {
31 while(cur) { 60 aim_conn_t *cur = sess->connlist, *tmp;
32 tmp = cur->next; 61
33 aim_conn_close(cur); 62 while (cur) {
34 free(cur); 63 tmp = cur->next;
35 cur = tmp; 64 aim_conn_close(cur);
36 } 65 connkill_real(sess, &cur);
37 } 66 cur = tmp;
38 sess->connlist = NULL; 67 }
39 return; 68 }
69
70 sess->connlist = NULL;
71
72 return;
40 } 73 }
41 74
42 /** 75 /**
43 * aim_conn_init - Reset a connection to default values. 76 * aim_conn_init - Reset a connection to default values.
44 * @deadconn: Connection to be reset 77 * @deadconn: Connection to be reset
45 * 78 *
46 * Initializes and/or resets a connection structure. 79 * Initializes and/or resets a connection structure.
47 * 80 *
48 */ 81 */
49 static void aim_conn_init(struct aim_conn_t *deadconn) 82 static void aim_conn_init(aim_conn_t *deadconn)
50 { 83 {
51 if (!deadconn) 84
52 return; 85 if (!deadconn)
53 86 return;
54 deadconn->fd = -1; 87
55 deadconn->subtype = -1; 88 deadconn->fd = -1;
56 deadconn->type = -1; 89 deadconn->subtype = -1;
57 deadconn->seqnum = 0; 90 deadconn->type = -1;
58 deadconn->lastactivity = 0; 91 deadconn->seqnum = 0;
59 deadconn->forcedlatency = 0; 92 deadconn->lastactivity = 0;
60 deadconn->handlerlist = NULL; 93 deadconn->forcedlatency = 0;
61 deadconn->priv = NULL; 94 deadconn->handlerlist = NULL;
62 faim_mutex_init(&deadconn->active); 95 deadconn->priv = NULL;
63 faim_mutex_init(&deadconn->seqnum_lock); 96 faim_mutex_init(&deadconn->active);
64 97 faim_mutex_init(&deadconn->seqnum_lock);
65 return; 98
99 return;
66 } 100 }
67 101
68 /** 102 /**
69 * aim_conn_getnext - Gets a new connection structure. 103 * aim_conn_getnext - Gets a new connection structure.
70 * @sess: Session 104 * @sess: Session
71 * 105 *
72 * Allocate a new empty connection structure. 106 * Allocate a new empty connection structure.
73 * 107 *
74 */ 108 */
75 static struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) 109 static aim_conn_t *aim_conn_getnext(aim_session_t *sess)
76 { 110 {
77 struct aim_conn_t *newconn, *cur; 111 aim_conn_t *newconn;
78 112
79 if (!(newconn = malloc(sizeof(struct aim_conn_t)))) 113 if (!(newconn = malloc(sizeof(aim_conn_t))))
80 return NULL; 114 return NULL;
81 115 memset(newconn, 0, sizeof(aim_conn_t));
82 memset(newconn, 0, sizeof(struct aim_conn_t)); 116
83 aim_conn_init(newconn); 117 aim_conn_init(newconn);
84 newconn->next = NULL; 118
85 119 newconn->next = sess->connlist;
86 faim_mutex_lock(&sess->connlistlock); 120 sess->connlist = newconn;
87 if (sess->connlist == NULL) 121
88 sess->connlist = newconn; 122 return newconn;
89 else {
90 for (cur = sess->connlist; cur->next; cur = cur->next)
91 ;
92 cur->next = newconn;
93 }
94 faim_mutex_unlock(&sess->connlistlock);
95
96 return newconn;
97 } 123 }
98 124
99 /** 125 /**
100 * aim_conn_kill - Close and free a connection. 126 * aim_conn_kill - Close and free a connection.
101 * @sess: Session for the connection 127 * @sess: Session for the connection
103 * 129 *
104 * Close, clear, and free a connection structure. Should never be 130 * Close, clear, and free a connection structure. Should never be
105 * called from within libfaim. 131 * called from within libfaim.
106 * 132 *
107 */ 133 */
108 faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn) 134 faim_export void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn)
109 { 135 {
110 struct aim_conn_t *cur; 136 aim_conn_t *cur, **prev;
111 137
112 if (!deadconn || !*deadconn) 138 if (!deadconn || !*deadconn)
113 return; 139 return;
114 140
115 aim_tx_cleanqueue(sess, *deadconn); 141 for (prev = &sess->connlist; (cur = *prev); ) {
116 142 if (cur == *deadconn) {
117 faim_mutex_lock(&sess->connlistlock); 143 *prev = cur->next;
118 if (sess->connlist == NULL) 144 break;
119 ; 145 }
120 else if (sess->connlist->next == NULL) { 146 prev = &cur->next;
121 if (sess->connlist == *deadconn) 147 }
122 sess->connlist = NULL; 148
123 } else { 149 if (!cur)
124 cur = sess->connlist; 150 return; /* oops */
125 while (cur->next) { 151
126 if (cur->next == *deadconn) { 152 connkill_real(sess, &cur);
127 cur->next = cur->next->next; 153
128 break; 154 return;
129 }
130 cur = cur->next;
131 }
132 }
133 faim_mutex_unlock(&sess->connlistlock);
134
135 /* XXX: do we need this for txqueue too? */
136 aim_rxqueue_cleanbyconn(sess, *deadconn);
137
138 if ((*deadconn)->fd != -1)
139 aim_conn_close(*deadconn);
140 if ((*deadconn)->priv)
141 free((*deadconn)->priv);
142 free(*deadconn);
143 deadconn = NULL;
144
145 return;
146 } 155 }
147 156
148 /** 157 /**
149 * aim_conn_close - Close a connection 158 * aim_conn_close - Close a connection
150 * @deadconn: Connection to close 159 * @deadconn: Connection to close
151 * 160 *
152 * Close (but not free) a connection. 161 * Close (but not free) a connection.
153 * 162 *
154 * This leaves everything untouched except for clearing the 163 * This leaves everything untouched except for clearing the
155 * handler list and setting the fd to -1 (used to recognize 164 * handler list and setting the fd to -1 (used to recognize
156 * dead connections). 165 * dead connections). It will also remove cookies if necessary.
157 * 166 *
158 */ 167 */
159 faim_export void aim_conn_close(struct aim_conn_t *deadconn) 168 faim_export void aim_conn_close(aim_conn_t *deadconn)
160 { 169 {
161 170
162 faim_mutex_destroy(&deadconn->active); 171 faim_mutex_destroy(&deadconn->active);
163 faim_mutex_destroy(&deadconn->seqnum_lock); 172 faim_mutex_destroy(&deadconn->seqnum_lock);
164 if (deadconn->fd >= 3) 173 if (deadconn->fd >= 3)
165 close(deadconn->fd); 174 close(deadconn->fd);
166 deadconn->fd = -1; 175 deadconn->fd = -1;
167 if (deadconn->handlerlist) 176 if (deadconn->handlerlist)
168 aim_clearhandlers(deadconn); 177 aim_clearhandlers(deadconn);
169 178 if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS)
170 return; 179 aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn);
180
181
182 return;
171 } 183 }
172 184
173 /** 185 /**
174 * aim_getconn_type - Find a connection of a specific type 186 * aim_getconn_type - Find a connection of a specific type
175 * @sess: Session to search 187 * @sess: Session to search
178 * Searches for a connection of the specified type in the 190 * Searches for a connection of the specified type in the
179 * specified session. Returns the first connection of that 191 * specified session. Returns the first connection of that
180 * type found. 192 * type found.
181 * 193 *
182 */ 194 */
183 faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, 195 faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type)
184 int type) 196 {
185 { 197 aim_conn_t *cur;
186 struct aim_conn_t *cur; 198
187 199 faim_mutex_lock(&sess->connlistlock);
188 faim_mutex_lock(&sess->connlistlock); 200 for (cur = sess->connlist; cur; cur = cur->next) {
189 for (cur = sess->connlist; cur; cur = cur->next) { 201 if ((cur->type == type) &&
190 if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS)) 202 !(cur->status & AIM_CONN_STATUS_INPROGRESS))
191 break; 203 break;
192 } 204 }
193 faim_mutex_unlock(&sess->connlistlock); 205 faim_mutex_unlock(&sess->connlistlock);
194 206
195 return cur; 207 return cur;
196 } 208 }
197 209
198 faim_export struct aim_conn_t *aim_getconn_type_all(struct aim_session_t *sess, 210 faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type)
199 int type) 211 {
200 { 212 aim_conn_t *cur;
201 struct aim_conn_t *cur; 213
202 214 faim_mutex_lock(&sess->connlistlock);
203 faim_mutex_lock(&sess->connlistlock); 215 for (cur = sess->connlist; cur; cur = cur->next) {
204 for (cur = sess->connlist; cur; cur = cur->next) { 216 if (cur->type == type)
205 if (cur->type == type) 217 break;
206 break; 218 }
207 } 219 faim_mutex_unlock(&sess->connlistlock);
208 faim_mutex_unlock(&sess->connlistlock); 220
209 221 return cur;
210 return cur;
211 } 222 }
212 223
213 /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */ 224 /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */
214 faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *sess, 225 faim_export aim_conn_t *aim_getconn_fd(aim_session_t *sess, int fd)
215 int fd) 226 {
216 { 227 aim_conn_t *cur;
217 struct aim_conn_t *cur; 228
218 229 faim_mutex_lock(&sess->connlistlock);
219 faim_mutex_lock(&sess->connlistlock); 230 for (cur = sess->connlist; cur; cur = cur->next) {
220 for (cur = sess->connlist; cur; cur = cur->next) { 231 if (cur->fd == fd)
221 if (cur->fd == fd) 232 break;
222 break; 233 }
223 } 234 faim_mutex_unlock(&sess->connlistlock);
224 faim_mutex_unlock(&sess->connlistlock); 235
225 236 return cur;
226 return cur;
227 } 237 }
228 238
229 /** 239 /**
230 * aim_proxyconnect - An extrememly quick and dirty SOCKS5 interface. 240 * aim_proxyconnect - An extrememly quick and dirty SOCKS5 interface.
231 * @sess: Session to connect 241 * @sess: Session to connect
235 * 245 *
236 * Attempts to connect to the specified host via the configured 246 * Attempts to connect to the specified host via the configured
237 * proxy settings, if present. If no proxy is configured for 247 * proxy settings, if present. If no proxy is configured for
238 * this session, the connection is done directly. 248 * this session, the connection is done directly.
239 * 249 *
240 */ 250 * XXX this is really awful.
241 static int aim_proxyconnect(struct aim_session_t *sess, 251 *
242 char *host, unsigned short port, 252 */
243 int *statusret) 253 static int aim_proxyconnect(aim_session_t *sess, const char *host, fu16_t port, fu32_t *statusret)
244 { 254 {
245 int fd = -1; 255 int fd = -1;
246 256
247 if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ 257 if (strlen(sess->socksproxy.server)) { /* connecting via proxy */
248 int i; 258 int i;
249 unsigned char buf[512]; 259 unsigned char buf[512];
250 struct sockaddr_in sa; 260 struct sockaddr_in sa;
251 struct hostent *hp; 261 struct hostent *hp;
252 char *proxy; 262 char *proxy;
253 unsigned short proxyport = 1080; 263 unsigned short proxyport = 1080;
254 264
255 for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { 265 for(i=0;i<(int)strlen(sess->socksproxy.server);i++) {
256 if (sess->socksproxy.server[i] == ':') { 266 if (sess->socksproxy.server[i] == ':') {
257 proxyport = atoi(&(sess->socksproxy.server[i+1])); 267 proxyport = atoi(&(sess->socksproxy.server[i+1]));
258 break; 268 break;
259 } 269 }
260 } 270 }
261 proxy = (char *)malloc(i+1); 271
262 strncpy(proxy, sess->socksproxy.server, i); 272 proxy = (char *)malloc(i+1);
263 proxy[i] = '\0'; 273 strncpy(proxy, sess->socksproxy.server, i);
264 274 proxy[i] = '\0';
265 if (!(hp = gethostbyname(proxy))) { 275
266 faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); 276 if (!(hp = gethostbyname(proxy))) {
267 *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); 277 faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n");
268 return -1; 278 *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR);
269 } 279 return -1;
270 free(proxy); 280 }
271 281 free(proxy);
272 memset(&sa.sin_zero, 0, 8); 282
273 sa.sin_port = htons(proxyport); 283 memset(&sa.sin_zero, 0, 8);
274 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); 284 sa.sin_port = htons(proxyport);
275 sa.sin_family = hp->h_addrtype; 285 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
276 286 sa.sin_family = hp->h_addrtype;
277 fd = socket(hp->h_addrtype, SOCK_STREAM, 0); 287
278 if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { 288 fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
279 faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); 289 if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
280 close(fd); 290 faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n");
281 return -1; 291 close(fd);
282 } 292 return -1;
283 293 }
284 i = 0; 294
285 buf[0] = 0x05; /* SOCKS version 5 */ 295 i = 0;
286 if (strlen(sess->socksproxy.username)) { 296 buf[0] = 0x05; /* SOCKS version 5 */
287 buf[1] = 0x02; /* two methods */ 297 if (strlen(sess->socksproxy.username)) {
288 buf[2] = 0x00; /* no authentication */ 298 buf[1] = 0x02; /* two methods */
289 buf[3] = 0x02; /* username/password authentication */ 299 buf[2] = 0x00; /* no authentication */
290 i = 4; 300 buf[3] = 0x02; /* username/password authentication */
291 } else { 301 i = 4;
292 buf[1] = 0x01; 302 } else {
293 buf[2] = 0x00; 303 buf[1] = 0x01;
294 i = 3; 304 buf[2] = 0x00;
295 } 305 i = 3;
296 306 }
297 if (write(fd, buf, i) < i) { 307
298 *statusret = errno; 308 if (write(fd, buf, i) < i) {
299 close(fd); 309 *statusret = errno;
300 return -1; 310 close(fd);
301 } 311 return -1;
302 312 }
303 if (read(fd, buf, 2) < 2) { 313
304 *statusret = errno; 314 if (read(fd, buf, 2) < 2) {
305 close(fd); 315 *statusret = errno;
306 return -1; 316 close(fd);
307 } 317 return -1;
308 318 }
309 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { 319
310 *statusret = EINVAL; 320 if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
311 close(fd); 321 *statusret = EINVAL;
312 return -1; 322 close(fd);
313 } 323 return -1;
314 324 }
315 /* check if we're doing username authentication */ 325
316 if (buf[1] == 0x02) { 326 /* check if we're doing username authentication */
317 i = aimutil_put8(buf, 0x01); /* version 1 */ 327 if (buf[1] == 0x02) {
318 i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); 328 i = aimutil_put8(buf, 0x01); /* version 1 */
319 i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); 329 i += aimutil_put8(buf+i, strlen(sess->socksproxy.username));
320 i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); 330 i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username));
321 i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); 331 i += aimutil_put8(buf+i, strlen(sess->socksproxy.password));
322 if (write(fd, buf, i) < i) { 332 i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password));
323 *statusret = errno; 333 if (write(fd, buf, i) < i) {
324 close(fd); 334 *statusret = errno;
325 return -1; 335 close(fd);
326 } 336 return -1;
327 if (read(fd, buf, 2) < 2) { 337 }
328 *statusret = errno; 338 if (read(fd, buf, 2) < 2) {
329 close(fd); 339 *statusret = errno;
330 return -1; 340 close(fd);
331 } 341 return -1;
332 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { 342 }
333 *statusret = EINVAL; 343 if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
334 close(fd); 344 *statusret = EINVAL;
335 return -1; 345 close(fd);
336 } 346 return -1;
337 } 347 }
338 348 }
339 i = aimutil_put8(buf, 0x05); 349
340 i += aimutil_put8(buf+i, 0x01); /* CONNECT */ 350 i = aimutil_put8(buf, 0x05);
341 i += aimutil_put8(buf+i, 0x00); /* reserved */ 351 i += aimutil_put8(buf+i, 0x01); /* CONNECT */
342 i += aimutil_put8(buf+i, 0x03); /* address type: host name */ 352 i += aimutil_put8(buf+i, 0x00); /* reserved */
343 i += aimutil_put8(buf+i, strlen(host)); 353 i += aimutil_put8(buf+i, 0x03); /* address type: host name */
344 i += aimutil_putstr(buf+i, host, strlen(host)); 354 i += aimutil_put8(buf+i, strlen(host));
345 i += aimutil_put16(buf+i, port); 355 i += aimutil_putstr(buf+i, host, strlen(host));
346 356 i += aimutil_put16(buf+i, port);
347 if (write(fd, buf, i) < i) { 357
348 *statusret = errno; 358 if (write(fd, buf, i) < i) {
349 close(fd); 359 *statusret = errno;
350 return -1; 360 close(fd);
351 } 361 return -1;
352 if (read(fd, buf, 10) < 10) { 362 }
353 *statusret = errno; 363 if (read(fd, buf, 10) < 10) {
354 close(fd); 364 *statusret = errno;
355 return -1; 365 close(fd);
356 } 366 return -1;
357 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { 367 }
358 *statusret = EINVAL; 368 if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
359 close(fd); 369 *statusret = EINVAL;
360 return -1; 370 close(fd);
361 } 371 return -1;
362 372 }
363 } else { /* connecting directly */ 373
364 struct sockaddr_in sa; 374 } else { /* connecting directly */
365 struct hostent *hp; 375 struct sockaddr_in sa;
366 376 struct hostent *hp;
367 if (!(hp = gethostbyname(host))) { 377
368 *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); 378 if (!(hp = gethostbyname(host))) {
369 return -1; 379 *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR);
370 } 380 return -1;
371 381 }
372 memset(&sa, 0, sizeof(struct sockaddr_in)); 382
373 sa.sin_port = htons(port); 383 memset(&sa, 0, sizeof(struct sockaddr_in));
374 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); 384 sa.sin_port = htons(port);
375 sa.sin_family = hp->h_addrtype; 385 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
376 386 sa.sin_family = hp->h_addrtype;
377 fd = socket(hp->h_addrtype, SOCK_STREAM, 0); 387
378 388 fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
379 if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) 389
380 fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ 390 if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT)
381 391 fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */
382 if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { 392
383 if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { 393 if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
384 if ((errno == EINPROGRESS) || (errno == EINTR)) { 394 if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) {
385 if (statusret) 395 if ((errno == EINPROGRESS) || (errno == EINTR)) {
386 *statusret |= AIM_CONN_STATUS_INPROGRESS; 396 if (statusret)
387 return fd; 397 *statusret |= AIM_CONN_STATUS_INPROGRESS;
388 } 398 return fd;
389 } 399 }
390 close(fd); 400 }
391 fd = -1; 401 close(fd);
392 } 402 fd = -1;
393 } 403 }
394 return fd; 404 }
405 return fd;
395 } 406 }
396 407
397 /** 408 /**
398 * aim_cloneconn - clone an aim_conn_t 409 * aim_cloneconn - clone an aim_conn_t
399 * @sess: session containing parent 410 * @sess: session containing parent
405 * is copied, not the data it points to. 416 * is copied, not the data it points to.
406 * 417 *
407 * This function returns a pointer to the new aim_conn_t, or %NULL on 418 * This function returns a pointer to the new aim_conn_t, or %NULL on
408 * error 419 * error
409 */ 420 */
410 faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, 421 faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src)
411 struct aim_conn_t *src) 422 {
412 { 423 aim_conn_t *conn;
413 struct aim_conn_t *conn; 424
414 struct aim_rxcblist_t *cur; 425 if (!(conn = aim_conn_getnext(sess)))
415 426 return NULL;
416 if (!(conn = aim_conn_getnext(sess))) 427
417 return NULL; 428 faim_mutex_lock(&conn->active);
418 429
419 faim_mutex_lock(&conn->active); 430 conn->fd = src->fd;
420 431 conn->type = src->type;
421 conn->fd = src->fd; 432 conn->subtype = src->subtype;
422 conn->type = src->type; 433 conn->seqnum = src->seqnum;
423 conn->subtype = src->subtype; 434 conn->priv = src->priv;
424 conn->seqnum = src->seqnum; 435 conn->internal = src->internal;
425 conn->priv = src->priv; 436 conn->lastactivity = src->lastactivity;
426 conn->lastactivity = src->lastactivity; 437 conn->forcedlatency = src->forcedlatency;
427 conn->forcedlatency = src->forcedlatency; 438 conn->sessv = src->sessv;
428 conn->sessv = src->sessv; 439 aim_clonehandlers(sess, conn, src);
429 440
430 /* clone handler list */ 441 faim_mutex_unlock(&conn->active);
431 for (cur = src->handlerlist; cur; cur = cur->next) { 442
432 aim_conn_addhandler(sess, conn, cur->family, cur->type, 443 return conn;
433 cur->handler, cur->flags);
434 }
435
436 faim_mutex_unlock(&conn->active);
437
438 return conn;
439 } 444 }
440 445
441 /** 446 /**
442 * aim_newconn - Open a new connection 447 * aim_newconn - Open a new connection
443 * @sess: Session to create connection in 448 * @sess: Session to create connection in
450 * is made. 455 * is made.
451 * 456 *
452 * FIXME: Return errors in a more sane way. 457 * FIXME: Return errors in a more sane way.
453 * 458 *
454 */ 459 */
455 faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess, 460 faim_export aim_conn_t *aim_newconn(aim_session_t *sess, int type, const char *dest)
456 int type, char *dest) 461 {
457 { 462 aim_conn_t *connstruct;
458 struct aim_conn_t *connstruct; 463 fu16_t port = FAIM_LOGIN_PORT;
459 int ret; 464 char *host;
460 u_short port = FAIM_LOGIN_PORT; 465 int i, ret;
461 char *host = NULL; 466
462 int i=0; 467 if (!(connstruct = aim_conn_getnext(sess)))
463 468 return NULL;
464 if ((connstruct=aim_conn_getnext(sess))==NULL) 469
465 return NULL; 470 faim_mutex_lock(&connstruct->active);
466 471
467 faim_mutex_lock(&connstruct->active); 472 connstruct->sessv = (void *)sess;
468 473 connstruct->type = type;
469 connstruct->sessv = (void *)sess; 474
470 connstruct->type = type; 475 if (!dest) { /* just allocate a struct */
471 476 connstruct->fd = -1;
472 if (!dest) { /* just allocate a struct */ 477 connstruct->status = 0;
473 connstruct->fd = -1; 478 faim_mutex_unlock(&connstruct->active);
474 connstruct->status = 0; 479 return connstruct;
475 faim_mutex_unlock(&connstruct->active); 480 }
476 return connstruct; 481
477 } 482 /*
478 483 * As of 23 Jul 1999, AOL now sends the port number, preceded by a
479 /* 484 * colon, in the BOS redirect. This fatally breaks all previous
480 * As of 23 Jul 1999, AOL now sends the port number, preceded by a 485 * libfaims. Bad, bad AOL.
481 * colon, in the BOS redirect. This fatally breaks all previous 486 *
482 * libfaims. Bad, bad AOL. 487 * We put this here to catch every case.
483 * 488 *
484 * We put this here to catch every case. 489 */
485 * 490
486 */ 491 for(i = 0; i < (int)strlen(dest); i++) {
487 492 if (dest[i] == ':') {
488 for(i=0;i<(int)strlen(dest);i++) { 493 port = atoi(&(dest[i+1]));
489 if (dest[i] == ':') { 494 break;
490 port = atoi(&(dest[i+1])); 495 }
491 break; 496 }
492 } 497
493 } 498 host = (char *)malloc(i+1);
494 host = (char *)malloc(i+1); 499 strncpy(host, dest, i);
495 strncpy(host, dest, i); 500 host[i] = '\0';
496 host[i] = '\0'; 501
497 502 if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) {
498 if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { 503 connstruct->fd = -1;
499 connstruct->fd = -1; 504 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
500 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); 505 free(host);
501 free(host); 506 faim_mutex_unlock(&connstruct->active);
502 faim_mutex_unlock(&connstruct->active); 507 return connstruct;
503 return connstruct; 508 } else
504 } else 509 connstruct->fd = ret;
505 connstruct->fd = ret; 510
506 511 faim_mutex_unlock(&connstruct->active);
507 faim_mutex_unlock(&connstruct->active); 512
508 513 free(host);
509 free(host); 514
510 515 return connstruct;
511 return connstruct;
512 } 516 }
513 517
514 /** 518 /**
515 * aim_conngetmaxfd - Return the highest valued file discriptor in session 519 * aim_conngetmaxfd - Return the highest valued file discriptor in session
516 * @sess: Session to search 520 * @sess: Session to search
517 * 521 *
518 * Returns the highest valued filed descriptor of all open 522 * Returns the highest valued filed descriptor of all open
519 * connections in @sess. 523 * connections in @sess.
520 * 524 *
521 */ 525 */
522 faim_export int aim_conngetmaxfd(struct aim_session_t *sess) 526 faim_export int aim_conngetmaxfd(aim_session_t *sess)
523 { 527 {
524 int j = 0; 528 int j;
525 struct aim_conn_t *cur; 529 aim_conn_t *cur;
526 530
527 faim_mutex_lock(&sess->connlistlock); 531 faim_mutex_lock(&sess->connlistlock);
528 for (cur = sess->connlist; cur; cur = cur->next) { 532 for (cur = sess->connlist, j = 0; cur; cur = cur->next) {
529 if (cur->fd > j) 533 if (cur->fd > j)
530 j = cur->fd; 534 j = cur->fd;
531 } 535 }
532 faim_mutex_unlock(&sess->connlistlock); 536 faim_mutex_unlock(&sess->connlistlock);
533 537
534 return j; 538 return j;
535 } 539 }
536 540
537 /** 541 /**
538 * aim_conn_in_sess - Predicate to test the precense of a connection in a sess 542 * aim_conn_in_sess - Predicate to test the precense of a connection in a sess
539 * @sess: Session to look in 543 * @sess: Session to look in
541 * 545 *
542 * Searches @sess for the passed connection. Returns 1 if its present, 546 * Searches @sess for the passed connection. Returns 1 if its present,
543 * zero otherwise. 547 * zero otherwise.
544 * 548 *
545 */ 549 */
546 faim_export int aim_conn_in_sess(struct aim_session_t *sess, struct aim_conn_t *conn) 550 faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn)
547 { 551 {
548 struct aim_conn_t *cur; 552 aim_conn_t *cur;
549 553
550 faim_mutex_lock(&sess->connlistlock); 554 faim_mutex_lock(&sess->connlistlock);
551 for(cur = sess->connlist; cur; cur = cur->next) 555 for (cur = sess->connlist; cur; cur = cur->next) {
552 if(cur == conn) { 556 if (cur == conn) {
553 faim_mutex_unlock(&sess->connlistlock); 557 faim_mutex_unlock(&sess->connlistlock);
554 return 1; 558 return 1;
555 } 559 }
556 faim_mutex_unlock(&sess->connlistlock); 560 }
557 return 0; 561 faim_mutex_unlock(&sess->connlistlock);
562
563 return 0;
558 } 564 }
559 565
560 /** 566 /**
561 * aim_select - Wait for a socket with data or timeout 567 * aim_select - Wait for a socket with data or timeout
562 * @sess: Session to wait on 568 * @sess: Session to wait on
573 * 2 incoming data pending (connection with pending data returned) 579 * 2 incoming data pending (connection with pending data returned)
574 * 580 *
575 * XXX: we could probably stand to do a little courser locking here. 581 * XXX: we could probably stand to do a little courser locking here.
576 * 582 *
577 */ 583 */
578 faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess, 584 faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status)
579 struct timeval *timeout, 585 {
580 int *status) 586 aim_conn_t *cur;
581 { 587 fd_set fds, wfds;
582 struct aim_conn_t *cur; 588 int maxfd, i, haveconnecting = 0;
583 fd_set fds, wfds; 589
584 int maxfd = 0; 590 faim_mutex_lock(&sess->connlistlock);
585 int i, haveconnecting = 0; 591 if (!sess->connlist) {
586 592 faim_mutex_unlock(&sess->connlistlock);
587 faim_mutex_lock(&sess->connlistlock); 593 *status = -1;
588 if (sess->connlist == NULL) { 594 return NULL;
589 faim_mutex_unlock(&sess->connlistlock); 595 }
590 *status = -1;
591 return NULL;
592 }
593 faim_mutex_unlock(&sess->connlistlock);
594
595 FD_ZERO(&fds);
596 FD_ZERO(&wfds);
597 maxfd = 0;
598
599 faim_mutex_lock(&sess->connlistlock);
600 for (cur = sess->connlist; cur; cur = cur->next) {
601 if (cur->fd == -1) {
602 /* don't let invalid/dead connections sit around */
603 *status = 2;
604 faim_mutex_unlock(&sess->connlistlock);
605 return cur;
606 } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
607 FD_SET(cur->fd, &wfds);
608
609 haveconnecting++;
610 }
611 FD_SET(cur->fd, &fds);
612 if (cur->fd > maxfd)
613 maxfd = cur->fd;
614 }
615 faim_mutex_unlock(&sess->connlistlock);
616
617 /*
618 * If we have data waiting to be sent, return
619 *
620 * We have to not do this if theres at least one
621 * connection thats still connecting, since that connection
622 * may have queued data and this return would prevent
623 * the connection from ever completing! This is a major
624 * inadequacy of the libfaim way of doing things. It means
625 * that nothing can transmit as long as there's connecting
626 * sockets. Evil.
627 *
628 * But its still better than having blocking connects.
629 *
630 */
631 if (!haveconnecting && (sess->queue_outgoing != NULL)) {
632 *status = 1;
633 return NULL;
634 }
635
636 if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
637 faim_mutex_lock(&sess->connlistlock);
638 for (cur = sess->connlist; cur; cur = cur->next) {
639 if ((FD_ISSET(cur->fd, &fds)) ||
640 ((cur->status & AIM_CONN_STATUS_INPROGRESS) &&
641 FD_ISSET(cur->fd, &wfds))) {
642 *status = 2;
643 faim_mutex_unlock(&sess->connlistlock); 596 faim_mutex_unlock(&sess->connlistlock);
644 return cur; /* XXX race condition here -- shouldnt unlock connlist */ 597
645 } 598 FD_ZERO(&fds);
646 } 599 FD_ZERO(&wfds);
647 *status = 0; /* shouldn't happen */ 600
648 } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ 601 faim_mutex_lock(&sess->connlistlock);
649 *status = 0; 602 for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) {
650 else 603 if (cur->fd == -1) {
651 *status = i; /* can be 0 or -1 */ 604 /* don't let invalid/dead connections sit around */
652 605 *status = 2;
653 faim_mutex_unlock(&sess->connlistlock); 606 faim_mutex_unlock(&sess->connlistlock);
654 607 return cur;
655 return NULL; /* no waiting or error, return */ 608 } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
656 } 609 FD_SET(cur->fd, &wfds);
657 610
658 /** 611 haveconnecting++;
659 * aim_conn_isready - Test if a connection is marked ready 612 }
660 * @conn: Connection to test 613 FD_SET(cur->fd, &fds);
661 * 614 if (cur->fd > maxfd)
662 * Returns true if the connection is ready, false otherwise. 615 maxfd = cur->fd;
663 * Returns -1 if the connection is invalid. 616 }
664 * 617 faim_mutex_unlock(&sess->connlistlock);
665 * XXX: This is deprecated. 618
666 * 619 /*
667 */ 620 * If we have data waiting to be sent, return
668 faim_export int aim_conn_isready(struct aim_conn_t *conn) 621 *
669 { 622 * We have to not do this if theres at least one
670 if (conn) 623 * connection thats still connecting, since that connection
671 return (conn->status & 0x0001); 624 * may have queued data and this return would prevent
672 return -1; 625 * the connection from ever completing! This is a major
673 } 626 * inadequacy of the libfaim way of doing things. It means
674 627 * that nothing can transmit as long as there's connecting
675 /** 628 * sockets. Evil.
676 * aim_conn_setstatus - Set the status of a connection 629 *
677 * @conn: Connection 630 * But its still better than having blocking connects.
678 * @status: New status 631 *
679 * 632 */
680 * @newstatus is %XOR'd with the previous value of the connection 633 if (!haveconnecting && sess->queue_outgoing) {
681 * status and returned. Returns -1 if the connection is invalid. 634 *status = 1;
682 * 635 return NULL;
683 * This isn't real useful. 636 }
684 * 637
685 */ 638 if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
686 faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status) 639 faim_mutex_lock(&sess->connlistlock);
687 { 640 for (cur = sess->connlist; cur; cur = cur->next) {
688 int val; 641 if ((FD_ISSET(cur->fd, &fds)) ||
689 642 ((cur->status & AIM_CONN_STATUS_INPROGRESS) &&
690 if (!conn) 643 FD_ISSET(cur->fd, &wfds))) {
691 return -1; 644 *status = 2;
692 645 faim_mutex_unlock(&sess->connlistlock);
693 faim_mutex_lock(&conn->active); 646 return cur; /* XXX race condition here -- shouldnt unlock connlist */
694 val = conn->status ^= status; 647 }
695 faim_mutex_unlock(&conn->active); 648 }
696 649 *status = 0; /* shouldn't happen */
697 return val; 650 } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */
651 *status = 0;
652 else
653 *status = i; /* can be 0 or -1 */
654
655 faim_mutex_unlock(&sess->connlistlock);
656
657 return NULL; /* no waiting or error, return */
698 } 658 }
699 659
700 /** 660 /**
701 * aim_conn_setlatency - Set a forced latency value for connection 661 * aim_conn_setlatency - Set a forced latency value for connection
702 * @conn: Conn to set latency for 662 * @conn: Conn to set latency for
709 * 669 *
710 * XXX: This should really be replaced with something that scales and 670 * XXX: This should really be replaced with something that scales and
711 * backs off like the real rate limiting does. 671 * backs off like the real rate limiting does.
712 * 672 *
713 */ 673 */
714 faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval) 674 faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval)
715 { 675 {
716 if (!conn) 676
717 return -1; 677 if (!conn)
718 678 return -1;
719 faim_mutex_lock(&conn->active); 679
720 conn->forcedlatency = newval; 680 faim_mutex_lock(&conn->active);
721 conn->lastactivity = 0; /* reset this just to make sure */ 681 conn->forcedlatency = newval;
722 faim_mutex_unlock(&conn->active); 682 conn->lastactivity = 0; /* reset this just to make sure */
723 683 faim_mutex_unlock(&conn->active);
724 return 0; 684
685 return 0;
725 } 686 }
726 687
727 /** 688 /**
728 * aim_setupproxy - Configure a proxy for this session 689 * aim_setupproxy - Configure a proxy for this session
729 * @sess: Session to set proxy for 690 * @sess: Session to set proxy for
736 * args, it will clear out a previously set proxy. 697 * args, it will clear out a previously set proxy.
737 * 698 *
738 * Set username and password to %NULL if not applicable. 699 * Set username and password to %NULL if not applicable.
739 * 700 *
740 */ 701 */
741 faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password) 702 faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password)
742 { 703 {
743 /* clear out the proxy info */ 704 /* clear out the proxy info */
744 if (!server || !strlen(server)) { 705 if (!server || !strlen(server)) {
745 memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server)); 706 memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server));
746 memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username)); 707 memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username));
747 memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password)); 708 memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password));
748 return; 709 return;
749 } 710 }
750 711
751 strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server)); 712 strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server));
752 if (username && strlen(username)) 713 if (username && strlen(username))
753 strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username)); 714 strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username));
754 if (password && strlen(password)) 715 if (password && strlen(password))
755 strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password)); 716 strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password));
756 return; 717
757 } 718 return;
758 719 }
759 static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va) 720
760 { 721 static void defaultdebugcb(aim_session_t *sess, int level, const char *format, va_list va)
761 vfprintf(stderr, format, va); 722 {
723
724 vfprintf(stderr, format, va);
725
726 return;
762 } 727 }
763 728
764 /** 729 /**
765 * aim_session_init - Initializes a session structure 730 * aim_session_init - Initializes a session structure
766 * @sess: Session to initialize 731 * @sess: Session to initialize
768 * @debuglevel: Level of debugging output (zero is least) 733 * @debuglevel: Level of debugging output (zero is least)
769 * 734 *
770 * Sets up the initial values for a session. 735 * Sets up the initial values for a session.
771 * 736 *
772 */ 737 */
773 faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags, int debuglevel) 738 faim_export void aim_session_init(aim_session_t *sess, fu32_t flags, int debuglevel)
774 { 739 {
775 if (!sess) 740
776 return; 741 if (!sess)
777 742 return;
778 memset(sess, 0, sizeof(struct aim_session_t)); 743
779 aim_connrst(sess); 744 memset(sess, 0, sizeof(aim_session_t));
780 sess->queue_outgoing = NULL; 745 aim_connrst(sess);
781 sess->queue_incoming = NULL; 746 sess->queue_outgoing = NULL;
782 sess->pendingjoin = NULL; 747 sess->queue_incoming = NULL;
783 sess->pendingjoinexchange = 0; 748 sess->pendingjoin = NULL;
784 aim_initsnachash(sess); 749 sess->pendingjoinexchange = 0;
785 sess->msgcookies = NULL; 750 aim_initsnachash(sess);
786 sess->snac_nextid = 0x00000001; 751 sess->msgcookies = NULL;
787 752 sess->snacid_next = 0x00000001;
788 sess->flags = 0; 753
789 sess->debug = debuglevel; 754 sess->flags = 0;
790 sess->debugcb = defaultdebugcb; 755 sess->debug = debuglevel;
791 756 sess->debugcb = defaultdebugcb;
792 sess->modlistv = NULL; 757
793 758 sess->modlistv = NULL;
794 /* 759
795 * Default to SNAC login unless XORLOGIN is explicitly set. 760 /*
796 */ 761 * Default to SNAC login unless XORLOGIN is explicitly set.
797 if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) 762 */
798 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; 763 if (!(flags & AIM_SESS_FLAGS_XORLOGIN))
799 sess->flags |= flags; 764 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
800 765 sess->flags |= flags;
801 /* 766
802 * This must always be set. Default to the queue-based 767 /*
803 * version for back-compatibility. 768 * This must always be set. Default to the queue-based
804 */ 769 * version for back-compatibility.
805 aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); 770 */
806 771 aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);
807 772
808 /* 773
809 * Register all the modules for this session... 774 /*
810 */ 775 * Register all the modules for this session...
811 aim__registermodule(sess, misc_modfirst); /* load the catch-all first */ 776 */
812 aim__registermodule(sess, buddylist_modfirst); 777 aim__registermodule(sess, misc_modfirst); /* load the catch-all first */
813 aim__registermodule(sess, admin_modfirst); 778 aim__registermodule(sess, buddylist_modfirst);
814 aim__registermodule(sess, bos_modfirst); 779 aim__registermodule(sess, admin_modfirst);
815 aim__registermodule(sess, search_modfirst); 780 aim__registermodule(sess, bos_modfirst);
816 aim__registermodule(sess, stats_modfirst); 781 aim__registermodule(sess, search_modfirst);
817 aim__registermodule(sess, auth_modfirst); 782 aim__registermodule(sess, stats_modfirst);
818 aim__registermodule(sess, msg_modfirst); 783 aim__registermodule(sess, auth_modfirst);
819 aim__registermodule(sess, chatnav_modfirst); 784 aim__registermodule(sess, msg_modfirst);
820 aim__registermodule(sess, chat_modfirst); 785 aim__registermodule(sess, chatnav_modfirst);
821 aim__registermodule(sess, locate_modfirst); 786 aim__registermodule(sess, chat_modfirst);
822 aim__registermodule(sess, general_modfirst); 787 aim__registermodule(sess, locate_modfirst);
823 788 aim__registermodule(sess, general_modfirst);
824 return; 789
790 return;
825 } 791 }
826 792
827 /** 793 /**
828 * aim_session_kill - Deallocate a session 794 * aim_session_kill - Deallocate a session
829 * @sess: Session to kill 795 * @sess: Session to kill
830 * 796 *
831 * 797 */
832 */ 798 faim_export void aim_session_kill(aim_session_t *sess)
833 faim_export void aim_session_kill(struct aim_session_t *sess) 799 {
834 { 800
835 801 aim_logoff(sess);
836 aim_logoff(sess); 802
837 803 aim__shutdownmodules(sess);
838 aim__shutdownmodules(sess); 804
839 805 return;
840 return;
841 } 806 }
842 807
843 /** 808 /**
844 * aim_setdebuggingcb - Set the function to call when outputting debugging info 809 * aim_setdebuggingcb - Set the function to call when outputting debugging info
845 * @sess: Session to change 810 * @sess: Session to change
848 * The function specified is called whenever faimdprintf() is used within 813 * The function specified is called whenever faimdprintf() is used within
849 * libfaim, and the session's debugging level is greater tha nor equal to 814 * libfaim, and the session's debugging level is greater tha nor equal to
850 * the value faimdprintf was called with. 815 * the value faimdprintf was called with.
851 * 816 *
852 */ 817 */
853 faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t cb) 818 faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t cb)
854 { 819 {
855 820
856 if (!sess) 821 if (!sess)
857 return -1; 822 return -1;
858 823
859 sess->debugcb = cb; 824 sess->debugcb = cb;
860 825
861 return 0; 826 return 0;
862 } 827 }
863 828
864 /** 829 /**
865 * aim_conn_isconnecting - Determine if a connection is connecting 830 * aim_conn_isconnecting - Determine if a connection is connecting
866 * @conn: Connection to examine 831 * @conn: Connection to examine
868 * Returns nonzero if the connection is in the process of 833 * Returns nonzero if the connection is in the process of
869 * connecting (or if it just completed and aim_conn_completeconnect() 834 * connecting (or if it just completed and aim_conn_completeconnect()
870 * has yet to be called on it). 835 * has yet to be called on it).
871 * 836 *
872 */ 837 */
873 faim_export int aim_conn_isconnecting(struct aim_conn_t *conn) 838 faim_export int aim_conn_isconnecting(aim_conn_t *conn)
874 { 839 {
875 if (!conn) 840
876 return 0; 841 if (!conn)
877 return (conn->status & AIM_CONN_STATUS_INPROGRESS)?1:0; 842 return 0;
878 } 843
879 844 return !!(conn->status & AIM_CONN_STATUS_INPROGRESS);
880 faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn) 845 }
881 { 846
882 fd_set fds, wfds; 847 /*
883 struct timeval tv; 848 * XXX this is nearly as ugly as proxyconnect().
884 int res, error = ETIMEDOUT; 849 */
885 aim_rxcallback_t userfunc; 850 faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn)
886 851 {
887 if (!conn || (conn->fd == -1)) 852 fd_set fds, wfds;
888 return -1; 853 struct timeval tv;
889 854 int res, error = ETIMEDOUT;
890 if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) 855 aim_rxcallback_t userfunc;
891 return -1; 856
892 857 if (!conn || (conn->fd == -1))
893 FD_ZERO(&fds); 858 return -1;
894 FD_SET(conn->fd, &fds); 859
895 FD_ZERO(&wfds); 860 if (!(conn->status & AIM_CONN_STATUS_INPROGRESS))
896 FD_SET(conn->fd, &wfds); 861 return -1;
897 tv.tv_sec = 0; 862
898 tv.tv_usec = 0; 863 FD_ZERO(&fds);
899 864 FD_SET(conn->fd, &fds);
900 if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { 865 FD_ZERO(&wfds);
901 error = errno; 866 FD_SET(conn->fd, &wfds);
902 aim_conn_close(conn); 867 tv.tv_sec = 0;
903 errno = error; 868 tv.tv_usec = 0;
904 return -1; 869
905 } else if (res == 0) { 870 if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) {
906 faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); 871 error = errno;
907 return 0; /* hasn't really completed yet... */ 872 aim_conn_close(conn);
908 } 873 errno = error;
909 874 return -1;
910 if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { 875 } else if (res == 0) {
911 int len = sizeof(error); 876 faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd);
912 877 return 0; /* hasn't really completed yet... */
913 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) 878 }
914 error = errno; 879
915 } 880 if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
916 881 int len = sizeof(error);
917 if (error) { 882
918 aim_conn_close(conn); 883 if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
919 errno = error; 884 error = errno;
920 return -1; 885 }
921 } 886
922 887 if (error) {
923 fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ 888 aim_conn_close(conn);
924 889 errno = error;
925 conn->status &= ~AIM_CONN_STATUS_INPROGRESS; 890 return -1;
926 891 }
927 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) 892
928 userfunc(sess, NULL, conn); 893 fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
929 894
930 /* Flush out the queues if there was something waiting for this conn */ 895 conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
931 aim_tx_flushqueue(sess); 896
932 897 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE)))
933 return 0; 898 userfunc(sess, NULL, conn);
934 } 899
935 900 /* Flush out the queues if there was something waiting for this conn */
936 faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn) 901 aim_tx_flushqueue(sess);
937 { 902
938 903 return 0;
939 if (!conn) 904 }
940 return NULL; 905
941 906 faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn)
942 return (struct aim_session_t *)conn->sessv; 907 {
908
909 if (!conn)
910 return NULL;
911
912 return (aim_session_t *)conn->sessv;
943 } 913 }
944 914
945 /* 915 /*
946 * aim_logoff() 916 * aim_logoff()
947 * 917 *
948 * Closes -ALL- open connections. 918 * Closes -ALL- open connections.
949 * 919 *
950 */ 920 */
951 faim_export int aim_logoff(struct aim_session_t *sess) 921 faim_export int aim_logoff(aim_session_t *sess)
952 { 922 {
953 923
954 aim_connrst(sess); /* in case we want to connect again */ 924 aim_connrst(sess); /* in case we want to connect again */
955 925
956 return 0; 926 return 0;
957 927
958 } 928 }
959 929