|
- #include <string.h>
-
- #include "btpd.h"
-
- #define CHOKE_INTERVAL (& (struct timeval) { 10, 0 })
-
- static struct event m_choke_timer;
- static unsigned m_npeers;
- static struct peer_tq m_peerq = BTPDQ_HEAD_INITIALIZER(m_peerq);
- static int m_max_uploads;
-
- struct peer_sort {
- struct peer *p;
- unsigned i;
- };
-
- static int
- rate_cmp(const void *arg1, const void *arg2)
- {
- struct peer *p1 = ((struct peer_sort *)arg1)->p;
- struct peer *p2 = ((struct peer_sort *)arg2)->p;
- unsigned long rate1 = cm_full(p1->n->tp) ? p1->rate_up / 2: p1->rate_dwn;
- unsigned long rate2 = cm_full(p2->n->tp) ? p2->rate_up / 2: p2->rate_dwn;
- if (rate1 < rate2)
- return -1;
- else if (rate1 == rate2)
- return 0;
- else
- return 1;
- }
-
- static void
- choke_do(void)
- {
- if (m_max_uploads < 0) {
- struct peer *p;
- BTPDQ_FOREACH(p, &m_peerq, ul_entry)
- if (p->flags & PF_I_CHOKE)
- peer_unchoke(p);
- } else if (m_max_uploads == 0) {
- struct peer *p;
- BTPDQ_FOREACH(p, &m_peerq, ul_entry)
- if ((p->flags & PF_I_CHOKE) == 0)
- peer_choke(p);
- } else {
- struct peer_sort worthy[m_npeers];
- int nworthy = 0;
- int i = 0;
- int found = 0;
- struct peer *p;
- int unchoked[m_npeers];
-
- BTPDQ_FOREACH(p, &m_peerq, ul_entry) {
- int ok = 0;
- if (!peer_full(p)) {
- if (cm_full(p->n->tp)) {
- if (p->rate_up > 0)
- ok = 1;
- } else if (peer_active_down(p) && p->rate_dwn > 0)
- ok = 1;
- }
- if (ok) {
- worthy[nworthy].p = p;
- worthy[nworthy].i = i;
- nworthy++;
- }
- i++;
- }
- qsort(worthy, nworthy, sizeof(worthy[0]), rate_cmp);
-
- bzero(unchoked, sizeof(unchoked));
- for (i = nworthy - 1; i >= 0 && found < m_max_uploads - 1; i--) {
- if ((worthy[i].p->flags & PF_P_WANT) != 0)
- found++;
- if ((worthy[i].p->flags & PF_I_CHOKE) != 0)
- peer_unchoke(worthy[i].p);
- unchoked[worthy[i].i] = 1;
- }
-
- i = 0;
- BTPDQ_FOREACH(p, &m_peerq, ul_entry) {
- if (!unchoked[i]) {
- if (found < m_max_uploads && !peer_full(p)) {
- if (p->flags & PF_P_WANT)
- found++;
- if (p->flags & PF_I_CHOKE)
- peer_unchoke(p);
- } else {
- if ((p->flags & PF_I_CHOKE) == 0)
- peer_choke(p);
- }
- }
- i++;
- }
- }
- }
-
- static void
- shuffle_optimists(void)
- {
- for (int i = 0; i < m_npeers; i++) {
- struct peer *p = BTPDQ_FIRST(&m_peerq);
- if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == (PF_P_WANT|PF_I_CHOKE)) {
- break;
- } else {
- BTPDQ_REMOVE(&m_peerq, p, ul_entry);
- BTPDQ_INSERT_TAIL(&m_peerq, p, ul_entry);
- }
- }
- }
-
- static void
- choke_cb(int sd, short type, void *arg)
- {
- btpd_ev_add(&m_choke_timer, CHOKE_INTERVAL);
- static int cb_count = 0;
- cb_count++;
- if (cb_count % 3 == 0)
- shuffle_optimists();
- choke_do();
- }
-
- void
- ul_on_new_peer(struct peer *p)
- {
- long where = rand_between(-2, m_npeers);
- if (where < 1)
- BTPDQ_INSERT_HEAD(&m_peerq, p, ul_entry);
- else {
- struct peer *it = BTPDQ_FIRST(&m_peerq);
- where--;
- while (where > 0) {
- it = BTPDQ_NEXT(it, ul_entry);
- where--;
- }
- BTPDQ_INSERT_AFTER(&m_peerq, it, p, ul_entry);
- }
- m_npeers++;
- choke_do();
- }
-
- void
- ul_on_lost_peer(struct peer *p)
- {
- assert(m_npeers > 0);
- BTPDQ_REMOVE(&m_peerq, p, ul_entry);
- m_npeers--;
- if ((p->flags & (PF_P_WANT|PF_I_CHOKE)) == PF_P_WANT)
- choke_do();
- }
-
- void
- ul_on_lost_torrent(struct net *n)
- {
- struct peer *p;
- BTPDQ_FOREACH(p, &n->peers, p_entry) {
- BTPDQ_REMOVE(&m_peerq, p, ul_entry);
- m_npeers--;
- }
- choke_do();
- }
-
- void
- ul_on_interest(struct peer *p)
- {
- if ((p->flags & PF_I_CHOKE) == 0)
- choke_do();
- }
-
- void
- ul_on_uninterest(struct peer *p)
- {
- if ((p->flags & PF_I_CHOKE) == 0)
- choke_do();
- }
-
- void
- ul_init(void)
- {
- if (net_max_uploads >= -1)
- m_max_uploads = net_max_uploads;
- else {
- if (net_bw_limit_out == 0)
- m_max_uploads = 8;
- else if (net_bw_limit_out < (10 << 10))
- m_max_uploads = 2;
- else if (net_bw_limit_out < (20 << 10))
- m_max_uploads = 3;
- else if (net_bw_limit_out < (40 << 10))
- m_max_uploads = 4;
- else
- m_max_uploads = 5 + (net_bw_limit_out / (100 << 10));
- }
-
- evtimer_set(&m_choke_timer, choke_cb, NULL);
- btpd_ev_add(&m_choke_timer, CHOKE_INTERVAL);
- }
|