// vim600:fdm=marker #include "cygwin.h" #include "sFile.h" #include "cSocket.h" #include "sTag.h" #include "db_macro.h" #ifdef __cplusplus extern "C" { #endif #include "md4.h" #ifdef __cplusplus } #endif #include "donkey.h" #include "misc.h" #include "opcodes.h" // zlib stream handling {{{ void* zalloc (void *, unsigned items, unsigned size) { return MALLOC(items*size); } void zfree (void *,void * ptr) { free(ptr); } z_stream *init_Infalte (void) {{{ z_stream *ZIP = reinterpret_cast(MALLOC (sizeof(z_stream))); ZIP->zalloc = zalloc; ZIP->zfree = zfree; ZIP->opaque = NULL; ZIP->avail_in = 0; ZIP->avail_out = 0; ZIP->total_in = 0; ZIP->total_out = 0; int err = inflateInit(ZIP); if (err != Z_OK) { free (ZIP); return NULL; } return ZIP; }}} z_stream *ende_Infalte (z_stream *ZIP) {{{ if (ZIP == NULL) return NULL; int err = inflateEnd(ZIP); if (err != Z_OK) printf("ende_Infalte FAILED\n"); Free2 (ZIP); return NULL; }}} int Infalte (z_stream *ZIP,char *in, int in_cnt, char *out, int *out_cnt) {{{ // ZIP zlib stream buffer // in := Buffer that contain compressed data // in_cnt := Size of the Buffer // out := Buffer for decompressed data // out_cnt := Size used in the decompressed buffer ZIP->next_in = reinterpret_cast(in); ZIP->avail_in = in_cnt; ZIP->next_out = reinterpret_cast(out); ZIP->avail_out = *out_cnt; int err = inflate(ZIP, Z_NO_FLUSH); if (err != Z_OK && err != Z_STREAM_END) {{{ out_cnt = 0; printf("ZIP Err %i\n", err); return -1; }}} int done = (*out_cnt) - ZIP->avail_out; (*out_cnt) = done; return in_cnt - ZIP->avail_in; }}} // }}} uint32_t IP4Name(const char *host) {{{ struct in_addr ip; // struct sockaddr_in *sa = NULL; ip.s_addr = 0; #ifdef HAVE_GETADDRINFO struct addrinfo *addr = NULL; int err = getaddrinfo (host, NULL, NULL, &addr); if (err != 0) return 0; if (addr->ai_family != PF_INET) return 0; // Normaly i should check all entry's ip = reinterpret_cast(addr->ai_addr)->sin_addr; if (addr != NULL) freeaddrinfo(addr); return ip.s_addr; #elif HAVE_GETHOSTBYNAME // I think getaddrinfo checks for ip string, so we only need this for gethostbyname #ifdef HAVE_INET_ADDR if (inet_addr(host) != 0xFFFFFFFF) return inet_addr(host); #elif HAVE_INET_ATON if (inet_aton(host, &ip) ) return ip.s_addr; #elif HAVE_INET_PTON if (inet_pton(AF_INET, host, &ip)>0) return ip.s_addr; #endif struct hostent *hostent = gethostbyname(host); if (hostent == NULL) return 0; if (hostent->h_addrtype != PF_INET) return 0; // Normaly i should check all entry's ip = *((struct in_addr*) hostent->h_addr_list[0]); return ip.s_addr; // sa = (struct sockaddr_in *)hostent->h_addr_list[0]; // return sa->sin_addr.s_addr; #else printf("ERROR: no getaddrinfo or gethostbyname: Cannot resolve HOSTNAME's !!!\n"); return 0; #endif }}} // Hash Conversion {{{ const unsigned char *md4(char *txt, size_t len) {{{ static unsigned char hash[MD4_DIGEST_LENGTH]; if (txt == NULL) return NULL; MD4_CTX ctx; MD4Init (&ctx); MD4Update (&ctx, reinterpret_cast(txt), len); MD4Final (hash, &ctx); return hash; // Binary }}} /// Returns a pointer (to a statically allocated buffer) in which the 32 chars /// wide string representation of the given hash resides. Subsequent calls will /// overwrite the buffer. /// @param hash the hash to bring into textual representation const unsigned char *hash_bin2hex (const unsigned char *hash) {{{ const unsigned char hexdigits[] = "0123456789abcdef"; static unsigned char m_hash_str[33]; for (int j=0; j<16; j++) { m_hash_str[(j<<1) ] = hexdigits[(((hash[j]) & 0xf0) >> 4)]; m_hash_str[(j<<1)+1] = hexdigits[(((hash[j]) & 0x0f) )]; } return m_hash_str; }}} const unsigned char *hash_hex2bin (const char *hash_str) {{{ static unsigned char m_hash[16]; int val; const char* str = hash_str; for (int i = 0; i < 16; i++) { if( (val = HexDigit2Int(*str++)) < 0 ) break; m_hash[i] = (unsigned char) val << 4; if( (val = HexDigit2Int(*str++)) < 0 ) break; m_hash[i] |= (unsigned char) val; } return m_hash; }}} // }}} int cmp_u32(DB *, const DBT *A, const DBT *B) {{{ uint32_t *a = reinterpret_cast(A->data); uint32_t *b = reinterpret_cast(B->data); if (*a > *b) return 1; if (*a < *b) return -1; return 0; }}} // ---------------------------- IP CHECK --------------------------- // {{{ Block list of IP's DB *ip_block = NULL; DBC *ip_block_cur = NULL; struct sIP_range { unsigned von; unsigned bis; unsigned val; }; void read_IP_list(const char *name) {{{ int err = 0; if (ip_block == NULL) {{{ DB_create (ip_block); DB_set_alloc(ip_block); DB_set_bt_compare2 (ip_block ,cmp_u32); DB_open2 ( ip_block, NULL, NULL, DB_BTREE, DB_CREATE, 0); }}} FILE *fip = fopen (name, "r"); if (fip == NULL) {{{ printf("Can not read IP list!\n"); return; }}} char buf[512]; char ip_von[16]; char ip_bis[16]; char ip_val[ 4]; ip_von[15]=0; ip_bis[15]=0; ip_val[ 3]=0; unsigned ip_key = 0; struct sIP_range range; INIT_DBT(key, &ip_key , sizeof(ip_key)); INIT_DBT(val, &range , sizeof(range )); while (0 < fgets(buf, 512, fip)) { buf[511] = 0; if (0 < sscanf(buf, "%15s - %15s , %3s , %*s", ip_von, ip_bis, ip_val)) { range.von = (atol(ip_von+0)<<24)+(atol(ip_von+4)<<16)+(atol(ip_von+8)<< 8)+atol(ip_von+12); range.bis = (atol(ip_bis+0)<<24)+(atol(ip_bis+4)<<16)+(atol(ip_bis+8)<< 8)+atol(ip_bis+12); range.val = atol(ip_val); ip_key = 0xFFFFFFFF - range.von; // DB sortiert 0.Byte 1.Byte (set range >= wir wollen aber <=) DB_put2 (ip_block, key, val); } } fclose(fip); }}} void IP_block(struct in_addr ip) { int err = 0; struct sIP_range range; uint32_t KEY = 0xFFFFFFFF - htonl(ip.s_addr); range.von = htonl(ip.s_addr); range.bis = htonl(ip.s_addr); range.val = 0; INIT_DBT(key, &KEY , sizeof(KEY )); INIT_DBT(val, &range, sizeof(range)); DB_put2 (ip_block, key, val); } bool IP_is_OK(struct in_addr ip) {{{ static unsigned count_all = 0; static unsigned count_bad = 0; uint32_t IP = htonl (ip.s_addr); if (0x00000000 == (IP & 0x0000FFFF)) return false; // aaa.bbb.0.0 if (0x00000000 == (IP & 0xFF000000)) return false; if (0x7F000000 == (IP & 0xFF000000)) return false; if (0xE0000000 == (IP & 0xF0000000)) return false; // Spezial USE never valid if (0xF0000000 == (IP & 0xF0000000)) return false; // MCAST nevervalid if (ip.s_addr == cSocket::getLocalExternalIP().s_addr) return false; // context should be taken into account if (ip.s_addr == cSocket::getLocalInternalIP().s_addr) return false; if (ip_block == NULL) return true; count_all ++; int err = 0; if (ip_block_cur == NULL) DB_cursor2 (ip_block, ip_block_cur); unsigned KEY = 0; KEY = 0xFFFFFFFF - IP; struct sIP_range range; INIT_DBT(key, &KEY , sizeof(KEY )); INIT_DBT(val, &range, sizeof(range)); if (0 != (err = ip_block_cur->c_get (ip_block_cur, &key, &val, DB_SET_RANGE))) {{{ if (err != DB_NOTFOUND) DB_error(); //printf("DEBUG 0: ip not in block %15s\n", inet_ntoa(ip)); return true; }}} if (IP < range.von || IP > range.bis) {{{ printf("DEBUG 1: ip not in block %15s\n", inet_ntoa(ip)); KEY = 0xFFFFFFFF - IP; range.von = htonl(ip.s_addr); range.bis = htonl(ip.s_addr); range.von &= 0xFFFFFF00; range.bis &= 0xFFFFFF00; range.bis += 255; range.val = pref.ip_trash + 1; DB_put2 (ip_block, key, val); return true; }}} if (range.val > pref.ip_trash) return true; count_bad ++; if (range.val == 127) return false; // Private netspace if (range.val == 11) return false; // IANA reserved printf("DEBUG: ip alert %15s is mark as bad.level %u (%u/%u)\n", inet_ntoa(ip), range.val, count_all, count_bad); return false; }}} void ende_IP_list(void) {{{ int err = 0; if(ip_block_cur != NULL) { DB_c_close(ip_block_cur); ip_block_cur = NULL; } DB_close2 (ip_block); }}} // }}} // ---------------------------- IP CHECK --------------------------- int cmp_20 (DB *, const DBT *A, const DBT *B) {{{ return memcmp(A->data, B->data, 20); }}} int key_src_time(DB *, const DBT *, const DBT *pdata, DBT *skey) {{{ bzero (skey, sizeof(DBT)); skey->data=( & (reinterpret_cast(pdata->data)->next_time)); skey->size=(sizeof(((reinterpret_cast(pdata->data)->next_time)))); return 0; }}} int key_dat_ip (DB *, const DBT *, const DBT *pdata, DBT *skey) {{{ bzero (skey, sizeof(DBT)); skey->data=( & (reinterpret_cast(pdata->data)->ip)); skey->size=(sizeof((reinterpret_cast(pdata->data)->ip))); return 0; }}} int key_dat_hash(DB *, const DBT *, const DBT *pdata, DBT *skey) {{{ bzero (skey, sizeof(DBT)); skey->data=( & (reinterpret_cast(pdata->data))->hash); skey->size=(sizeof((reinterpret_cast(pdata->data))->hash)); return 0; }}} // B+Tree IP suche {IDX,IP} IDX => Entry in one Table void db_warn (const char *file, int line, int err) {{{ printf("\n\n%s %i DB: %5i %s\n\n", file, line, err, db_strerror(err)); }}} void db_error (const char *file, int line, int err) {{{ printf("\n\n%s %i DB: %5i %s\n\n", file, line, err, db_strerror(err)); fflush(stdout); abort(); }}} DB *src_ip = NULL; DB *src_time = NULL; DB *srv_ip = NULL; DB *srv_next = NULL; DB *srv_ping = NULL; DB *dat_idx = NULL; DB *dat_hash = NULL; DB *dat_ip = NULL; DBC *c0 = NULL; DBC *c1 = NULL; DBC *c2 = NULL; void dbSync (void) {{{ if (src_ip == NULL) return; static time_t next = 0; if(next >= currentTime) return; next = currentTime + 60; if (src_ip != NULL) src_ip->sync(src_ip, 0); }}} int cursor_count = 0; void open_Sources (void) {{{ int err = 0; if (src_ip != NULL) return; DB_create(src_ip ); // Open Primary (IP) DB_create(src_time); // Open secondary (TIME) DB_create(dat_idx ); // Open Primary (IP) DB_create(dat_hash); // Open Primary (IP) DB_create(dat_ip ); // Open secondary (TIME) DB_set_alloc(src_ip ); DB_set_alloc(src_time); DB_set_alloc(dat_idx ); DB_set_alloc(dat_hash); DB_set_alloc(dat_ip ); src_ip ->set_errfile(src_ip , stdout); src_time->set_errfile(src_time, stdout); DB_set_bt_compare2 (src_time ,cmp_u32); DB_set_bt_compare2 (dat_idx ,cmp_20 ); DB_set_flags2 (dat_hash, DB_DUP | DB_DUPSORT); DB_set_flags2 (dat_ip , DB_DUP | DB_DUPSORT); DB_set_flags2 (src_time, DB_DUP | DB_DUPSORT); DB_open2 (src_ip , db_client , "source_lst", DB_BTREE, DB_CREATE, 0600); printf("DB_client %s\n", db_client); DB_open2 (dat_idx , NULL, NULL, DB_BTREE, DB_CREATE, 0); DB_open2 (dat_hash, NULL, NULL, DB_BTREE, DB_CREATE, 0); DB_open2 (dat_ip , NULL, NULL, DB_BTREE, DB_CREATE, 0); DB_open2 (src_time, NULL, NULL, DB_BTREE, DB_CREATE, 0); // Associate secondary indexes with primary index DB_associate2 (src_ip , src_time, key_src_time); DB_associate2 (dat_idx, dat_hash, key_dat_hash); DB_associate2 (dat_idx, dat_ip , key_dat_ip ); uint32_t ip = 0; #define BUFFER_LENGTH (5 * 1024 * 1024) char *buffer = reinterpret_cast(MALLOC (BUFFER_LENGTH)); INIT_DBT(key, &ip , sizeof(ip)); INIT_DBT(val, buffer, BUFFER_LENGTH); DBC *cur = NULL; DB_cursor2 (src_ip, cur); while (0 == cur->c_get (cur, &key, &val, DB_MULTIPLE_KEY|DB_NEXT)) {{{ void *p = NULL; struct eSources *tmp = NULL; DBT m_key; DBT m_val; DB_MULTIPLE_INIT(p, &val); for(;;) { DB_MULTIPLE_KEY_NEXT(p, &val, m_key.data, m_key.size, m_val.data, m_val.size); if (p == NULL) break; tmp = reinterpret_cast(m_val.data); tmp->aktive = 0; INIT_DBT(key_set, &tmp->ip, sizeof(tmp->ip)); INIT_DBT(val_set, tmp , sizeof(struct eSources)); DB_put2 (src_ip, key_set, val_set); } }}} DB_c_close(cur); Free2 (buffer); }}} void close_Sources (void) {{{ if (src_ip == NULL) return; int err = 0; if (c0 != NULL) DB_c_close(c0); if (c2 != NULL) DB_c_close(c2); if (dat_idx != NULL) DB_close2 (dat_idx ); dat_idx = NULL; if (src_ip != NULL) DB_close2 (src_ip ); src_ip = NULL; if (dat_hash != NULL) DB_close2 (dat_hash); dat_hash = NULL; if (dat_ip != NULL) DB_close2 (dat_ip ); dat_ip = NULL; if (src_time != NULL) DB_close2 (src_time); src_time = NULL; c0 = NULL; }}} unsigned countBtree (DB *db) {{{ if (db == NULL) return 0; int err; DB_BTREE_STAT *statistik; DB_stat(db, statistik); uint32_t ret = statistik->bt_nkeys; free (statistik); return ret; }}} // { {{ Source Liste void Update_src (struct eSources *s) {{{ if (src_ip == NULL) return; in_addr ip = s->ip; int err = 0; INIT_DBT(key, &ip, sizeof(ip)); INIT_DBT(val, s , sizeof(struct eSources)); DB_put2 (src_ip, key, val); }}} void Delete_src (struct in_addr IP) {{{ if (src_ip == NULL) return; int err = 0; INIT_DBT(key, &IP, sizeof(IP)); DB_del2 (src_ip, key); }}} eSources *Source_ip (struct in_addr IP) {{{ if (src_ip == NULL) { if (running) printf("WARNING src_ip = NULL\n"); return NULL; } struct in_addr ip = IP; static struct eSources tmp; bzero (&tmp, sizeof(tmp)); INIT_DBT(key, &ip , sizeof(ip )); INIT_DBT(val, &tmp, sizeof(tmp)); int err = 0; if (0 != (err = DB_get (src_ip, key, val))) { if (DB_NOTFOUND != err) DB_error(); return NULL; } return &tmp; }}} time_t addSource (struct in_addr IP, uint16_t PORT, unsigned VER, bool usefull) {{{ if (usefull) ASSERT(usefull); if (htonl(IP.s_addr) <= 0x00FFFFFF) { printf("REJECT(0) IP %s\n", inet_ntoa(IP)); return currentTime + 3600; } if ((IP.s_addr & 0x000000FF) == 0 ) { printf("REJECT(1) IP %s\n", inet_ntoa(IP)); return currentTime + 3600; } if ((IP.s_addr & 0xFF000000) == 0 ) { return currentTime + 3600; printf("REJECT(2) IP %s\n", inet_ntoa(IP)); } if (!IP_is_OK(IP)) { printf("REJECT(3) IP %s\n", inet_ntoa(IP)); return currentTime + 3600; } struct eSources tmp; struct eSources *s = Source_ip (IP); if (s == NULL) { s = &tmp; bzero (s, sizeof(struct eSources)); s->ip = IP; s->next_time = 0; s->prio = 1; s->ratio = 0; s->aktive = 0; s->version = 0; s->udp_port = 0; log (2,"ADD source %15s\n", inet_ntoa(IP)); } else { memcpy(&tmp, s, sizeof(tmp)); s = &tmp; } s->port = PORT; s->version = VER; Update_src (s); dbSync (); return s->next_time; }}} void delSource (struct in_addr IP, int err) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; time_t zeit = 0; switch (err) { case 0 : zeit = currentTime + 60 * 10; break; case 101 : zeit = currentTime + 60 * 60; break; // net unreachable case 104 : zeit = currentTime + 60 * 3; break; // reset by peer case 110 : zeit = currentTime + 60 * 10; break; // timeout case 111 : zeit = currentTime + 60 * 10; break; // refused case 113 : zeit = currentTime + 60 * 30; break; // no Route case -3 : zeit = currentTime + 60 * 30; break; // protocol error default : zeit = currentTime + 60 * 60; printf("DELETE source ground %4i\n", err); break; } s->next_time = zeit; ASSERT(0); Update_src (s); }}} bool getSource (in_addr *ip, unsigned short *port) {{{ // DB_DBT_USERMEM; static time_t next = 0; static int fresh = 0; if (next >= currentTime) return false; bzero (ip, sizeof(in_addr)); *port = 0; fresh++; if ((fresh % 1000) == 0) { printf("SOURCE: 1000 refresh pool\n"); return false; } int err = 0; struct eSources tmp; bzero (&tmp, sizeof(tmp)); time_t zeit = 0; INIT_DBT(key, &zeit, sizeof(zeit)); INIT_DBT(val, &tmp , sizeof(tmp )); DBC *c3 = NULL; DB_cursor2 (src_time, c3); while (0 == (err = c3->c_get (c3, &key, &val, DB_NEXT))) {{{ // search next source for connect ASSERT(sizeof(tmp ) == val.size); ASSERT(sizeof(zeit) == key.size); uint16_t s_port = tmp.port; if (tmp.next_time >= currentTime) { // sortiert !!! next = tmp.next_time; DB_c_close(c3); char zeit_tmp[101]; strftime(zeit_tmp, 100, "%m-%d %H:%M.%S", gmtime(&tmp.next_time)); printf("SOURCE: no current timeouted source %15s => %s\n", inet_ntoa(tmp.ip), zeit_tmp); return false; } if (s_port == 0 ) { Delete_src (tmp.ip); continue; } if (!IP_is_OK(tmp.ip)) { Delete_src (tmp.ip); continue; } if (tmp.aktive > 0) continue; if (tmp.ratio < -PARTSIZE) continue; bool use = false; { FILE_LIST { if (akt->status == ALL_DONE || akt->Pause() ) continue; if (NULL == File_idx (akt->hash, tmp.ip)) continue; use = true; } } if (!use) { tmp.next_time = currentTime + 600; Update_src(&tmp); continue; } *ip = tmp.ip; *port = s_port; log (2,"GET source %15s cur: %s t: %s", inet_ntoa(*ip), currentTime_str, ctime(&tmp.next_time)); tmp.next_time = currentTime + 600; Update_src(&tmp); DB_c_close(c3); log (1, "getSource_from_File (%s,%u) OK nextTime %s\n",inet_ntoa(*ip),*port, currentTime_str); if (*port == 0) { printf("SOURCE: 0 port in pool\n"); return false; } printf("SOURCE: using %15s\n", inet_ntoa(*ip)); return true; }}} if (err != DB_NOTFOUND) DB_error(); DB_c_close(c3); // printf("SOURCE: none used from pool\n"); return false; }}} unsigned cntSource (void) {{{ int err = 0; DB_BTREE_STAT *statistik; DB_stat(src_ip, statistik); uint32_t ret = statistik->bt_nkeys; free (statistik); return ret; }}} void setSource_timeout (struct in_addr IP, time_t zeit) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; s->next_time = zeit; Update_src (s); }}} /* Does not Change the order */ void chgSources_ratio (struct in_addr IP, long ratio ) {{{ printf("Change Source Ratio "); struct eSources *s = Source_ip (IP); if (s == NULL) { printf("Source not found\n"); return; } printf("Change done\n"); s->ratio += ratio; ASSERT(0); Update_src (s); return; }}} void setSources_aktive (struct in_addr IP) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; s->aktive++; Update_src (s); }}} void setSources_version(struct in_addr IP, int version) {{{ struct eSources *s = Source_ip (IP); struct eSources tmp; if (s == NULL) { s = &tmp; bzero (s, sizeof(struct eSources)); s->ip = IP; s->prio = 1; s->ratio = 0; s->aktive = 0; } s->version = version; Update_src (s); return; }}} void setSources_udp (struct in_addr IP, uint16_t u) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; s->udp_port = u; Update_src (s); }}} void setSources_hash_dl(struct in_addr IP, uint8_t *h) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; memcpy(s->hash_dl, h, 16); Update_src (s); }}} void setSources_hash (struct in_addr IP, uint8_t *h) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; memcpy(s->hash, h, 16); Update_src (s); }}} int cntSources_aktive (struct in_addr IP) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return 0; return s->aktive; }}} void endSources_aktive (struct in_addr IP) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return; if (s->aktive <= 0) return; s->aktive--; Update_src (s); }}} long getSources_ratio (struct in_addr IP) {{{ struct eSources *s = Source_ip (IP); if (s == NULL) return 0; return s->ratio; }}} // } }} // {{{ Server liste static void Update_srv (const struct eServers *s) {{{ struct eServers u; memcpy (&u, s, sizeof(struct eServers)); struct in_addr ip = u.ip; int err = 0; INIT_DBT(key, &ip, sizeof(ip)); INIT_DBT(val, &u , sizeof(u )); DB_put2 (srv_ip, key, val); dbSync (); }}} void cServer_list::Save(void) {{{ size_t count = countBtree(srv_ip); if (count == 0) return; size_t len, LEN = len = count * 400; unsigned char *buf, *BUF = buf = reinterpret_cast(MALLOC(LEN)); ADD_U1 (&buf, &len, 0xE0); ADD_U4 (&buf, &len, count); struct eServers tmp; time_t zeit = 0; int err = 0; INIT_DBT(key, &zeit, sizeof(time_t)); INIT_DBT(val, &tmp , sizeof(struct eServers)); DBC *c = NULL; DB_cursor2 (srv_next, c); while (0 == (err = c->c_get (c, &key, &val, DB_NEXT))) { count--; ADD_U4 (&buf, &len, tmp.ip.s_addr); ADD_U2 (&buf, &len, tmp.port); unsigned char *cnt_idx = buf; size_t cnt_len = len; size_t tag_count = 0; ADD_U4 (&buf, &len, 0); if (0 != strlen(tmp.name)) { add_strTag(&buf, &len, ST_SERVERNAME , tmp.name ); tag_count++; } if (0 != strlen(tmp.desc)) { add_strTag(&buf, &len, ST_DESCRIPTION, tmp.desc ); tag_count++; } add_intTag(&buf, &len, ST_LASTPING , tmp.last_ping); tag_count++; add_intTag(&buf, &len, ST_PREFERENCE , tmp.prio ); tag_count++; add_intTag(&buf, &len, ST_FAIL , tmp.ping_fail); tag_count++; add_intTag(&buf, &len, ST_LONG_USERS , tmp.user ); tag_count++; add_intTag(&buf, &len, ST_LONG_FILES , tmp.file ); tag_count++; add_intTag(&buf, &len, ST_MAXUSERS , tmp.user_max ); tag_count++; ADD_U4 (&cnt_idx, &cnt_len, tag_count); } DB_c_close(c); if (count != 0) printf("Wrong count %u\n", count); int fd = FD_create ("server.met.new", O_WRONLY|O_BINARY|O_TRUNC|O_CREAT,0600); if (fd == -1) {{{ printf ("server.met.new not open\n"); free (BUF); return; }}} len = LEN - len; buf = BUF; FD_WRITE2 (fd, buf, len); free(BUF); if (close (fd)) printf("close server.met failed\n"); remove("server.met.old"); if(rename("server.met", "server.met.old")) printf("old server.met was not saved\n"); if(rename("server.met.new", "server.met")) printf("new server.met was not saved\n"); }}} void cServer_list::Load(void) {{{ size_t len, LEN = len = 0; unsigned char *buf, *BUF = buf = file("server.met", &LEN); len = LEN; if (BUF == NULL) return; uint8_t version = GET_U1(&buf, &len); if (version != 0xE0) { free(BUF); return; } struct eServers server; server.id = 0; server.name[31] = 0; server.desc[63] = 0; server.padding = 0; for (size_t count = GET_U4 (&buf, &len); count > 0; count--) { server.ip.s_addr = GET_U4 (&buf, &len); server.port = GET_U2 (&buf, &len); size_t cnt = len; class sTag *tag = parse_tag (buf, &cnt); buf += cnt; len -= cnt; server.name[0] = 0; server.desc[0] = 0; if (tag->name != NULL) strncpy(server.name, tag->name, 31); if (tag->desc != NULL) strncpy(server.desc, tag->desc, 63); server.user = tag->users; server.file = tag->files; server.user_max = tag->users_max; server.next_time = 0; server.last_action = 0; server.prio = tag->pref; server.last_ping = tag->last_ping; server.ping_fail = tag->fail; Update_srv (&server); delete tag; } free (BUF); }}} unsigned cntServer (void) {{{ int err; DB_BTREE_STAT *statistik; DB_stat(srv_ip, statistik); uint32_t ret = statistik->bt_nkeys; free (statistik); return ret; }}} int key_srv_next(DB *, const DBT *, const DBT *pdata, DBT *skey) {{{ bzero (skey, sizeof(DBT)); skey->data=( & (reinterpret_cast(pdata->data))->next_time); skey->size=(sizeof((reinterpret_cast(pdata->data))->next_time)); return 0; }}} int key_srv_ping(DB *, const DBT *, const DBT *pdata, DBT *skey) {{{ bzero (skey, sizeof(DBT)); skey->data=( & (reinterpret_cast(pdata->data))->last_ping); skey->size=(sizeof((reinterpret_cast(pdata->data))->last_ping)); return 0; }}} void open_Servers (void) {{{ int err = 0; if (srv_ip != NULL) return; DB_create(srv_ip ); // Open Primary (IP) DB_create(srv_next); // Open secondary (TIME) DB_create(srv_ping); // Open secondary (PING) if (0 != (err = srv_next->set_flags(srv_next, DB_DUP | DB_DUPSORT))) DB_error(); if (0 != (err = srv_ping->set_flags(srv_ping, DB_DUP | DB_DUPSORT))) DB_error(); DB_set_alloc(srv_ip); DB_set_alloc(srv_next); DB_set_alloc(srv_ping); DB_set_bt_compare2 (srv_next ,cmp_u32); DB_set_bt_compare2 (srv_ping ,cmp_u32); DB_open2 (srv_ip , NULL, NULL, DB_BTREE, DB_CREATE, 0); DB_open2 (srv_next, NULL, NULL, DB_BTREE, DB_CREATE, 0); DB_open2 (srv_ping, NULL, NULL, DB_BTREE, DB_CREATE, 0); // Associate secondary indexes with primary index DB_associate2 (srv_ip, srv_next, key_srv_next); DB_associate2 (srv_ip, srv_ping, key_srv_ping); }}} void close_Servers (void) {{{ cServer_list::Save (); if (srv_ip == NULL) return; int err = 0; if (c1 != NULL) DB_c_close(c1); c1 = NULL; if (srv_ip != NULL) DB_close2 (srv_ip ); srv_ip = NULL; if (srv_next != NULL) DB_close2 (srv_next); srv_next = NULL; if (srv_ping != NULL) DB_close2 (srv_ping); srv_ping = NULL; }}} void Delete_srv (in_addr ip) {{{ int err = 0; log (2, "final del server %15s\n", inet_ntoa(ip) ); INIT_DBT(key, &ip, sizeof(ip)); DB_del2 (srv_ip, key); dbSync (); }}} struct eServers *Server_ip (struct in_addr IP) {{{ if (!running) return NULL; if (srv_ip == NULL) { printf("WARNING srv_ip = NULL\n"); return NULL; } struct in_addr ip = IP; static struct eServers tmp; bzero (&tmp, sizeof(tmp)); INIT_DBT(val, &tmp , sizeof(tmp )); INIT_DBT(key, &ip , sizeof(ip )); int err = 0; if (0 != (err = DB_get (srv_ip, key, val))) { if (DB_NOTFOUND != err) DB_error(); return NULL; } return reinterpret_cast(val.data); }}} void delServer (in_addr IP, uint16_t , int err) {{{ // NEW struct eServers *s = Server_ip (IP); time_t zeit = currentTime + 90; if (s == NULL) return; switch (err) { case 104 : zeit = currentTime + 180; break; // connection reset by peer case 111 : zeit = currentTime + 180; break; // connection refused by peer case -4 : zeit = currentTime + 600; strncpy(s->desc, "unwanted", 64); s->desc[63] = 0; break; case -7 : Delete_srv(IP); return; default : printf("del server %15s cause %4i\n", inet_ntoa(IP), err); break; } s->ping_fail++; s->next_time = zeit; Update_srv (s); return; }}} // true: valid ip/port found , else false bool nextServer (struct in_addr *ip, uint16_t *port) {{{ ip->s_addr = 0; *port = 0; int err = 0; struct eServers tmp; time_t zeit = 0; INIT_DBT(key, &zeit, sizeof(time_t)); INIT_DBT(val, &tmp , sizeof(struct eServers)); DBC *c = NULL; DB_cursor2 (srv_next, c); while (0 == (err = c->c_get (c, &key, &val, DB_NEXT))) {{{ // find the server we next ry to connect ASSERT(val.size == sizeof(struct eServers)); uint16_t s_port = tmp.port; // Delete server if we got 10 errors : adjust variable ? if (tmp.ping_fail > 10) { Delete_srv (tmp.ip); continue; } if (s_port == 0) { Delete_srv (tmp.ip); continue; } if (0 == strcmp (tmp.desc, "unwanted")) continue; DB_c_close(c); if (tmp.next_time >= currentTime) { log (1, "nextServer: All servers exhausted. Trying next one in %li seconds.\n", tmp.next_time-currentTime ); return false; // sortiert !!! } *ip = tmp.ip; *port = s_port; tmp.next_time = currentTime + 60; tmp.ping_fail ++; Update_srv(&tmp); log (1, "1 USE %15s t: %10lu \n", inet_ntoa(*ip), (tmp.next_time - currentTime) ); return true; }}} if (err != DB_NOTFOUND) DB_error(); DB_c_close(c); return false; }}} const struct eServers *nextServers(bool first) {{{ int err; static struct eServers tmp; static uint32_t ip; INIT_DBT(val, &tmp, sizeof(tmp)); INIT_DBT(key, &ip , sizeof(ip )); if (c1 == NULL) { if (!first) return NULL; DB_cursor2 (srv_ip, c1); bzero (&tmp, sizeof(tmp)); ip = 0; // RESET_DBT(key, &ip , sizeof(ip )); if (0 != (err = c1->c_get (c1, &key, &val, DB_FIRST))) { if (err != DB_NOTFOUND) DB_error(); return NULL; } return reinterpret_cast(val.data); } if (0 != (err = c1->c_get (c1, &key, &val, (first)?DB_FIRST:DB_NEXT))) { if (err != DB_NOTFOUND) DB_error(); DB_c_close(c1); c1 = NULL; return NULL; } return reinterpret_cast(val.data); }}} bool saveServer (struct in_addr ip, uint16_t port,unsigned int files,unsigned int user, bool gui) {{{ // SQL-Enabled if ((ip.s_addr & 0xFF000000) == 0) return false; if ((ip.s_addr & 0x000000FF) == 0) return false; if (!IP_is_OK (ip)) return false; if (port == 4665) port = 4661; ASSERT (port != 4665); struct eServers tmp; struct eServers *s = Server_ip (ip); bool neu = false; if (s == NULL || gui) {{{ s = &tmp; bzero (s, sizeof(struct eServers)); s->id = 0; // Currently unused s->ip = ip; s->port = port; s->next_time = currentTime - 1; // server is available to be tested. s->name[0] = 0; s->desc[0] = 0; s->user = user; s->file = files; s->user_max = user; s->file_max = files; s->prio = 1; // s->last_action IMMER s->ping_fail = 0; s->last_ping = 0; neu = true; }}} else { if (files>0 || user>0) { s->user = user; s->file = files; if (s->user_max < user ) s->user_max = user ; if (s->file_max < files) s->file_max = files; } if (port != 0) s->port = port; } s->last_action = currentTime - 120; Update_srv (s); return true; }}} bool actionServer (struct in_addr ip, uint16_t) {{{ struct eServers *s = Server_ip (ip); if (s == NULL) return false; s->ping_fail = 0; s->next_time = currentTime + 600; s->last_ping = currentTime + 60; s->last_action = currentTime; Update_srv (s); return true; }}} bool setServer_name (struct in_addr ip, uint16_t, const char *name) {{{ struct eServers *s = Server_ip (ip); if (s == NULL) return false; s->last_ping = currentTime + 60; s->next_time = currentTime + 60; s->ping_fail = 0; s->last_action = currentTime; strncpy (s->name, name, 32); s->name[31] = 0; Update_srv (s); return true; }}} bool setServer_desc (struct in_addr ip, uint16_t, const char *desc) {{{ struct eServers *s = Server_ip (ip); if (s == NULL) return false; s->last_ping = currentTime + 60; s->next_time = currentTime + 60; s->last_action = currentTime; s->ping_fail = 0; strncpy (s->desc, desc, 64); s->desc[63] = 0; Update_srv (s); return true; }}} bool setServer_prio (struct in_addr ip, uint16_t, uint8_t prio) {{{ struct eServers *s = Server_ip (ip); if (s == NULL) return false; s->prio = prio; Update_srv (s); return true; }}} bool pongServer (struct in_addr ip) {{{ struct eServers *s = Server_ip (ip); if (s == NULL) return false; s->last_action = currentTime; s->ping_fail = 0; s->last_action = currentTime; s->last_ping = currentTime + 120; if (s->next_time > currentTime - 120) s->next_time = currentTime - 120; Update_srv (s); return true; }}} bool nextPing (struct in_addr *ip, uint16_t *port, uint32_t *challange) {{{ // DB_DBT_USERMEM ASSERT(ip != NULL); *challange = currentTime; ip->s_addr = 0; *port = 0; if (srv_ping == NULL) return false; int err = 0; struct eServers tmp; bzero (&tmp, sizeof(tmp)); time_t zeit = currentTime; INIT_DBT(key, &zeit, sizeof(zeit)); INIT_DBT(val, &tmp , sizeof(tmp)); DBC *c = NULL; DB_cursor2 (srv_ping, c); while (0 == (err = c->c_get (c, &key, &val, DB_NEXT))) { struct eServers *s = reinterpret_cast(val.data); if (s->last_action + 180 >= currentTime) continue; // only ping when needed if (s->last_ping >= currentTime) { // sortiert !!! DB_c_close(c); return false; } if (0 == (s->ip.s_addr & 0xFF000000) || 0 == (s->ip.s_addr & 0x000000FF)) { Delete_srv (s->ip); continue; } if (!IP_is_OK(s->ip)) { Delete_srv (s->ip); continue; } *ip = s->ip; *port = s->port; log (1, "PING %15s ping/action: %10lu/%10lu c:%s\n", inet_ntoa(*ip), currentTime- s->last_ping,currentTime- s->last_action, currentTime_str); s->ping_fail++; s->last_ping = currentTime + s->ping_fail * 10; Update_srv(s); DB_c_close(c); return true; } if (err != DB_NOTFOUND) DB_error(); DB_c_close(c); return false; }}} // }}} // {{{ Files liste void insertFiles(tHash &hash, in_addr ip, size_t info_len, const unsigned char *info) {{{ int err = 0; size_t len = info_len + sizeof(eFiles) - 1; struct eFiles *i = reinterpret_cast(MALLOC (len)); memcpy(i->hash, hash, sizeof(tHash)); char idx[20]; memcpy(idx + 0, hash, 16); memcpy(idx + 16, &ip , 4); i->ip.s_addr = ip.s_addr; i->info_len = info_len; i->since = currentTime; if (info_len > 0) { ASSERT(info != NULL); memcpy(i->info, info, info_len); } INIT_DBT(key, idx, 20); INIT_DBT(val, i, len); DB_put2 (dat_idx, key, val); Free2 (i); }}} void deleteFiles_ip (in_addr ip) {{{ int err = 0; INIT_DBT(key, &ip, sizeof(ip)); DB_del2 (dat_ip, key); }}} void deleteFiles_hash(char *hash) {{{ int err = 0; INIT_DBT(key, hash, 16); DB_del2 (dat_hash, key); }}} unsigned cntFiles (void) {{{ int err; DB_BTREE_STAT *statistik; DB_stat(dat_idx, statistik); uint32_t ret = statistik->bt_nkeys; free (statistik); return ret; }}} const struct eFiles *nextFile (const tHash &hash, bool first) {{{ static DBT key; // DB_DBT_USERMEM static DBT val; // should be handeld static char Hash[16]; static bool first_run = true; if (first_run) { first_run = false; bzero (&val, sizeof(val)); } int err; if (first) {{{ if (c0 != NULL) DB_c_close (c0); DB_cursor2 (dat_hash, c0); memcpy (Hash, hash, 16); RESET_DBT(key, Hash, 16); if (0 != (err = c0->c_get (c0, &key, &val, DB_SET_RANGE))) {{{ cursor_count = 0; if (err != DB_NOTFOUND) DB_error(); return NULL; }}} db_recno_t rec_count; c0->c_count (c0, &rec_count, 0); cursor_count = rec_count; return reinterpret_cast(val.data); }}} if (c0 == NULL) return NULL; if (0 != (err = c0->c_get (c0, &key, &val, DB_NEXT_DUP))) {{{ if (err != DB_NOTFOUND) DB_error(); DB_c_close (c0); c0 = NULL; return NULL; }}} return reinterpret_cast(val.data); }}} struct eFiles *File_idx (tHash &hash, struct in_addr ip) {{{ static bool first_run = true; static DBT val; if (first_run) { first_run = false; bzero (&val, sizeof(val)); } int err = 0; char idx[20]; memcpy(idx + 0, hash, 16); memcpy(idx + 16, &ip , 4); INIT_DBT(key, idx, 20); if (0 != (err = DB_get (dat_idx, key, val))) { if (DB_NOTFOUND != err && DB_PAGE_NOTFOUND != err) DB_error(); return NULL; } return reinterpret_cast(val.data); }}} // }}} void misc_init(void) {{{ read_IP_list ("ip.prefix"); open_Sources (); open_Servers (); }}} #define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) static char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" "????????????????????????????????????????????????????????????????" "????????????????????????????????????????????????????????????????" "???????????"; static char index_64[128] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; bool encode64(const char *_in, size_t inlen, char *_out, size_t outmax, size_t *outlen) {{{ const unsigned char *in = reinterpret_cast(_in); unsigned char *out = reinterpret_cast(_out); size_t olen = (inlen + 2) / 3 * 4; // Will it fit? if (outlen != NULL) *outlen = olen; if (outmax < olen) return false; // Do the work... while (inlen >= 3) { // user provided max buffer size; make sure we don't go over it *out++ = basis_64[in[0] >> 2]; *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)]; *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; *out++ = basis_64[in[2] & 0x3f]; in += 3; inlen -= 3; } if (inlen > 0) { // user provided max buffer size; make sure we don't go over it unsigned char oval = (in[0] << 4) & 0x30; *out++ = basis_64[in[0] >> 2]; if (inlen > 1) oval |= in[1] >> 4; *out++ = basis_64[oval]; *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c]; *out++ = '='; } if (olen < outmax) *out = '\0'; return true; }}} bool decode64(const char * in, size_t inlen, char * out, size_t *outlen) {{{ size_t len = 0,lup; int v1, v2, c3, c4; if (out == NULL) return false; // check parameters if (in[0] == '+' && in[1] == ' ') in += 2; // xxx these necessary? if (*in == '\r') return false; for (lup=0;lup> 4); ++len; if (c3 != '=') { *out++ = ((CHAR64(v2) << 4) & 0xf0) | (CHAR64(c3) >> 2); ++len; if (c4 != '=') { *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4); ++len; } } } *out=0; // terminate string *outlen=len; return true; }}}