Mercurial > pidgin.yaz
comparison libgaim/protocols/oscar/flap_connection.c @ 15106:b2b0839f57d0
[gaim-migrate @ 17891]
Outgoing message throttling. If we're sending messages too quickly,
and Gaim thinks that sending another message will make AIM give us
a warning, then delay sending the message a little bit.
Currently only activated for IMs. Let me know if you see any problems.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 04 Dec 2006 07:47:50 +0000 |
parents | 525607f86cce |
children | f41cd6f78c60 |
comparison
equal
deleted
inserted
replaced
15105:cb7eef7bf550 | 15106:b2b0839f57d0 |
---|---|
70 aim_tlvlist_free(&tl); | 70 aim_tlvlist_free(&tl); |
71 | 71 |
72 flap_connection_send(conn, frame); | 72 flap_connection_send(conn, frame); |
73 } | 73 } |
74 | 74 |
75 static void | 75 static struct rateclass * |
76 update_rate_class(FlapConnection *conn, guint16 family, guint16 subtype) | 76 flap_connection_get_rateclass(FlapConnection *conn, guint16 family, guint16 subtype) |
77 { | 77 { |
78 GSList *tmp1, *tmp2; | 78 GSList *tmp1, *tmp2; |
79 | 79 |
80 for (tmp1 = conn->rateclasses; tmp1 != NULL; tmp1 = tmp1->next) | 80 for (tmp1 = conn->rateclasses; tmp1 != NULL; tmp1 = tmp1->next) |
81 { | 81 { |
86 { | 86 { |
87 struct snacpair *snacpair; | 87 struct snacpair *snacpair; |
88 snacpair = tmp2->data; | 88 snacpair = tmp2->data; |
89 if ((snacpair->group == family) && (snacpair->subtype == subtype)) | 89 if ((snacpair->group == family) && (snacpair->subtype == subtype)) |
90 { | 90 { |
91 /* | 91 return rateclass; |
92 * We've found the rateclass for this SNAC family | |
93 * and subtype! Update our "current" average by | |
94 * calculating a rolling average. This is pretty | |
95 * shoddy. We should really keep track of the times | |
96 * when the last windowsize messages that were sent | |
97 * and just calculate the REAL average. | |
98 */ | |
99 struct timeval now; | |
100 struct timezone tz; | |
101 unsigned long timediff; /* In milliseconds */ | |
102 | |
103 gettimeofday(&now, &tz); | |
104 timediff = MIN((now.tv_sec - rateclass->last.tv_sec) * 1000 + (now.tv_usec - rateclass->last.tv_usec) / 1000, rateclass->max); | |
105 | |
106 /* This formula is taken from the joscar API docs. */ | |
107 rateclass->current = MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max); | |
108 rateclass->last.tv_sec = now.tv_sec; | |
109 rateclass->last.tv_usec = now.tv_usec; | |
110 | |
111 return; | |
112 } | 92 } |
113 } | 93 } |
114 } | 94 } |
115 } | 95 |
116 | 96 return NULL; |
97 } | |
98 | |
99 /* | |
100 * Attempt to calculate what our new current average would be if we | |
101 * were to send a SNAC in this rateclass at the given time. | |
102 */ | |
103 static guint32 | |
104 rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval now) | |
105 { | |
106 unsigned long timediff; /* In milliseconds */ | |
107 | |
108 timediff = (now.tv_sec - rateclass->last.tv_sec) * 1000 + (now.tv_usec - rateclass->last.tv_usec) / 1000; | |
109 | |
110 /* This formula is taken from the joscar API docs. Preesh. */ | |
111 return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max); | |
112 } | |
113 | |
114 static gboolean flap_connection_send_queued(gpointer data) | |
115 { | |
116 FlapConnection *conn; | |
117 struct timeval now; | |
118 | |
119 conn = data; | |
120 gettimeofday(&now, NULL); | |
121 | |
122 while (conn->queued_snacs != NULL) | |
123 { | |
124 QueuedSnac *queued_snac; | |
125 struct rateclass *rateclass; | |
126 | |
127 queued_snac = conn->queued_snacs->data; | |
128 | |
129 rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype); | |
130 if (rateclass != NULL) | |
131 { | |
132 guint32 new_current; | |
133 | |
134 new_current = rateclass_get_new_current(conn, rateclass, now); | |
135 | |
136 if (new_current < rateclass->alert) | |
137 /* Not ready to send this SNAC yet--keep waiting. */ | |
138 return TRUE; | |
139 | |
140 rateclass->current = new_current; | |
141 rateclass->last.tv_sec = now.tv_sec; | |
142 rateclass->last.tv_usec = now.tv_usec; | |
143 } | |
144 | |
145 flap_connection_send(conn, queued_snac->frame); | |
146 g_free(queued_snac); | |
147 conn->queued_snacs = g_slist_delete_link(conn->queued_snacs, conn->queued_snacs); | |
148 } | |
149 | |
150 conn->outgoing_timeout = 0; | |
151 return FALSE; | |
152 } | |
117 | 153 |
118 /** | 154 /** |
119 * This sends a channel 2 FLAP containing a SNAC. The SNAC family and | 155 * This sends a channel 2 FLAP containing a SNAC. The SNAC family and |
120 * subtype are looked up in the rate info for this connection, and if | 156 * subtype are looked up in the rate info for this connection, and if |
121 * sending this SNAC will induce rate limiting then we delay sending | 157 * sending this SNAC will induce rate limiting then we delay sending |
122 * of the SNAC by putting it into an outgoing holding queue. | 158 * of the SNAC by putting it into an outgoing holding queue. |
159 * | |
160 * @param data The optional bytestream that makes up the data portion | |
161 * of this SNAC. For empty SNACs this should be NULL. | |
123 */ | 162 */ |
124 void | 163 void |
125 flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data) | 164 flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data) |
126 { | 165 { |
127 FlapFrame *frame; | 166 FlapFrame *frame; |
128 guint32 length; | 167 guint32 length; |
168 gboolean enqueue = FALSE; | |
169 struct rateclass *rateclass; | |
129 | 170 |
130 length = data != NULL ? data->offset : 0; | 171 length = data != NULL ? data->offset : 0; |
131 | 172 |
132 frame = flap_frame_new(od, 0x02, 10 + length); | 173 frame = flap_frame_new(od, 0x02, 10 + length); |
133 aim_putsnac(&frame->data, family, subtype, flags, snacid); | 174 aim_putsnac(&frame->data, family, subtype, flags, snacid); |
136 { | 177 { |
137 byte_stream_rewind(data); | 178 byte_stream_rewind(data); |
138 byte_stream_putbs(&frame->data, data, length); | 179 byte_stream_putbs(&frame->data, data, length); |
139 } | 180 } |
140 | 181 |
141 /* TODO: Outgoing message throttling */ | 182 if (conn->outgoing_timeout != 0) |
142 update_rate_class(conn, family, subtype); | 183 enqueue = TRUE; |
184 else if ((rateclass = flap_connection_get_rateclass(conn, family, subtype)) != NULL) | |
185 { | |
186 struct timeval now; | |
187 guint32 new_current; | |
188 | |
189 gettimeofday(&now, NULL); | |
190 new_current = rateclass_get_new_current(conn, rateclass, now); | |
191 | |
192 if (new_current < rateclass->alert) | |
193 { | |
194 enqueue = TRUE; | |
195 } | |
196 else | |
197 { | |
198 rateclass->current = new_current; | |
199 rateclass->last.tv_sec = now.tv_sec; | |
200 rateclass->last.tv_usec = now.tv_usec; | |
201 } | |
202 } | |
203 | |
204 if (enqueue) | |
205 { | |
206 /* We've been sending too fast, so delay this message */ | |
207 QueuedSnac *queued_snac; | |
208 | |
209 queued_snac = g_new(QueuedSnac, 1); | |
210 queued_snac->family = family; | |
211 queued_snac->subtype = subtype; | |
212 queued_snac->frame = frame; | |
213 conn->queued_snacs = g_slist_append(conn->queued_snacs, queued_snac); | |
214 | |
215 if (conn->outgoing_timeout == 0) | |
216 conn->outgoing_timeout = gaim_timeout_add(500, flap_connection_send_queued, conn); | |
217 | |
218 return; | |
219 } | |
143 | 220 |
144 flap_connection_send(conn, frame); | 221 flap_connection_send(conn, frame); |
145 } | 222 } |
146 | 223 |
147 /** | 224 /** |
263 g_free(rateclass->members->data); | 340 g_free(rateclass->members->data); |
264 rateclass->members = g_slist_delete_link(rateclass->members, rateclass->members); | 341 rateclass->members = g_slist_delete_link(rateclass->members, rateclass->members); |
265 } | 342 } |
266 | 343 |
267 free(rateclass); | 344 free(rateclass); |
345 } | |
346 | |
347 /** | |
348 * Free a FlapFrame | |
349 * | |
350 * @param frame The frame to free. | |
351 */ | |
352 static void | |
353 flap_frame_destroy(FlapFrame *frame) | |
354 { | |
355 free(frame->data.data); | |
356 free(frame); | |
268 } | 357 } |
269 | 358 |
270 static gboolean | 359 static gboolean |
271 flap_connection_destroy_cb(gpointer data) | 360 flap_connection_destroy_cb(gpointer data) |
272 { | 361 { |
332 { | 421 { |
333 flap_connection_destroy_rateclass(conn->rateclasses->data); | 422 flap_connection_destroy_rateclass(conn->rateclasses->data); |
334 conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses); | 423 conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses); |
335 } | 424 } |
336 | 425 |
426 while (conn->queued_snacs != NULL) | |
427 { | |
428 QueuedSnac *queued_snac; | |
429 queued_snac = conn->queued_snacs->data; | |
430 flap_frame_destroy(queued_snac->frame); | |
431 g_free(queued_snac); | |
432 conn->queued_snacs = g_slist_delete_link(conn->queued_snacs, conn->queued_snacs); | |
433 } | |
434 if (conn->outgoing_timeout > 0) | |
435 gaim_timeout_remove(conn->outgoing_timeout); | |
436 | |
337 g_free(conn); | 437 g_free(conn); |
338 | 438 |
339 return FALSE; | 439 return FALSE; |
340 } | 440 } |
341 | 441 |
525 | 625 |
526 if (datalen > 0) | 626 if (datalen > 0) |
527 byte_stream_new(&frame->data, datalen); | 627 byte_stream_new(&frame->data, datalen); |
528 | 628 |
529 return frame; | 629 return frame; |
530 } | |
531 | |
532 /** | |
533 * Free a FlapFrame | |
534 * | |
535 * @param frame The frame to free. | |
536 * @return -1 on error; 0 on success. | |
537 */ | |
538 static void | |
539 flap_frame_destroy(FlapFrame *frame) | |
540 { | |
541 free(frame->data.data); | |
542 free(frame); | |
543 | |
544 return; | |
545 } | 630 } |
546 | 631 |
547 static void | 632 static void |
548 parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame) | 633 parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame) |
549 { | 634 { |