/** \brief The benc_get_string function deserializes a btSring from the stream 'bts' using the BEncoding scheme. \param bts a parameter of type struct btStream* \param s a parameter of type btString * \return int 0 - success, 1 - some error */ int benc_get_string( struct btStream* bts, btString *s) { int res; char ibuf[10]; char *sbuf; int slen; res = bts_scanbreak( bts, "0123456789", ":", ibuf, sizeof(ibuf)); if (res) return res; slen= atoi(ibuf); bt_assert(slen<MAXSTRING); sbuf = btmalloc(slen+1); bt_assert(sbuf); if (slen > 0) { res = bts_read( bts, sbuf, slen); } else if (slen < 0) { errno = BTERR_NEGATIVE_STRING_LENGTH; res = -1; } else { *sbuf = 0; res = 0; } if (res) { btfree(sbuf); return res; } sbuf[slen]=0; btString_setbuf(s, sbuf, slen); return 0; }
int kStringBuffer_grow( kStringBuffer *sb, int len) { sb->bufsize += len; sb->buf = btrealloc( sb->buf, sb->bufsize); bt_assert(sb->buf); return 0; }
int btFileSet_addfile( btFileSet *fs, const char *path, _int64 len) { int ifile=fs->nfiles++; btFile *f; fs->file = btrealloc(fs->file, sizeof(btFile *)*fs->nfiles); bt_assert(fs->file); f=btcalloc(1,sizeof(btFile)); bt_assert(f); f->path = strdup(path); f->len = len; if (ifile > 0) { btFile *lf = fs->file[ifile-1]; f->start = lf->start + lf->len; } fs->file[ifile]=f; return 0; }
btDictIt* btDictIt_create( btDictIt *buf, btDict *d) { if (!buf) { buf = btmalloc( sizeof(btDictIt)); bt_assert(buf); } memset(buf, 0, sizeof(btDictIt)); buf->d = d; return buf; }
/* * Return 0 if continue downloading * Return 1 if block complete */ int seg_writebuf( btFileSet *fs, int piece, int offset, char *buf, int len) { int res=0; int blocksize; btPartialPiece *p=fs->partial; while(p && p->piecenumber!=piece) { p=p->next; } if (!p) { //printf("got extra packet %d, offset %d\n", piece, offset); return 0; } blocksize = seg_piecelen( fs, piece); bt_assert(offset>=0 && offset<blocksize && offset+len<=blocksize && len>0); memcpy(p->buffer + offset, buf, len); bs_setRange( &p->filled, offset, offset+len); #if 0 printf("packet %d of %d, offset %d, blocksize %d\n", piece, fs->npieces, offset, blocksize); #endif if ( p->isdone || bs_isFull( &p->filled)) { /* last data for this piece */ p->isdone=1; if (_checkhash( fs, piece, p->buffer)) { /* Remove from partial list */ btPartialPiece *pp=fs->partial; if(pp==p) { /* First in list */ fs->partial=p->next; } else { while(pp->next != p) pp=pp->next; pp->next=p->next; } fs->dl += blocksize; fs->left -= blocksize; #if 0 printf("hash ok for block %d\n", piece); #endif if( seg_write( fs, p) < 0 ) return -1; kBitSet_finit( &p->filled); btfree(p); res = 1; } else { //printf("hash bad for block %d\n", piece); } } return res; }
/* the list takes ownership of the object v */ int btList_add( btList *_this, btObject *v) { int idx = _this->len++; bt_assert(_this->parent.t == BT_LIST); if (idx >= _this->listsize) { int newsize = QUANTIZE(idx+1); _this->list = btrealloc( _this->list, sizeof(*_this->list)*newsize); _this->listsize = newsize; } _this->list[idx] = v; return 0; }
int sbtail( kStringBuffer *sb, int start_char) { bt_assert( start_char >= 0 && start_char <= sb->cpos); if (start_char == 0) return 0; if (start_char < sb->cpos) { memmove( sb->buf, sb->buf + start_char, sb->cpos - start_char); } sb->cpos -= start_char; sb->buf[sb->cpos] = 0; return 0; }
void CTorrent::init( const void* data, size_t size ) { int res; int optseed = 0; char* optignore = NULL; m_pMetaData = data; m_nMetaSize = size; btStream *io; io = bts_create_strstream( BTS_OUTPUT ); bt_assert( io ); res = bts_write( io, (char*)data, size ); bt_assert( res == 0 ); res = ctx_loadfile( io, &m_Context, (char*)m_szDownloadDir, optseed, optignore); bts_destroy( io ); if (res < 0) { notify("Bad torrent"); return; } m_nState = STATE_STOPPED; notify("Torrent loaded"); }
int sbcat( kStringBuffer *sb, char *str, int len) { bt_assert( len >= 0); if (sb->cpos + len >= sb->bufsize) { kStringBuffer_grow( sb, max( len+1, 1024)); if (!sb->buf) return -1; } memcpy(sb->buf + sb->cpos, str, len); sb->cpos += len; sb->buf[sb->cpos] = 0; return 0; }
int seg_readbuf( btFileSet *fs, kBitSet *writeCache, int piece, int start, char *buf, int len) { btFile *f; _int64 addr = ((_int64)piece * fs->blocksize)+start; int ifile; if (!bs_isSet(writeCache, piece) && !bs_isSet(&fs->completed, piece)) { //printf("Attempted to read uncompleted block %d from disk.\n", piece); return -1; } for (ifile=0; ifile < fs->nfiles; ifile++) { f=fs->file[ifile]; if ( f->start+f->len >= addr && f->start < addr + len) { /* this file (partly) includes this piece */ int fd = cacheopen( f->path, O_RDONLY, 0); off_t fpos = addr - f->start; _int64 rlen; _int64 beg = 0; ssize_t res; if (fd == -1) { bts_perror(errno, "readbuf.cacheopen"); return -1; } if (fpos < 0) { beg = -fpos; fpos = 0; } rlen = min(f->len - fpos, len - beg); if (lseek( fd, fpos, SEEK_SET) != fpos) { bts_perror(errno, "readbuf.read"); return -1; } bt_assert( rlen <= fs->blocksize); res = read(fd, buf+beg, rlen); if (res != rlen) { if (res == 0) { /* EOF */ return -1; } bts_perror(errno, "readbuf.read"); return -1; } } } return 0; }
int seg_piecelen( btFileSet *fs, int piece) { int blocklen; blocklen = fs->blocksize; if (piece == fs->npieces-1) { /* last block may be short */ _int64 modulus = fs->tsize % (_int64)fs->blocksize; if (modulus) blocklen = (int)modulus; } bt_assert(piece>=0 && piece<fs->npieces); return blocklen; }
btFileSet* btFileSet_create( btFileSet *fs, int npieces, int blocksize, const char *hashbuf) { if (!fs) { fs = btcalloc( 1, sizeof(btFileSet)); bt_assert(fs); } fs->npieces = npieces; fs->blocksize = blocksize; fs->dl = 0; fs->ul = 0; fs->hashes = btmalloc( npieces * SHA_DIGEST_LENGTH); memcpy(fs->hashes, hashbuf, npieces * SHA_DIGEST_LENGTH); kBitSet_create(&fs->completed, npieces); return fs; }
BT_TEST_FIXTURE(pathman, border, pathman_test_setup, pathman_test_teardown, object) { struct pathman_test * test = object; e_pdir_t dlup; e_pfile_t flup; dlup = pathman_add_dir(test->pman, "/a", 0); bt_chkerr(dlup.err); bt_assert_ptr_not_equal(dlup.dir, NULL); flup = pathman_add_file(test->pman, dlup.dir, "foo/bar", 0); bt_assert(flup.err); err_reset(); return BT_RESULT_OK; }
void btObject_dump( int d, btObject *b) { switch(b->t) { case BT_LIST: btList_dump( d, (btList*)b); break; case BT_STRING: btString_dump( d, (btString*)b); break; case BT_DICT: btDict_dump( d, (btDict*)b); break; case BT_INTEGER: btInteger_dump( d, (btInteger*)b); break; default: bt_assert(0==1); } fflush(stdout); }
btPartialPiece * seg_getPiece( btFileSet *fs, int piece) { btPartialPiece *p; bt_assert(piece>=0 && piece<fs->npieces); p=fs->partial; while(p && p->piecenumber!=piece) { p=p->next; } if(!p) { int blocksize=seg_piecelen(fs, piece); /* Allocation trick: the memory after the structure * is the piece contents */ p=btcalloc(1, sizeof(btPartialPiece)+blocksize); p->piecenumber=piece; kBitSet_create( &p->filled, blocksize); pp_addtail( fs, p); } return p; }
int btObject_destroy( btObject *b) { int sz; sz = (int) b->t; switch(sz) { case BT_LIST: btList_destroy((btList*)b); break; case BT_STRING: btString_destroy((btString*)b); break; case BT_DICT: btDict_destroy((btDict*)b); break; case BT_INTEGER: btInteger_destroy((btInteger*)b); break; default: (void)bt_assert(0==1); } return sz; }
static int seg_write( btFileSet *fs, btPartialPiece *piece) { btFile *f; _int64 addr = (_int64)piece->piecenumber * fs->blocksize; int ifile; for (ifile=0; ifile < fs->nfiles; ifile++) { int blocklen = seg_piecelen( fs, piece->piecenumber); f=fs->file[ifile]; if ( f->start+f->len >= addr && f->start < addr + blocklen) { /* this file (partly) includes this piece */ _int64 beg = f->start - addr; off_t fpos=0; _int64 len; int fd = openPath( f->path, O_CREAT | O_WRONLY); if (fd < 0) { return -1; } if (beg<0) { fpos=-beg; beg=0; } len = min(f->len - fpos, (_int64)blocklen - beg); if (lseek( fd, fpos, SEEK_SET) != fpos) { return -1; } bt_assert( len <= fs->blocksize); if (write( fd, piece->buffer+beg, len) != len) { return -1; } } } bs_set( &fs->completed, piece->piecenumber); return 0; }
/* String */ btString* btString_cast( btObject *o) { if (o==NULL) return NULL; bt_assert(o->t == BT_STRING); return (btString*)o; }
/* Integer */ btInteger* btInteger_cast( btObject *o) { if (o==NULL) return NULL; if (o->t != BT_INTEGER) return NULL; bt_assert(o->t == BT_INTEGER); return (btInteger*)o; }
/* Dict */ btDict* btDict_cast( btObject *o) { if (o==NULL) return NULL; bt_assert(o->t == BT_DICT); return (btDict*)o; }
/* List */ btList* btList_cast( btObject *o) { if (o==NULL) return NULL; bt_assert(o->t == BT_LIST); return (btList*)o; }
BT_TEST_FIXTURE(pathman, insert_and_find, pathman_test_setup, pathman_test_teardown, object) { struct pathman_test * test = object; e_pdir_t dlup = {NULL, NULL}; e_pfile_t flup; uint32_t fnum = 0, dnum = 0; for (uint32_t k = 0; k < test->num; k++) { if (test->flag[k] == 1) { // printf("DIR '%s'\n", test->strv[k]); dlup = pathman_add_dir(test->pman, test->strv[k], 0); if (dlup.err) { printf("FAIL dir '%s'\n", test->strv[k]); bt_chkerr(dlup.err); } bt_assert_ptr_not_equal(dlup.dir, NULL); bt_assert_int_not_equal(dlup.dir->state.top.index, 0); dlup.dir->rid = k; dnum++; } else if (test->flag[k] == 2 && dlup.dir) { // printf("FILE '%s'\n", basename(test->strv[k])); flup = pathman_add_file(test->pman, dlup.dir, basename(test->strv[k]), 0); if (flup.err) { printf("FAIL file '%s'\n", basename(test->strv[k])); bt_chkerr(flup.err); } flup.file->rid = k; fnum++; } } char buf[1024], * s; uint16_t dl = 0, fl = 0; for (unsigned k = 0; k < test->num; k++) { if (test->flag[k] == 1) { s = test->strv[k]; dl = strlen(s); memcpy(buf, s, dl); if (buf[dl - 1] != '/') { buf[dl++] = '/'; } buf[dl] = '\0'; // printf("D %s\n", buf); dlup = pathman_get_dir(test->pman, buf); if (dlup.err) { printf("FAIL dir '%s'\n", test->strv[k]); bt_chkerr(dlup.err); } bt_assert_ptr_not_equal(dlup.dir, NULL); } else if (test->flag[k] == 2 && dlup.dir) { bt_assert(dl + fl < 1023); s = test->strv[k]; fl = strlen(s); memcpy(buf + dl, s, fl); buf[dl + fl++] = '\0'; // printf("F %s\n", buf); flup = pathman_get_file(test->pman, buf); if (flup.err) { printf("FAIL file '%s'\n", basename(test->strv[k])); bt_chkerr(flup.err); } bt_assert_ptr_not_equal(flup.file, NULL); //bt_assert(flup.file->rid == k); } } printf("[pathman] %u file(s) in %u dir(s)\n", fnum, dnum); printf("[pathman] %u trie bank(s)\n", test->pman->trie->banks); printf("[pathman] %u dir bank(s)\n", test->pman->dbanks); printf("[pathman] %u file bank(s)\n", test->pman->fbanks); // trie_print(test->pman->trie, 4); // pathman_print(test->pman, 4); return BT_RESULT_OK; }
void CTorrent::run() { m_bRunning = true; m_bStopping = false; try { if( !check() ) { m_nState = STATE_STOPPED; m_bStopping = m_bRunning = false; notify("Checking canceled"); return; } btContext* ctx = &m_Context; int dl = 0; m_pListener->notify("Starting server.."); ctx_startserver(ctx); m_pListener->notify("Registering..."); ctx_register(ctx, dl); m_nState = STATE_RUNNING; m_pListener->notify("Download started"); int ttv; int tv_slow = 1; /*ms*/ int tv_fast = 0; /*ms*/ btPeer *peer; int cs; struct sockaddr csin; int err; time_t choke_timer; time_t report_timer; time_t now; int i; time( &now ); choke_timer = report_timer = now; while( !m_bStopping ) { int readerr; int writeerr; int execerr; int pollerr; socklen_t sa_len; /* * Select a socket or time out */ if (ctx->xsock) { ttv = tv_fast; } else { ttv = tv_slow; } err = poll( ctx->status, ctx->nstatus, ttv); if (err < 0) { bts_perror(errno, "poll"); m_nState = STATE_ERROR; break; } time(&now); for (cs=0; cs < SOCKID_MAX; cs++) { /* loop through executable sockets */ if (ctx->x_set[ cs]) { btPeer *p = ctx->sockpeer[cs]; execerr = clientRun( cs, EXECUTE); if (execerr == 0) { if ( ctx->x_set[ cs]) { ctx->x_set[ cs] = 0; ctx->xsock--; } } if ( kStream_oqlen( &p->ios)) { /* data is waiting on the output buffer */ ctx_setevents( ctx, cs, POLLOUT); } if (execerr < 0) { clientError("execute", cs); } } } for (i=0; i<ctx->nstatus; i++) { /* for each poll event */ cs = ctx->status[i].fd; readerr=0; writeerr=0; execerr=0; pollerr=0; if (CTX_STATUS_REVENTS( ctx, i) & POLLIN) { bt_assert( ctx->status[i].events & POLLIN); /* readable */ if (cs == ctx->ss) { /* service socket */ sa_len = sizeof(csin); cs = accept( ctx->ss, &csin, &sa_len); if (cs < 0) { bts_perror( errno, "accept"); } else { peer_answer( ctx, cs); } } else if (cs == ctx->udpsock) { int err = udp_ready( ctx); if (err) { printf("Error %d processing UDP packet.\n", err); } } else { btPeer *p = ctx->sockpeer[ cs]; readerr = clientRun( cs, READABLE); if (readerr == 1) { /* more to read */ if (!ctx->x_set[cs]) { ctx->x_set[cs] = 1; ctx->xsock++; } } if ( kStream_oqlen( &p->ios)) { /* data is waiting on the output buffer */ ctx_setevents( ctx, cs, POLLOUT); } } } /* if */ if (CTX_STATUS_REVENTS( ctx, i) & POLLOUT) { writeerr = clientWrite( cs ); if (writeerr == 0) { /* output drained */ ctx_clrevents( ctx, cs, POLLOUT); if (!ctx->x_set[ cs]) { /* output buffer is empty, check for more work */ ctx->x_set[ cs] = 1; ctx->xsock++; } } } /* if */ if (CTX_STATUS_REVENTS( ctx, i) & (POLLERR | POLLHUP | POLLNVAL)) { int events = CTX_STATUS_REVENTS( ctx, i); if (events & POLLHUP) { ctx->sockpeer[cs]->ios.error = BTERR_POLLHUP; } else if (events & POLLERR) { ctx->sockpeer[cs]->ios.error = BTERR_POLLERR; } else if (events & POLLNVAL) { ctx->sockpeer[cs]->ios.error = BTERR_POLLNVAL; } pollerr = -1; } if (readerr < 0 || writeerr < 0 || execerr < 0 || pollerr < 0) { const char *act = NULL; if (readerr<0) act = "read"; if (writeerr<0) act = "write"; if (execerr<0) act = "execute"; if (pollerr<0) act = "poll"; clientError( act, cs); } peer = ctx->sockpeer[cs]; if ( peer && !peer->remote.choked && peer->local.interested && !peer->local.snubbed && now - peer->lastreceived > 120) { peer->local.snubbed = 1; } if (peer && peer->pex_supported > 0 && peer->pex_timer > 0 && now - peer->pex_timer >= 60) { sendPeerExchange(ctx->downloads[peer->download], peer); } } if (ctx->downloads[dl]->reregister_interval != 0 && now - ctx->downloads[dl]->reregister_timer > ctx->downloads[dl]->reregister_interval) { notify("Updating..."); ctx->downloads[dl]->reregister_timer = now; ctx_reregister( ctx, dl); } if (now - report_timer > 0) { int complt = bs_countBits( &ctx->downloads[dl]->fileset.completed); if ((complt == ctx->downloads[dl]->fileset.npieces) && !ctx->downloads[dl]->complete) { notify("Completing..."); ctx_complete (ctx, dl); m_nState = STATE_COMPLETE; break; } report_timer=now; updateStatus(); } if (now - choke_timer > 30) { /* recalculate favorite peers */ choke_timer=now; peer_favorites( ctx, &ctx->downloads[dl]->peerset); } } } catch(const char* ex) { m_pListener->error( ex ); m_nState = STATE_ERROR; } notify("Disconnecting..."); int dl = 0; ctx_writefastresume(m_Context.downloads[dl], (char*) m_szDownloadDir ); ctx_shutdown( &m_Context, dl ); cacheclose(); m_bRunning = false; if( m_bStopping ) { notify("Download stopped"); m_bStopping = false; m_nState = STATE_STOPPED; } else if( m_nState == STATE_COMPLETE ) { notify("Download complete"); } else if( m_nState == STATE_ERROR ) { notify("Download failed"); } else m_nState = STATE_STOPPED; }
btObject *btList_index( btList *_this, int idx) { bt_assert (idx>=0 && idx<_this->len); return _this->list[idx]; }