comparison libfaim/aim_txqueue.c @ 2:68b230f8da5f

[gaim-migrate @ 11] A few more commits :) committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Thu, 23 Mar 2000 03:16:06 +0000
parents
children 6ced2f1c8b24
comparison
equal deleted inserted replaced
1:2846a03bda67 2:68b230f8da5f
1 /*
2 aim_txqueue.c
3
4 Herein lies all the mangement routines for the transmit (Tx) queue.
5
6 */
7
8 #include "aim.h"
9
10 /*
11 aim_tx_enqeue()
12
13 The overall purpose here is to enqueue the passed in command struct
14 into the outgoing (tx) queue. Basically...
15 1) Make a scope-irrelevent copy of the struct
16 2) Lock the struct
17 3) Mark as not-sent-yet
18 4) Enqueue the struct into the list
19 5) Unlock the struct once it's linked in
20 6) Return
21
22 */
23
24 int aim_tx_enqueue(struct command_tx_struct *newpacket)
25 {
26 struct command_tx_struct *workingPtr = NULL;
27 struct command_tx_struct *newpacket_copy = NULL;
28
29 if (newpacket->conn == NULL)
30 {
31 printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n");
32 newpacket->conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
33 }
34
35 newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
36 memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
37
38 /* assign seqnum */
39 newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn);
40 /* set some more fields */
41 newpacket_copy->lock = 1; /* lock */
42 newpacket_copy->sent = 0; /* not sent yet */
43 newpacket_copy->next = NULL; /* always last */
44
45 if (aim_queue_outgoing == NULL)
46 {
47 aim_queue_outgoing = newpacket_copy;
48 }
49 else
50 {
51 workingPtr = aim_queue_outgoing;
52 while (workingPtr->next != NULL)
53 workingPtr = workingPtr->next;
54 workingPtr->next = newpacket_copy;
55 }
56
57 newpacket_copy->lock = 0; /* unlock so it can be sent */
58
59 #if debug > 2
60 printf("calling aim_tx_printqueue()\n");
61 aim_tx_printqueue();
62 printf("back from aim_tx_printqueue()\n");
63 #endif
64
65 /* we'll force a flush for now -- this behavior probably will change */
66 #if debug > 1
67 printf("calling aim_tx_flushqueue()\n");
68 #endif
69 aim_tx_flushqueue();
70 #if debug > 1
71 printf("back from aim_tx_flushqueue()\n");
72 #endif
73
74 return 0;
75 }
76
77 /*
78 aim_get_next_txseqnum()
79
80 This increments the tx command count, and returns the seqnum
81 that should be stamped on the next FLAP packet sent. This is
82 normally called during the final step of packet preparation
83 before enqueuement (in aim_tx_enqueue()).
84
85 */
86 unsigned int aim_get_next_txseqnum(struct aim_conn_t *conn)
87 {
88 return ( ++conn->seqnum );
89 }
90
91 /*
92 aim_tx_printqueue()
93
94 This is basically for debuging purposes only. It dumps all the
95 records in the tx queue and their current status. Very helpful
96 if the queue isn't working quite right.
97
98 */
99 #if debug > 2
100 int aim_tx_printqueue(void)
101 {
102 struct command_tx_struct *workingPtr = NULL;
103
104 workingPtr = aim_queue_outgoing;
105 #if debug > 2
106 printf("\ncurrent aim_queue_outgoing...\n");
107 printf("\ttype seqnum len lock sent\n");
108 #endif
109 if (workingPtr == NULL)
110 printf("aim_tx_flushqueue(): queue empty");
111 else
112 {
113 while (workingPtr != NULL)
114 {
115 printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent);
116
117 workingPtr = workingPtr->next;
118 }
119 }
120
121 printf("\n(done printing queue)\n");
122
123 return 0;
124 }
125 #endif
126
127 /*
128 aim_tx_flushqueue()
129
130 This the function is responsable for putting the queued commands
131 onto the wire. This function is critical to the operation of
132 the queue and therefore is the most prone to brokenness. It
133 seems to be working quite well at this point.
134
135 Procedure:
136 1) Traverse the list, only operate on commands that are unlocked
137 and haven't been sent yet.
138 2) Lock the struct
139 3) Allocate a temporary buffer to store the finished, fully
140 processed packet in.
141 4) Build the packet from the command_tx_struct data.
142 5) Write the packet to the socket.
143 6) If success, mark the packet sent, if fail report failure, do NOT
144 mark the packet sent (so it will not get purged and therefore
145 be attempted again on next call).
146 7) Unlock the struct.
147 8) Free the temp buffer
148 9) Step to next struct in list and go back to 1.
149
150 */
151 int aim_tx_flushqueue(void)
152 {
153 struct command_tx_struct *workingPtr = NULL;
154 unsigned char *curPacket = NULL;
155 #if debug > 1
156 int i = 0;
157 #endif
158
159 workingPtr = aim_queue_outgoing;
160 #if debug > 1
161 printf("beginning txflush...\n");
162 #endif
163 while (workingPtr != NULL)
164 {
165 /* only process if its unlocked and unsent */
166 if ( (workingPtr->lock == 0) &&
167 (workingPtr->sent == 0) )
168 {
169 workingPtr->lock = 1; /* lock the struct */
170
171 /* allocate full-packet buffer */
172 curPacket = (char *) malloc(workingPtr->commandlen + 6);
173
174 /* command byte */
175 curPacket[0] = 0x2a;
176 /* type/family byte */
177 curPacket[1] = workingPtr->type;
178 /* bytes 3+4: word: FLAP sequence number */
179 curPacket[2] = (char) ( (workingPtr->seqnum) >> 8);
180 curPacket[3] = (char) ( (workingPtr->seqnum) & 0xFF);
181 /* bytes 5+6: word: SNAC len */
182 curPacket[4] = (char) ( (workingPtr->commandlen) >> 8);
183 curPacket[5] = (char) ( (workingPtr->commandlen) & 0xFF);
184 /* bytes 7 and on: raw: SNAC data */
185 memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen);
186
187 /* full image of raw packet data now in curPacket */
188
189 if ( write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
190 {
191 perror("write");
192 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum);
193 workingPtr->sent = 0; /* mark it unsent */
194 return -1; /* bail out */
195 }
196 else
197 {
198 #if debug > 2
199 printf("\nSENT 0x%4x\n\n", workingPtr->seqnum);
200 #endif
201 workingPtr->sent = 1; /* mark the struct as sent */
202 }
203 #if debug > 2
204 printf("\nPacket:");
205 for (i = 0; i < (workingPtr->commandlen + 6); i++)
206 {
207 if ((i % 8) == 0)
208 printf("\n\t");
209 if (curPacket[i] >= ' ' && curPacket[i]<127)
210 printf("%c=%02x ",curPacket[i], curPacket[i]);
211 else
212 printf("0x%2x ", curPacket[i]);
213 }
214 printf("\n");
215 #endif
216 workingPtr->lock = 0; /* unlock the struct */
217 free(curPacket); /* free up full-packet buffer */
218 }
219 workingPtr = workingPtr->next;
220 }
221
222 /* purge sent commands from queue */
223 /* this may not always occur explicitly--i may put this on a timer later */
224 #if debug > 1
225 printf("calling aim_tx_purgequeue()\n");
226 #endif
227 aim_tx_purgequeue();
228 #if debug > 1
229 printf("back from aim_tx_purgequeu() [you must be a lucky one]\n");
230 #endif
231
232 return 0;
233 }
234
235 /*
236 aim_tx_purgequeue()
237
238 This is responsable for removing sent commands from the transmit
239 queue. This is not a required operation, but it of course helps
240 reduce memory footprint at run time!
241
242 */
243 int aim_tx_purgequeue(void)
244 {
245 struct command_tx_struct *workingPtr = NULL;
246 struct command_tx_struct *workingPtr2 = NULL;
247 #if debug > 1
248 printf("purgequeue(): starting purge\n");
249 #endif
250 /* Empty queue: nothing to do */
251 if (aim_queue_outgoing == NULL)
252 {
253 #if debug > 1
254 printf("purgequeue(): purge done (len=0)\n");
255 #endif
256 return 0;
257 }
258 /* One Node queue: free node and return */
259 else if (aim_queue_outgoing->next == NULL)
260 {
261 #if debug > 1
262 printf("purgequeue(): entered case len=1\n");
263 #endif
264 /* only free if sent AND unlocked -- dont assume sent structs are done */
265 if ( (aim_queue_outgoing->lock == 0) &&
266 (aim_queue_outgoing->sent == 1) )
267 {
268 #if debug > 1
269 printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
270 #endif
271 workingPtr2 = aim_queue_outgoing;
272 aim_queue_outgoing = NULL;
273 free(workingPtr2->data);
274 free(workingPtr2);
275 }
276 #if debug > 1
277 printf("purgequeue(): purge done (len=1)\n");
278 #endif
279 return 0;
280 }
281 else
282 {
283 #if debug > 1
284 printf("purgequeue(): entering case len>1\n");
285 #endif
286 while(workingPtr->next != NULL)
287 {
288 if ( (workingPtr->next->lock == 0) &&
289 (workingPtr->next->sent == 1) )
290 {
291 #if debug > 1
292 printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum);
293 #endif
294 workingPtr2 = workingPtr->next;
295 workingPtr->next = workingPtr2->next;
296 free(workingPtr2->data);
297 free(workingPtr2);
298 }
299 }
300 #if debug > 1
301 printf("purgequeue(): purge done (len>1)\n");
302 #endif
303 return 0;
304 }
305
306 /* no reach */
307 }