]>
Commit | Line | Data |
---|---|---|
9de3ca7e | 1 | /* |
f1a5efe0 | 2 | * aim_rxqueue.c |
3 | * | |
4 | * This file contains the management routines for the receive | |
5 | * (incoming packet) queue. The actual packet handlers are in | |
6 | * aim_rxhandlers.c. | |
9de3ca7e | 7 | */ |
8 | ||
a25832e6 | 9 | #include <faim/aim.h> |
78b3fb13 | 10 | #include <sys/socket.h> |
9de3ca7e | 11 | |
a3619f23 | 12 | /* |
13 | * Since not all implementations support MSG_WAITALL, define | |
14 | * an alternate guarenteed read function... | |
78b3fb13 | 15 | * |
16 | * We keep recv() for systems that can do it because it means | |
17 | * a single system call for the entire packet, where read may | |
18 | * take more for a badly fragmented packet. | |
19 | * | |
a3619f23 | 20 | */ |
5ac21963 | 21 | faim_internal int aim_recv(int fd, void *buf, size_t count) |
a3619f23 | 22 | { |
78b3fb13 | 23 | #ifdef MSG_WAITALL |
a3619f23 | 24 | return recv(fd, buf, count, MSG_WAITALL); |
25 | #else | |
26 | int left, ret, cur = 0; | |
27 | ||
28 | left = count; | |
29 | ||
30 | while (left) { | |
5ac21963 | 31 | ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); |
a3619f23 | 32 | if (ret == -1) |
33 | return -1; | |
34 | if (ret == 0) | |
35 | return cur; | |
36 | ||
37 | cur += ret; | |
38 | left -= ret; | |
39 | } | |
40 | ||
41 | return cur; | |
42 | #endif | |
43 | } | |
44 | ||
9de3ca7e | 45 | /* |
f1a5efe0 | 46 | * Grab a single command sequence off the socket, and enqueue |
47 | * it in the incoming event queue in a seperate struct. | |
a25832e6 | 48 | */ |
78b3fb13 | 49 | faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) |
9de3ca7e | 50 | { |
b69540e3 | 51 | unsigned char generic[6]; |
f1a5efe0 | 52 | struct command_rx_struct *newrx = NULL; |
9de3ca7e | 53 | |
f1a5efe0 | 54 | if (!sess || !conn) |
55 | return 0; | |
9de3ca7e | 56 | |
f1a5efe0 | 57 | if (conn->fd < 3) /* can happen when people abuse the interface */ |
9de3ca7e | 58 | return 0; |
59 | ||
040457cc | 60 | /* |
61 | * Rendezvous (client-client) connections do not speak | |
62 | * FLAP, so this function will break on them. | |
63 | */ | |
b69540e3 | 64 | if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) |
65 | return aim_get_command_rendezvous(sess, conn); | |
7392c79f | 66 | if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) |
67 | return 0; | |
040457cc | 68 | |
f1a5efe0 | 69 | /* |
70 | * Read FLAP header. Six bytes: | |
71 | * | |
72 | * 0 char -- Always 0x2a | |
73 | * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. | |
74 | * 2 short -- Sequence number | |
75 | * 4 short -- Number of data bytes that follow. | |
76 | */ | |
e88ba395 | 77 | faim_mutex_lock(&conn->active); |
a3619f23 | 78 | if (aim_recv(conn->fd, generic, 6) < 6){ |
1a8c261b | 79 | aim_conn_close(conn); |
e88ba395 | 80 | faim_mutex_unlock(&conn->active); |
f1a5efe0 | 81 | return -1; |
82 | } | |
9de3ca7e | 83 | |
b8d0da45 | 84 | /* |
85 | * This shouldn't happen unless the socket breaks, the server breaks, | |
86 | * or we break. We must handle it just in case. | |
87 | */ | |
88 | if (generic[0] != 0x2a) { | |
f1a5efe0 | 89 | faimdprintf(1, "Bad incoming data!"); |
1a8c261b | 90 | aim_conn_close(conn); |
b69540e3 | 91 | faim_mutex_unlock(&conn->active); |
b8d0da45 | 92 | return -1; |
93 | } | |
9de3ca7e | 94 | |
9de3ca7e | 95 | /* allocate a new struct */ |
b69540e3 | 96 | if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) { |
97 | faim_mutex_unlock(&conn->active); | |
f1a5efe0 | 98 | return -1; |
b69540e3 | 99 | } |
f1a5efe0 | 100 | memset(newrx, 0x00, sizeof(struct command_rx_struct)); |
b8d0da45 | 101 | |
f1a5efe0 | 102 | newrx->lock = 1; /* lock the struct */ |
9de3ca7e | 103 | |
b69540e3 | 104 | /* we're doing OSCAR if we're here */ |
105 | newrx->hdrtype = AIM_FRAMETYPE_OSCAR; | |
106 | ||
a25832e6 | 107 | /* store channel -- byte 2 */ |
b69540e3 | 108 | newrx->hdr.oscar.type = (char) generic[1]; |
9de3ca7e | 109 | |
110 | /* store seqnum -- bytes 3 and 4 */ | |
b69540e3 | 111 | newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); |
9de3ca7e | 112 | |
113 | /* store commandlen -- bytes 5 and 6 */ | |
f1a5efe0 | 114 | newrx->commandlen = aimutil_get16(generic+4); |
9de3ca7e | 115 | |
f1a5efe0 | 116 | newrx->nofree = 0; /* free by default */ |
b8d0da45 | 117 | |
9de3ca7e | 118 | /* malloc for data portion */ |
b69540e3 | 119 | if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) { |
f1a5efe0 | 120 | free(newrx); |
b69540e3 | 121 | faim_mutex_unlock(&conn->active); |
f1a5efe0 | 122 | return -1; |
123 | } | |
9de3ca7e | 124 | |
125 | /* read the data portion of the packet */ | |
a3619f23 | 126 | if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ |
f1a5efe0 | 127 | free(newrx->data); |
128 | free(newrx); | |
1a8c261b | 129 | aim_conn_close(conn); |
e88ba395 | 130 | faim_mutex_unlock(&conn->active); |
b8d0da45 | 131 | return -1; |
132 | } | |
e88ba395 | 133 | faim_mutex_unlock(&conn->active); |
9de3ca7e | 134 | |
f1a5efe0 | 135 | newrx->conn = conn; |
9de3ca7e | 136 | |
f1a5efe0 | 137 | newrx->next = NULL; /* this will always be at the bottom */ |
138 | newrx->lock = 0; /* unlock */ | |
9de3ca7e | 139 | |
140 | /* enqueue this packet */ | |
b8d0da45 | 141 | if (sess->queue_incoming == NULL) { |
f1a5efe0 | 142 | sess->queue_incoming = newrx; |
b8d0da45 | 143 | } else { |
144 | struct command_rx_struct *cur; | |
145 | ||
146 | /* | |
147 | * This append operation takes a while. It might be faster | |
148 | * if we maintain a pointer to the last entry in the queue | |
149 | * and just update that. Need to determine if the overhead | |
150 | * to maintain that is lower than the overhead for this loop. | |
151 | */ | |
152 | for (cur = sess->queue_incoming; cur->next; cur = cur->next) | |
153 | ; | |
f1a5efe0 | 154 | cur->next = newrx; |
b8d0da45 | 155 | } |
9de3ca7e | 156 | |
f1a5efe0 | 157 | newrx->conn->lastactivity = time(NULL); |
9de3ca7e | 158 | |
159 | return 0; | |
160 | } | |
161 | ||
162 | /* | |
b8d0da45 | 163 | * Purge recieve queue of all handled commands (->handled==1). Also |
164 | * allows for selective freeing using ->nofree so that the client can | |
165 | * keep the data for various purposes. | |
a25832e6 | 166 | * |
b8d0da45 | 167 | * If ->nofree is nonzero, the frame will be delinked from the global list, |
168 | * but will not be free'ed. The client _must_ keep a pointer to the | |
169 | * data -- libfaim will not! If the client marks ->nofree but | |
170 | * does not keep a pointer, it's lost forever. | |
a25832e6 | 171 | * |
9de3ca7e | 172 | */ |
78b3fb13 | 173 | faim_export void aim_purge_rxqueue(struct aim_session_t *sess) |
9de3ca7e | 174 | { |
b8d0da45 | 175 | struct command_rx_struct *cur = NULL; |
176 | struct command_rx_struct *tmp; | |
9de3ca7e | 177 | |
b8d0da45 | 178 | if (sess->queue_incoming == NULL) |
179 | return; | |
180 | ||
181 | if (sess->queue_incoming->next == NULL) { | |
182 | if (sess->queue_incoming->handled) { | |
183 | tmp = sess->queue_incoming; | |
184 | sess->queue_incoming = NULL; | |
185 | ||
186 | if (!tmp->nofree) { | |
b69540e3 | 187 | if (tmp->hdrtype == AIM_FRAMETYPE_OFT) |
188 | free(tmp->hdr.oft.hdr2); | |
b8d0da45 | 189 | free(tmp->data); |
190 | free(tmp); | |
191 | } else | |
192 | tmp->next = NULL; | |
9de3ca7e | 193 | } |
b8d0da45 | 194 | return; |
195 | } | |
196 | ||
197 | for(cur = sess->queue_incoming; cur->next != NULL; ) { | |
198 | if (cur->next->handled) { | |
199 | tmp = cur->next; | |
200 | cur->next = tmp->next; | |
201 | if (!tmp->nofree) { | |
b69540e3 | 202 | if (tmp->hdrtype == AIM_FRAMETYPE_OFT) |
203 | free(tmp->hdr.oft.hdr2); | |
b8d0da45 | 204 | free(tmp->data); |
205 | free(tmp); | |
206 | } else | |
207 | tmp->next = NULL; | |
208 | } | |
209 | cur = cur->next; | |
210 | ||
211 | /* | |
212 | * Be careful here. Because of the way we just | |
213 | * manipulated the pointer, cur may be NULL and | |
214 | * the for() will segfault doing the check unless | |
215 | * we find this case first. | |
216 | */ | |
217 | if (cur == NULL) | |
218 | break; | |
219 | } | |
220 | ||
221 | return; | |
9de3ca7e | 222 | } |
68ac63c2 | 223 | |
224 | /* | |
225 | * Since aim_get_command will aim_conn_kill dead connections, we need | |
226 | * to clean up the rxqueue of unprocessed connections on that socket. | |
227 | * | |
228 | * XXX: this is something that was handled better in the old connection | |
229 | * handling method, but eh. | |
230 | */ | |
78b3fb13 | 231 | faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn) |
68ac63c2 | 232 | { |
233 | struct command_rx_struct *currx; | |
234 | ||
235 | for (currx = sess->queue_incoming; currx; currx = currx->next) { | |
236 | if ((!currx->handled) && (currx->conn == conn)) | |
237 | currx->handled = 1; | |
238 | } | |
239 | return; | |
240 | } |