]> andersk Git - libfaim.git/blame - aim_conn.c
close->closesocket for win32, and socket() stupidity in aim_ft.
[libfaim.git] / aim_conn.c
CommitLineData
9de3ca7e 1
2/*
3 * aim_conn.c
4 *
5 * Does all this gloriously nifty connection handling stuff...
6 *
7 */
8
a25832e6 9#include <faim/aim.h>
9de3ca7e 10
67a264ef 11#ifndef _WIN32
78b3fb13 12#include <netdb.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
67a264ef 15#endif
78b3fb13 16
040457cc 17/*
18 * Clears out connection list, killing remaining connections.
19 */
78b3fb13 20faim_internal void aim_connrst(struct aim_session_t *sess)
9de3ca7e 21{
b13c9e13 22 faim_mutex_init(&sess->connlistlock);
040457cc 23 if (sess->connlist) {
24 struct aim_conn_t *cur = sess->connlist, *tmp;
25
26 while(cur) {
27 tmp = cur->next;
28 aim_conn_close(cur);
29 free(cur);
30 cur = tmp;
31 }
e88ba395 32 }
040457cc 33 sess->connlist = NULL;
34 return;
9de3ca7e 35}
36
040457cc 37/*
38 * Gets a new connection structure.
39 */
78b3fb13 40faim_internal struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
9de3ca7e 41{
040457cc 42 struct aim_conn_t *newconn, *cur;
43
44 if (!(newconn = malloc(sizeof(struct aim_conn_t))))
45 return NULL;
46
47 memset(newconn, 0, sizeof(struct aim_conn_t));
48 aim_conn_close(newconn);
49 newconn->next = NULL;
50
51 faim_mutex_lock(&sess->connlistlock);
52 if (sess->connlist == NULL)
53 sess->connlist = newconn;
54 else {
55 for (cur = sess->connlist; cur->next; cur = cur->next)
56 ;
57 cur->next = newconn;
58 }
59 faim_mutex_unlock(&sess->connlistlock);
60
61 return newconn;
62}
63
4d7c1bfb 64static void aim_conn_init(struct aim_conn_t *deadconn)
65{
66 if (!deadconn)
67 return;
68
69 deadconn->fd = -1;
3369f8d4 70 deadconn->subtype = -1;
4d7c1bfb 71 deadconn->type = -1;
72 deadconn->seqnum = 0;
73 deadconn->lastactivity = 0;
74 deadconn->forcedlatency = 0;
75 deadconn->handlerlist = NULL;
76 deadconn->priv = NULL;
b13c9e13 77 faim_mutex_init(&deadconn->active);
78 faim_mutex_init(&deadconn->seqnum_lock);
4d7c1bfb 79
80 return;
81}
82
78b3fb13 83faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn)
040457cc 84{
85 struct aim_conn_t *cur;
86
87 if (!deadconn || !*deadconn)
88 return;
89
90 faim_mutex_lock(&sess->connlistlock);
91 if (sess->connlist == NULL)
92 ;
93 else if (sess->connlist->next == NULL) {
94 if (sess->connlist == *deadconn)
95 sess->connlist = NULL;
96 } else {
97 cur = sess->connlist;
98 while (cur->next) {
99 if (cur->next == *deadconn) {
100 cur->next = cur->next->next;
101 break;
102 }
103 cur = cur->next;
104 }
105 }
106 faim_mutex_unlock(&sess->connlistlock);
107
68ac63c2 108 /* XXX: do we need this for txqueue too? */
109 aim_rxqueue_cleanbyconn(sess, *deadconn);
110
f8ac5020 111 aim_conn_close(*deadconn);
112 if ((*deadconn)->priv)
113 free((*deadconn)->priv);
040457cc 114 free(*deadconn);
115 deadconn = NULL;
116
117 return;
9de3ca7e 118}
119
78b3fb13 120faim_export void aim_conn_close(struct aim_conn_t *deadconn)
9de3ca7e 121{
3369f8d4 122 int typesav = -1, subtypesav = -1;
123 void *privsav = NULL;
4d7c1bfb 124
125 faim_mutex_destroy(&deadconn->active);
126 faim_mutex_destroy(&deadconn->seqnum_lock);
9de3ca7e 127 if (deadconn->fd >= 3)
128 close(deadconn->fd);
0252e8c0 129 if (deadconn->handlerlist)
130 aim_clearhandlers(deadconn);
3369f8d4 131
132 typesav = deadconn->type;
133 subtypesav = deadconn->subtype;
134
135 if (deadconn->priv && (deadconn->type != AIM_CONN_TYPE_RENDEZVOUS)) {
0c20631f 136 free(deadconn->priv);
3369f8d4 137 deadconn->priv = NULL;
138 }
139 privsav = deadconn->priv;
140
4d7c1bfb 141 aim_conn_init(deadconn);
142
143 deadconn->type = typesav;
3369f8d4 144 deadconn->subtype = subtypesav;
145 deadconn->priv = privsav;
4d7c1bfb 146
147 return;
9de3ca7e 148}
149
78b3fb13 150faim_internal struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
151 int type)
9de3ca7e 152{
040457cc 153 struct aim_conn_t *cur;
154
155 faim_mutex_lock(&sess->connlistlock);
156 for (cur = sess->connlist; cur; cur = cur->next) {
157 if (cur->type == type)
158 break;
159 }
160 faim_mutex_unlock(&sess->connlistlock);
161 return cur;
9de3ca7e 162}
163
164/*
165 * aim_newconn(type, dest)
166 *
167 * Opens a new connection to the specified dest host of type type.
168 *
169 * TODO: fix for proxies
170 * FIXME: Return errors in a more sane way.
171 *
172 */
78b3fb13 173faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess,
174 int type, char *dest)
9de3ca7e 175{
176 struct aim_conn_t *connstruct;
177 int ret;
178 struct sockaddr_in sa;
179 struct hostent *hp;
180 u_short port = FAIM_LOGIN_PORT;
a25832e6 181 char *host = NULL;
9de3ca7e 182 int i=0;
040457cc 183
e6b05d80 184 if ((connstruct=aim_conn_getnext(sess))==NULL)
9de3ca7e 185 return NULL;
186
040457cc 187 faim_mutex_lock(&connstruct->active);
188
9de3ca7e 189 connstruct->type = type;
190
e6b05d80 191 if (!dest) { /* just allocate a struct */
192 connstruct->fd = -1;
193 connstruct->status = 0;
040457cc 194 faim_mutex_unlock(&connstruct->active);
e6b05d80 195 return connstruct;
196 }
197
9de3ca7e 198 /*
199 * As of 23 Jul 1999, AOL now sends the port number, preceded by a
200 * colon, in the BOS redirect. This fatally breaks all previous
201 * libfaims. Bad, bad AOL.
202 *
203 * We put this here to catch every case.
204 *
205 */
206
5ac21963 207 for(i=0;i<(int)strlen(dest);i++) {
e88ba395 208 if (dest[i] == ':') {
209 port = atoi(&(dest[i+1]));
210 break;
9de3ca7e 211 }
e88ba395 212 }
a25832e6 213 host = (char *)malloc(i+1);
214 strncpy(host, dest, i);
9ba272ca 215 host[i] = '\0';
216
040457cc 217 hp = gethostbyname(host);
a25832e6 218 free(host);
9de3ca7e 219
e88ba395 220 if (hp == NULL) {
221 connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR);
040457cc 222 faim_mutex_unlock(&connstruct->active);
e88ba395 223 return connstruct;
224 }
9de3ca7e 225
226 memset(&sa.sin_zero, 0, 8);
227 sa.sin_port = htons(port);
228 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
229 sa.sin_family = hp->h_addrtype;
230
231 connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
232 ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
e88ba395 233 if(ret < 0) {
234 connstruct->fd = -1;
235 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
040457cc 236 faim_mutex_unlock(&connstruct->active);
e88ba395 237 return connstruct;
238 }
a25832e6 239
040457cc 240 faim_mutex_unlock(&connstruct->active);
241
9de3ca7e 242 return connstruct;
243}
244
78b3fb13 245faim_export int aim_conngetmaxfd(struct aim_session_t *sess)
9de3ca7e 246{
040457cc 247 int j = 0;
248 struct aim_conn_t *cur;
249
250 faim_mutex_lock(&sess->connlistlock);
251 for (cur = sess->connlist; cur; cur = cur->next) {
252 if (cur->fd > j)
253 j = cur->fd;
254 }
255 faim_mutex_unlock(&sess->connlistlock);
e88ba395 256
9de3ca7e 257 return j;
258}
259
78b3fb13 260static int aim_countconn(struct aim_session_t *sess)
9de3ca7e 261{
040457cc 262 int cnt = 0;
263 struct aim_conn_t *cur;
264
265 faim_mutex_lock(&sess->connlistlock);
266 for (cur = sess->connlist; cur; cur = cur->next)
267 cnt++;
268 faim_mutex_unlock(&sess->connlistlock);
e88ba395 269
9de3ca7e 270 return cnt;
271}
272
273/*
274 * aim_select(timeout)
275 *
276 * Waits for a socket with data or for timeout, whichever comes first.
277 * See select(2).
278 *
b8d0da45 279 * Return codes in *status:
280 * -1 error in select() (NULL returned)
281 * 0 no events pending (NULL returned)
282 * 1 outgoing data pending (NULL returned)
283 * 2 incoming data pending (connection with pending data returned)
284 *
040457cc 285 * XXX: we could probably stand to do a little courser locking here.
286 *
9de3ca7e 287 */
78b3fb13 288faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess,
289 struct timeval *timeout, int *status)
9de3ca7e 290{
040457cc 291 struct aim_conn_t *cur;
9de3ca7e 292 fd_set fds;
040457cc 293 int maxfd = 0;
9de3ca7e 294 int i;
295
040457cc 296 faim_mutex_lock(&sess->connlistlock);
297 if (sess->connlist == NULL) {
298 faim_mutex_unlock(&sess->connlistlock);
68ac63c2 299 *status = -1;
300 return NULL;
040457cc 301 }
302 faim_mutex_unlock(&sess->connlistlock);
f1a5efe0 303
9de3ca7e 304 /*
305 * If we have data waiting to be sent, return immediatly
306 */
b8d0da45 307 if (sess->queue_outgoing != NULL) {
308 *status = 1;
309 return NULL;
310 }
9de3ca7e 311
312 FD_ZERO(&fds);
040457cc 313 maxfd = 0;
314
315 faim_mutex_lock(&sess->connlistlock);
316 for (cur = sess->connlist; cur; cur = cur->next) {
317 FD_SET(cur->fd, &fds);
318 if (cur->fd > maxfd)
319 maxfd = cur->fd;
320 }
321 faim_mutex_unlock(&sess->connlistlock);
322
323 if ((i = select(maxfd+1, &fds, NULL, NULL, timeout))>=1) {
324 faim_mutex_lock(&sess->connlistlock);
325 for (cur = sess->connlist; cur; cur = cur->next) {
326 if (FD_ISSET(cur->fd, &fds)) {
327 *status = 2;
328 faim_mutex_unlock(&sess->connlistlock);
329 return cur;
330 }
331 }
9797852c 332 *status = 0; /* shouldn't happen */
333 } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */
334 *status = 0;
335 else
336 *status = i; /* can be 0 or -1 */
b8d0da45 337
040457cc 338 faim_mutex_unlock(&sess->connlistlock);
b8d0da45 339 return NULL; /* no waiting or error, return */
9de3ca7e 340}
341
78b3fb13 342faim_export int aim_conn_isready(struct aim_conn_t *conn)
9de3ca7e 343{
344 if (conn)
345 return (conn->status & 0x0001);
040457cc 346 return -1;
9de3ca7e 347}
348
78b3fb13 349faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status)
9de3ca7e 350{
040457cc 351 int val;
352
353 if (!conn)
9de3ca7e 354 return -1;
040457cc 355
356 faim_mutex_lock(&conn->active);
357 val = conn->status ^= status;
358 faim_mutex_unlock(&conn->active);
359 return val;
9de3ca7e 360}
361
78b3fb13 362faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
9de3ca7e 363{
364 if (!conn)
365 return -1;
040457cc 366
367 faim_mutex_lock(&conn->active);
9de3ca7e 368 conn->forcedlatency = newval;
369 conn->lastactivity = 0; /* reset this just to make sure */
040457cc 370 faim_mutex_unlock(&conn->active);
9de3ca7e 371
372 return 0;
373}
a25832e6 374
78b3fb13 375faim_export void aim_session_init(struct aim_session_t *sess)
a25832e6 376{
a25832e6 377 if (!sess)
378 return;
379
040457cc 380 memset(sess, 0, sizeof(struct aim_session_t));
e88ba395 381 aim_connrst(sess);
a25832e6 382 sess->queue_outgoing = NULL;
383 sess->queue_incoming = NULL;
0c20631f 384 sess->pendingjoin = NULL;
b13c9e13 385 aim_initsnachash(sess);
a25832e6 386 sess->snac_nextid = 0x00000001;
387
e88ba395 388 /*
389 * This must always be set. Default to the queue-based
390 * version for back-compatibility.
391 */
392 sess->tx_enqueue = &aim_tx_enqueue__queuebased;
393
a25832e6 394 return;
395}
This page took 4.267743 seconds and 5 git commands to generate.