| |
1 |
| |
2 /* |
| |
3 * aim_conn.c |
| |
4 * |
| |
5 * Does all this gloriously nifty connection handling stuff... |
| |
6 * |
| |
7 */ |
| |
8 |
| |
9 #include "aim.h" |
| |
10 |
| |
11 void aim_connrst(void) |
| |
12 { |
| |
13 int i; |
| |
14 for (i = 0; i < AIM_CONN_MAX; i++) |
| |
15 { |
| |
16 aim_conns[i].fd = -1; |
| |
17 aim_conns[i].type = -1; |
| |
18 aim_conns[i].status = 0; |
| |
19 } |
| |
20 |
| |
21 } |
| |
22 |
| |
23 struct aim_conn_t *aim_conn_getnext(void) |
| |
24 { |
| |
25 int i; |
| |
26 for (i=0;i<AIM_CONN_MAX;i++) |
| |
27 if (aim_conns[i].fd == -1) |
| |
28 return &(aim_conns[i]); |
| |
29 return NULL; |
| |
30 } |
| |
31 |
| |
32 void aim_conn_close(struct aim_conn_t *deadconn) |
| |
33 { |
| |
34 if (deadconn->fd >= 3) |
| |
35 close(deadconn->fd); |
| |
36 deadconn->fd = -1; |
| |
37 deadconn->type = -1; |
| |
38 } |
| |
39 |
| |
40 struct aim_conn_t *aim_getconn_type(int type) |
| |
41 { |
| |
42 int i; |
| |
43 for (i=0; i<AIM_CONN_MAX; i++) |
| |
44 if (aim_conns[i].type == type) |
| |
45 return &(aim_conns[i]); |
| |
46 return NULL; |
| |
47 } |
| |
48 |
| |
49 /* |
| |
50 * aim_newconn(type, dest) |
| |
51 * |
| |
52 * Opens a new connection to the specified dest host of type type. |
| |
53 * |
| |
54 * TODO: fix for proxies |
| |
55 * FIXME: Return errors in a more sane way. |
| |
56 * |
| |
57 */ |
| |
58 struct aim_conn_t *aim_newconn(int type, char *dest) |
| |
59 { |
| |
60 struct aim_conn_t *connstruct; |
| |
61 int ret; |
| |
62 struct sockaddr_in sa; |
| |
63 struct hostent *hp; |
| |
64 int port = FAIM_LOGIN_PORT; |
| |
65 int i=0; |
| |
66 |
| |
67 if (!dest || ((connstruct=aim_conn_getnext())==NULL)) |
| |
68 return NULL; |
| |
69 |
| |
70 connstruct->type = type; |
| |
71 |
| |
72 /* |
| |
73 * As of 23 Jul 1999, AOL now sends the port number, preceded by a |
| |
74 * colon, in the BOS redirect. This fatally breaks all previous |
| |
75 * libfaims. Bad, bad AOL. |
| |
76 * |
| |
77 * We put this here to catch every case. |
| |
78 * |
| |
79 */ |
| |
80 for(i=0;(i<strlen(dest));i++) |
| |
81 if (dest[i] == ':') break; |
| |
82 if (i<strlen(dest)) |
| |
83 { |
| |
84 port = atoi(dest+i); |
| |
85 dest[i] = '\0'; |
| |
86 } |
| |
87 |
| |
88 hp = gethostbyname2(dest, AF_INET); |
| |
89 if (hp == NULL) |
| |
90 { |
| |
91 connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR); |
| |
92 return connstruct; |
| |
93 } |
| |
94 |
| |
95 memset(&sa.sin_zero, 0, 8); |
| |
96 sa.sin_port = htons(port); |
| |
97 memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); |
| |
98 sa.sin_family = hp->h_addrtype; |
| |
99 |
| |
100 connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0); |
| |
101 ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)); |
| |
102 if( ret < 0) |
| |
103 { |
| |
104 connstruct->fd = -1; |
| |
105 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); |
| |
106 return connstruct; |
| |
107 } |
| |
108 |
| |
109 return connstruct; |
| |
110 } |
| |
111 |
| |
112 int aim_conngetmaxfd(void) |
| |
113 { |
| |
114 int i,j; |
| |
115 j=0; |
| |
116 for (i=0;i<AIM_CONN_MAX;i++) |
| |
117 if(aim_conns[i].fd > j) |
| |
118 j = aim_conns[i].fd; |
| |
119 return j; |
| |
120 } |
| |
121 |
| |
122 int aim_countconn(void) |
| |
123 { |
| |
124 int i,cnt; |
| |
125 cnt = 0; |
| |
126 for (i=0;i<AIM_CONN_MAX;i++) |
| |
127 if (aim_conns[i].fd > -1) |
| |
128 cnt++; |
| |
129 return cnt; |
| |
130 } |
| |
131 |
| |
132 /* |
| |
133 * aim_select(timeout) |
| |
134 * |
| |
135 * Waits for a socket with data or for timeout, whichever comes first. |
| |
136 * See select(2). |
| |
137 * |
| |
138 */ |
| |
139 struct aim_conn_t *aim_select(struct timeval *timeout) |
| |
140 { |
| |
141 fd_set fds; |
| |
142 fd_set errfds; |
| |
143 int i; |
| |
144 |
| |
145 if (aim_countconn() <= 0) |
| |
146 return 0; |
| |
147 |
| |
148 FD_ZERO(&fds); |
| |
149 FD_ZERO(&errfds); |
| |
150 |
| |
151 for(i=0;i<AIM_CONN_MAX;i++) |
| |
152 if (aim_conns[i].fd>-1) |
| |
153 { |
| |
154 FD_SET(aim_conns[i].fd, &fds); |
| |
155 FD_SET(aim_conns[i].fd, &errfds); |
| |
156 } |
| |
157 |
| |
158 i = select(aim_conngetmaxfd()+1, &fds, NULL, &errfds, timeout); |
| |
159 if (i>=1) |
| |
160 { |
| |
161 int j; |
| |
162 for (j=0;j<AIM_CONN_MAX;j++) |
| |
163 { |
| |
164 if ((FD_ISSET(aim_conns[j].fd, &errfds))) |
| |
165 { |
| |
166 /* got an exception; close whats left of it up */ |
| |
167 aim_conn_close(&(aim_conns[j])); |
| |
168 return (struct aim_conn_t *)-1; |
| |
169 } |
| |
170 else if ((FD_ISSET(aim_conns[j].fd, &fds))) |
| |
171 return &(aim_conns[j]); /* return the first waiting struct */ |
| |
172 } |
| |
173 /* should never get here */ |
| |
174 } |
| |
175 else |
| |
176 return (struct aim_conn_t *)i; /* no waiting or error, return -- FIXME: return type funnies */ |
| |
177 return NULL; /* NO REACH */ |
| |
178 } |
| |
179 |
| |
180 int aim_conn_isready(struct aim_conn_t *conn) |
| |
181 { |
| |
182 if (conn) |
| |
183 return (conn->status & 0x0001); |
| |
184 else |
| |
185 return -1; |
| |
186 } |
| |
187 |
| |
188 int aim_conn_setstatus(struct aim_conn_t *conn, int status) |
| |
189 { |
| |
190 if (conn) |
| |
191 return (conn->status ^= status); |
| |
192 else |
| |
193 return -1; |
| |
194 } |
| |
195 |