| 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 /** |