From 185cff17a56e3185049f01b295307bb5f38a3e4b Mon Sep 17 00:00:00 2001 From: Sergey Dorofeev Date: Tue, 21 Feb 2012 08:53:49 +0400 Subject: [PATCH] binkp reengineered --- source/bforce/netspool.c | 43 +- source/bforce/prot_binkp.c | 1678 ++++++++++++++++++++----------- source/bforce/prot_binkp_misc.c | 473 +-------- source/bforce/prot_common.c | 61 +- source/bforce/prot_hydra.c | 2 +- source/bforce/prot_zmsend.c | 2 +- source/bforce/sess_main.c | 11 +- source/include/bforce.h | 1 - source/include/includes.h | 1 + source/include/prot_binkp.h | 98 +- source/include/prot_common.h | 47 +- source/openwrt-conf | 2 + 12 files changed, 1250 insertions(+), 1169 deletions(-) mode change 100644 => 100755 source/openwrt-conf diff --git a/source/bforce/netspool.c b/source/bforce/netspool.c index 5269bdf..86e9db1 100644 --- a/source/bforce/netspool.c +++ b/source/bforce/netspool.c @@ -19,12 +19,12 @@ int readstr(int s, char *buf, int len) { while(1) { r=recv(s, &c, 1, 0); if(r==0){ - puts("remote socket shutdown"); + //puts("remote socket shutdown"); return -3; } if(r==-1){ - puts("error reading string"); - printf("%d %s\n", errno, strerror(errno)); + //puts("error reading string"); + //printf("%d %s\n", errno, strerror(errno)); return -3; } if(c=='\n') { @@ -34,7 +34,7 @@ int readstr(int s, char *buf, int len) { *buf++=c; len--; if(!len) { - puts("string buffer overflow"); + //puts("string buffer overflow"); return -3; } } @@ -48,24 +48,24 @@ int sendstr(int s, const char *buf) { while(l>0) { c=send(s, buf, l, 0); if(c==-1){ - puts("error sending string"); - printf("%d %s\n", errno, strerror(errno)); + //puts("error sending string"); + //printf("%d %s\n", errno, strerror(errno)); return -3; } if(c==0){ - puts("zero send: may loop infinitely"); + //puts("zero send: may loop infinitely"); return -3; } l-=c; } c=send(s, &nl, 1, 0); if(c==-1){ - puts("error sending string"); - printf("%d %s\n", errno, strerror(errno)); + //puts("error sending string"); + //printf("%d %s\n", errno, strerror(errno)); return -3; } if(c==0){ - puts("zero send: may loop infinitely"); + //puts("zero send: may loop infinitely"); return -3; } return 0; @@ -107,7 +107,8 @@ void netspool_start(s_netspool_state *state, const char *host, const char *port, while(a) { r = connect(s, a->ai_addr, a->ai_addrlen); if(r==-1) { - printf("%d %s\n", errno, strerror(errno)); + //printf("%d %s\n", errno, strerror(errno)); + ; } else { break; } @@ -122,16 +123,16 @@ void netspool_start(s_netspool_state *state, const char *host, const char *port, } r = readstr(s, strbuf, STRBUF); - if( r ) { state->state = NS_ERROR; state->error = "IO error"; } - puts(strbuf); + if( r ) { state->state = NS_ERROR; state->error = "IO error"; return; } + //puts(strbuf); -- hello from remote snprintf(strbuf, STRBUF, "ADDRESS %s", address); r = sendstr(s, strbuf); - if( r ) { state->state = NS_ERROR; state->error = "IO error"; } + if( r ) { state->state = NS_ERROR; state->error = "IO error"; return; } snprintf(strbuf, STRBUF, "PASSWORD %s", password); r = sendstr(s, strbuf); - if( r ) { state->state = NS_ERROR; state->error = "IO error"; } + if( r ) { state->state = NS_ERROR; state->error = "IO error"; return; } state->state = NS_READY; } @@ -157,7 +158,7 @@ void netspool_receive(s_netspool_state *state) r = readstr(state->socket, strbuf, STRBUF); if( r ) { state->state = NS_ERROR; state->error = "IO error"; return; } - puts(strbuf); + //puts(strbuf); if(strcmp(strbuf, "QUEUE EMPTY")==0) { state->state = NS_READY; return; @@ -165,7 +166,7 @@ void netspool_receive(s_netspool_state *state) if(strncmp(strbuf, "FILENAME ", 9)==0) { strcpy(state->filename, strbuf+9); - puts(state->filename); + //puts(state->filename); } else { state->state = NS_ERROR; state->error = "expected filename or queue empty"; @@ -180,7 +181,7 @@ void netspool_receive(s_netspool_state *state) exit(-5); } */ sscanf(strbuf+7, "%Lu", &state->length); - printf("length=%Lu\n", state->length); + //printf("length=%Lu\n", state->length); state->state = NS_RECVFILE; } else { state->state = NS_ERROR; @@ -194,7 +195,7 @@ int netspool_read(s_netspool_state *state, void *buf, int buflen) { int n; if( state->length == 0 ) { - puts("everithing is read"); + //puts("everithing is read"); return 0; } @@ -207,8 +208,8 @@ int netspool_read(s_netspool_state *state, void *buf, int buflen) } if(n==-1) { - puts("error reading data"); - printf("%d %s\n", errno, strerror(errno)); + //puts("error reading data"); + //printf("%d %s\n", errno, strerror(errno)); state->state = NS_ERROR; state->error = "IO error"; return -1; diff --git a/source/bforce/prot_binkp.c b/source/bforce/prot_binkp.c index e9528af..6d83be4 100644 --- a/source/bforce/prot_binkp.c +++ b/source/bforce/prot_binkp.c @@ -21,23 +21,1064 @@ #include "prot_common.h" #include "prot_binkp.h" -typedef enum { - BPI_SendSysInfo, - BPI_WaitADR, - BPI_WaitPWD, - BPI_Auth -} binkp_incoming_state; +#define BINKP_HEADER (2) +#define BINKP_MAXBLOCK (32768) + +#define BINKP_BLK_CMD (1) +#define BINKP_BLK_DATA (2) typedef enum { - BPO_SendSysInfo, - BPO_WaitNUL, - BPO_SendPWD, - BPO_WaitADR, - BPO_Auth, - BPO_WaitOK -} binkp_outgoing_state; + frs_nothing, + frs_data, + frs_didget, + frs_skipping +} e_file_receive_status; + +typedef struct { + e_binkp_mode mode; + int phase; + int subphase; + s_binkp_sysinfo *local_data; + s_binkp_sysinfo *remote_data; + s_protinfo *pi; + bool address_established; // indicates that remote address is verified and disallows further change + char extracmd[BINKP_MAXBLOCK+1]; + bool extraislast; + bool password_received; + bool NR; + bool MB; + bool complete; + int batchsendcomplete; + int batchreceivecomplete; + bool waiting_got; + int batch_send_count; + int batch_recv_count; + e_file_receive_status frs; + int emptyloop; +} s_binkp_state; + +int binkp_getforsend(s_binkp_state *bstate, char *buf, int *block_type, unsigned short *block_length); +int binkp_doreceiveblock(s_binkp_state *bstate, char *buf, int block_type, unsigned short block_length); +void binkp_process_NUL(s_binkp_sysinfo *remote_data, char *buffer); +void binkp_process_ADR(s_binkp_sysinfo *remote_data, char *buffer); + +int binkp_loop(s_binkp_state *bstate) { + unsigned char readbuf[BINKP_HEADER+BINKP_MAXBLOCK+1]; + unsigned char writebuf[BINKP_HEADER+BINKP_MAXBLOCK+1]; + + int rc = HRC_OK; + + bstate->phase = 0; + bstate->subphase = 0; + bstate->extracmd[0] = -1; + bstate->extraislast = false; + bstate->password_received = false; + bstate->NR = false; + if(bstate->remote_data->options & BINKP_OPT_NR) { + bstate->NR = true; + } + bstate->MB = false; + if(bstate->remote_data->options & BINKP_OPT_MB) { + bstate->MB = true; + } + bstate->complete = false; // end in this mode (handshake or session) + bstate->batchsendcomplete = 0; + bstate->batchreceivecomplete = 0; + bstate->waiting_got = false; + bstate->batch_send_count = 0; + bstate->batch_recv_count = 0; + bstate->frs = frs_nothing; + bstate->emptyloop = 0; + + unsigned short read_pos=0; + unsigned short read_blklen=0; + unsigned short want_read=BINKP_HEADER; + + unsigned short write_pos=0; + unsigned short have_to_write=0; + + int n, m; + bool no_more_to_send = false; + bool no_more_read = false; + bool canread, canwrite; + + int timeout = conf_number(cf_binkp_timeout); + if( timeout==0 ) + timeout = 60; + + /* used for higher level calls */ + int block_type; + unsigned short block_length; + + // session criterium handshake criterium + while (!bstate->complete || bstate->waiting_got) { + log("loop s: %d r: %d", bstate->batchsendcomplete, bstate->batchreceivecomplete); + if(have_to_write==0 && (!no_more_to_send || bstate->extracmd[0]!=-1)) { + m = binkp_getforsend(bstate, writebuf+BINKP_HEADER, &block_type, &block_length); + if( m==1) { + //log("got block for sending %d %hu", block_type, block_length); + write_pos = 0; + have_to_write = block_length+BINKP_HEADER; + if( block_type == BINKP_BLK_CMD ) { + writebuf[0] = (block_length>>8)|0x80; + } + else if( block_type == BINKP_BLK_DATA ) { + writebuf[0] = (block_length>>8)&0x7f; + } else { + log("block for sending has invalid type, aborting"); + return -1; + } + writebuf[1] = block_length&0xff; + } else if (m==2) { + log("no more to send"); + no_more_to_send = true; + } + else if (m==0) { + log("binkp: nothing to write"); + } else { + log("getforsend error"); + return -1; + } + } + + if (bstate->batchsendcomplete && bstate->batchreceivecomplete) { + log("batch is complete"); + if (bstate->MB && (bstate->batch_send_count || bstate->batch_recv_count)) { + log("starting one more batch"); + bstate->batchsendcomplete -= 1; + bstate->batchreceivecomplete -= 1; + //bstate->firstbatch = false; + bstate->batch_send_count = 0; + bstate->batch_recv_count = 0; + no_more_to_send = false; + bstate->phase = 0; + bstate->frs = frs_nothing; + want_read = BINKP_HEADER; + continue; + } + else { + if (bstate->waiting_got) { + log("waiting for all files have being confirmed"); + } + else { + log("finishing session"); + bstate->complete = true; + want_read = 0; + } + } + } + + log("select read: %d write %d", want_read, have_to_write); + if (want_read || have_to_write) { + n = tty_select(want_read?&canread:NULL, have_to_write?&canwrite:NULL, timeout); + if( n<0 ) { + log("binkp error on tty_select"); + return -1; + } + } + else { + log("empty loop %d", ++bstate->emptyloop); + if (bstate->emptyloop==10) { + return -1; + } + } + + if(want_read && canread) { + n = tty_read(readbuf+read_pos, want_read); + if( n<0 ) { + log("binkp: tty read error"); + return -1; + } + else if (n==0) { + log("read: remote socket shutdown"); + return -1; + } + want_read -= n; + read_pos += n; + if (read_pos == BINKP_HEADER) { + // have read header, want read body + log("it should be 0: %d", want_read); + want_read = ((unsigned short)(readbuf[0]&0x7F)<<8) | readbuf[1]; + log("pending block, length %u", want_read); + } // no else here: if want_read may be zero here for zero length block + } + + // no_more_read only signs that read thread do not keep connection anymore but messages should be processed + if (want_read==0 && read_pos) { // check every loop, not only just after read as accepting may be deferred + block_type = readbuf[0]&0x80? BINKP_BLK_CMD: BINKP_BLK_DATA; + block_length = read_pos - BINKP_HEADER; + log("binkp: complete block is received %d %hu", block_type, block_length); + m = binkp_doreceiveblock(bstate, readbuf+BINKP_HEADER, block_type, block_length); + if(m==1) { + log("block is successfully accepted"); + read_pos = 0; + want_read = BINKP_HEADER; + } else if (m==2) { + log("block accepted and no more is needed in this mode"); + no_more_read = true; + read_pos = 0; + want_read = 0; //BINKP_HEADER; + } + else if (m==0) { + log("binkp: keeping buffer"); + } + else if (m==3) { + log("aborting session"); + bstate->complete = true; + rc = HRC_OTHER_ERR; + } + else { + log("doreceiveblock error"); + return -1; + } + } + + if (have_to_write && canwrite) { + log("writing %d pos %d", have_to_write, write_pos); + n = tty_write(writebuf+write_pos, have_to_write); + if( n<0 ) { + log("binkp: tty write error"); + return -1; + } + else if (n==0) { + log("write: remote socket shutdown"); + return -1; + } + //log("%d bytes sent", n); + write_pos += n; + have_to_write -= n; + } + } + return rc; +} + +int binkp_outgoing(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) +{ + s_binkp_state s; + s.mode = bmode_outgoing_handshake; + s.local_data = local_data; + s.remote_data = remote_data; + s.pi = NULL; + s.address_established = false; + return binkp_loop(&s); +} + +int binkp_incoming(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) +{ + s_binkp_state s; + s.mode = bmode_incoming_handshake; + s.local_data = local_data; + s.remote_data = remote_data; + s.pi = NULL; + s.address_established = false; + return binkp_loop(&s); +} + +int binkp_transfer(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data, s_protinfo *pi) +{ + log("start transfer"); + s_binkp_state s; + s.mode = bmode_transfer; + s.local_data = local_data; + s.remote_data = remote_data; + s.pi = pi; + return binkp_loop(&s); +} + + +// hanshake +// send +// all nuls +// address +// wait password +// send OK/ERR +// -- end handshake +// M_FILE +// (wait M_GET) +// data +// wait M_GOT +// next file +// send EOB + +// recv +// accept NULs +// accept address +// accept password +// -- end handshake +// accept M_GET or +// accept M_FILE +// accept data +// accept next file or EOB + + +int binkp_getforsend(s_binkp_state *bstate, char *buf, int *block_type, unsigned short *block_length) +{ + int my_sf, wr_pos; + int n; // read file + if (bstate->extracmd[0]!=-1) { + log("extra command from receiver %d %s", bstate->extracmd[0], bstate->extracmd+1); + buf[0] = bstate->extracmd[0]; + strcpy(buf+1, bstate->extracmd+1); + *block_type = BINKP_BLK_CMD; + *block_length = strlen(buf+1)+1; + bstate->extracmd[0] = -1; + if (bstate->extraislast) { + bstate->phase = 100; + log("extracmd is last"); + bstate->complete = true; + } + return 1; + } + if (bstate->mode==bmode_incoming_handshake || bstate->mode==bmode_outgoing_handshake ) { + switch( bstate->phase ) { +case 0: // MD5 challenge + bstate->phase+=1; + bstate->subphase=0; + if( bstate->mode==bmode_incoming_handshake && bstate->local_data->challenge_length > 0 ) + { + log("send challenge"); + char challenge[128]; + string_bin_to_hex(challenge, bstate->local_data->challenge, bstate->local_data->challenge_length); + buf[0] = BPMSG_NUL; + sprintf(buf+1, "OPT CRAM-MD5-%s", challenge); + log("sent %s", buf+1); + *block_type = BINKP_BLK_CMD; + *block_length = strlen(buf+1)+1; + return 1; + } + +case 1: // send sysinfo + my_sf = bstate->subphase; + bstate->subphase+=1; + *block_type = BINKP_BLK_CMD; + switch( my_sf ) { +case 0: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "SYS %s", bstate->local_data->systname); + return 1; +case 1: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "ZYZ %s", bstate->local_data->sysop); + return 1; +case 2: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "LOC %s", bstate->local_data->location); + return 1; +case 3: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "PHN %s", bstate->local_data->phone); + return 1; +case 4: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "NDL %s", bstate->local_data->flags); + return 1; +case 5: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "TIME %s", bstate->local_data->timestr); + return 1; +case 6: + buf[0]=BPMSG_NUL; + *block_length = 1 + sprintf(buf+1, "VER %s %s/%d.%d", + bstate->local_data->progname, bstate->local_data->protname, + bstate->local_data->majorver, bstate->local_data->minorver); + return 1; +case 7: + if (bstate->mode==bmode_outgoing_handshake) { + buf[0]=BPMSG_NUL; + strcpy(buf+1, "OPT MB"); + if (!nodelist_checkflag (state.node.flags, "NR")) + strcat(buf+1, " NR"); + // ND is too complicated and have unclear gain + // seems not to remove files from inbound until successful session end is enough to eliminate dupes + // if (!nodelist_checkflag (state.node.flags, "ND")) + // strcat(buf+1, " ND"); + *block_length = 1 + strlen(buf+1); + return 1; + } + // else skip subphase + my_sf += 1; + bstate->subphase += 1; +//case 8: + } + // here if subphase==8 + bstate->phase += 1; + bstate->subphase = 0; + // p + +case 2: + log("send address"); + bstate->phase += 1; + buf[0] = BPMSG_ADR; + wr_pos = 1; + int i; + for( i = 0; i < bstate->local_data->anum; i++ ) + { + if (i) wr_pos += sprintf(buf+wr_pos, " "); + if (bstate->local_data->addrs[i].addr.point) { + wr_pos += sprintf(buf+wr_pos, "%d:%d/%d.%d@%s", + bstate->local_data->addrs[i].addr.zone, bstate->local_data->addrs[i].addr.net, + bstate->local_data->addrs[i].addr.node, bstate->local_data->addrs[i].addr.point, + bstate->local_data->addrs[i].addr.domain); + } + else { + wr_pos += sprintf(buf+wr_pos, "%d:%d/%d@%s", + bstate->local_data->addrs[i].addr.zone, bstate->local_data->addrs[i].addr.net, + bstate->local_data->addrs[i].addr.node, + bstate->local_data->addrs[i].addr.domain); + } + } + *block_type = BINKP_BLK_CMD; + *block_length = wr_pos; + log("address: %s", buf+1); + return 1; + +case 3: // send password on outgoing or pw confirmation on incoming + // special empty password is sent if there is no password for the remote addr + if (bstate->mode==bmode_incoming_handshake) { + if (bstate->password_received) { + log("password verified"); + buf[0] = BPMSG_OK; + *block_type = BINKP_BLK_CMD; + *block_length = 1; + bstate->phase += 1; + return 1; + } + log("waiting for password from remote"); + return 0; // nothing to send + } + else if (bstate->mode==bmode_outgoing_handshake) { + if (!bstate->address_established) { + log("address not received still"); + return 0; + } + log("sending password"); + + buf[0] = BPMSG_PWD; + *block_type = BINKP_BLK_CMD; + + if( bstate->local_data->passwd == '\0' ) { + *block_length = 1 + sprintf(buf+1, "-"); + } + else if( bstate->remote_data->options & BINKP_OPT_MD5 ) { + char digest_bin[16]; + char digest_hex[33]; + + if(bstate->remote_data->challenge_length==0) { + log("waiting for challenge"); + return 0; + } + md5_cram_get(bstate->local_data->passwd, bstate->remote_data->challenge, + bstate->remote_data->challenge_length, digest_bin); + + /* Encode digest to the hex string */ + string_bin_to_hex(digest_hex, digest_bin, 16); + + *block_length = 1 + sprintf(buf+1, "CRAM-MD5-%s", digest_hex); + } + else { + *block_length = 1 + sprintf(buf+1, "%s", bstate->local_data->passwd); + } + bstate->phase += 1; + return 1; + } + else { + log("impossible mode"); + return -1; + } + + +case 4: + if (bstate->mode==bmode_incoming_handshake) { + log("incoming handshake is complete"); + bstate->complete = true; + } + else { + log("outgoing handshake: everything is sent"); + } + return 2; + } + + } + else if (bstate->mode == bmode_transfer) { + + switch (bstate->phase) { + send_next_file: + case 0: + log("fetch file from queue"); + if (p_tx_fopen(bstate->pi, NULL)) { + log("queue empty"); + bstate->phase = 4; + goto send_EOB; + } + bstate->waiting_got = true; + bstate->batch_send_count += 1; + + //send M_FILE -1 + if (bstate->NR) { + log("send M_FILE with -1"); + buf[0] = BPMSG_FILE; + *block_length = 1+sprintf(buf+1, "%s %ld %ld -1", bstate->pi->send->net_name, + bstate->pi->send->bytes_total, bstate->pi->send->mod_time); + *block_type = BINKP_BLK_CMD; + return 1; // no state change. phase would be changed to 1 by recv when M_GET is received + } + bstate->phase += 1; + + case 1: //send M_FILE - M_GET forcibly sets this phase. M_GET must open needed file + log("send M_FILE"); + buf[0] = BPMSG_FILE; + *block_length = 1+sprintf(buf+1, "%s %ld %ld 0", bstate->pi->send->net_name, + bstate->pi->send->bytes_total, bstate->pi->send->mod_time); + *block_type = BINKP_BLK_CMD; + bstate->phase += 1; + return 1; + + case 2: //send file data + n = p_tx_readfile (buf, 4096, bstate->pi); // BINKP_MAXBLOCK + if (n>0) { + *block_type = BINKP_BLK_DATA; + *block_length = n; + bstate->pi->send->bytes_sent += n; + return 1; + } + else if (n<0) { + log("p_tx_readfile error"); + return -1; + } + log("file is sent"); + bstate->pi->send->status = FSTAT_WAITACK; + + bstate->phase += 1; + + case 3: //wait for acknowlede + + if (bstate->pi->send->waitack) { + log("file must be acknowledged with M_GOT"); + int i; + bool ack = false; + for(i = 0; i < bstate->pi->n_sentfiles; i++ ) { + if (p_compfinfo(&bstate->pi->sentfiles[i], bstate->pi->send->fname, bstate->pi->send->bytes_total, bstate->pi->send->mod_time) == 0) { + if (bstate->pi->sentfiles[i].status == FSTAT_SUCCESS) { + ack = true; + log("acknowledged"); + break; + } + } + } + if (!ack) { + log("wait for ACK"); + return 0; + } + } else { + log("do not wait M_GOT"); + } + bstate->phase = 0; + goto send_next_file; + + send_EOB: + case 4: + log("send EOB n_sentfile=%d", bstate->pi->n_sentfiles); + buf[0] = BPMSG_EOB; + *block_type = BINKP_BLK_CMD; + *block_length = 1; + bstate->batchsendcomplete += 1; + bstate->phase += 1; + return 1; + + case 5: + log("nothing to send"); + return 2; + + -#define GOTO(label,newrc) { rc = (newrc); goto label; } + + } + + } else { + log("invalid mode"); + return -1; + } + log("unrecognized state, shutting down"); + bstate->complete = true; + return 2; + +} + + +int binkp_doreceiveblock(s_binkp_state *bstate, char *buf, int block_type, unsigned short block_length) +{ + switch (block_type) { +case BINKP_BLK_CMD: + if (block_length<1) { + log("zero length command received"); + return -1; + } + buf[block_length] = 0; // fencing for easy processing + switch (buf[0]) { +case BPMSG_NUL: /* Site information, just logging */ + log("M_NUL"); + binkp_process_NUL(bstate->remote_data, buf+1); + return 1; +case BPMSG_ADR: /* List of addresses */ + log("M_ADR"); + if (bstate->address_established) { + log("remote tries to change address"); + return -1; + } + if( bstate->extracmd[0] !=-1 ) return 0; // suspend !!! + binkp_process_ADR(bstate->remote_data, buf+1); + + if( !bstate->remote_data->anum ) { + log("error: remote did not supplied any addresses"); + if( bstate->extracmd[0] !=-1 ) return 0; // suspend + bstate->extracmd[0] = BPMSG_BSY; + strcpy(bstate->extracmd+1, "No addresses was presented"); + bstate->extraislast = true; + return 1; + } + + if (bstate->mode == bmode_incoming_handshake) { + int i; + log("sending options"); + bstate->extracmd[0] = BPMSG_NUL; + bstate->extraislast = false; + sprintf(bstate->extracmd+1,"OPT MB"); + s_override ovr; + for(i = 0; i < bstate->remote_data->anum; i++) { + ovr.sFlags = ""; + override_get (&ovr, bstate->remote_data->addrs[i].addr, 0); + if (nodelist_checkflag (ovr.sFlags, "NR")==0) { + strcat (bstate->extracmd+1, " NR"); + break; + } + } + } + // further use extracmd only for errors + + if (bstate->mode == bmode_outgoing_handshake) { + // check that remote has the address we call + if( session_addrs_check_genuine(bstate->remote_data->addrs, bstate->remote_data->anum, + state.node.addr) ) { + log("error: remote does not have the called address"); + bstate->extracmd[0] = BPMSG_ERR; + strcpy(bstate->extracmd+1, "Sorry, you are not who I need"); + bstate->extraislast = true; + return 1; + } + // check that all addresses of remote has the same password + strncpy(bstate->remote_data->passwd, bstate->local_data->passwd, BINKP_MAXPASSWD); + bstate->remote_data->passwd[BINKP_MAXPASSWD] = '\0'; + + if( session_addrs_check(bstate->remote_data->addrs, bstate->remote_data->anum, + bstate->remote_data->passwd, NULL, 0) ) { + log("error: Security violation"); + bstate->extracmd[0] = BPMSG_ERR; + strcpy(bstate->extracmd+1, "Security violation"); + bstate->extraislast = true; + return 1; + } + } + + bstate->address_established = true; + return 1; +case BPMSG_PWD: /* Session password */ + log("M_PWD received"); + if (bstate->mode != bmode_incoming_handshake) { + log("unexpected M_PWD"); + return -1; + } + if (!bstate->address_established) { + log("M_PWD before M_ADR"); + return -1; + } + + strnxcpy(bstate->remote_data->passwd, buf+1, block_length); + memcpy(bstate->remote_data->challenge, bstate->local_data->challenge, BINKP_MAXCHALLENGE+1); + bstate->remote_data->challenge_length = bstate->local_data->challenge_length; + + /* Do authorization */ + if( binkp_auth_incoming(bstate->remote_data) ) { + log("error: invalid password"); + if( bstate->extracmd[0] !=-1 ) return 0; // suspend if extra is occupied + bstate->extracmd[0] = BPMSG_ERR; + strcpy(bstate->extracmd+1, "Security violation"); + bstate->extraislast = true; + return 1; + } + // lock addresses + if( session_addrs_lock(bstate->remote_data->addrs, bstate->remote_data->anum) ) { + log("error locking addresses of the remote"); + if( bstate->extracmd[0] !=-1 ) return 0; // suspend if extra is occupied + bstate->extracmd[0] = BPMSG_BSY; + strcpy(bstate->extracmd+1, "All addresses are busy"); + bstate->extraislast = true; + return 1; + } + else { + log("flag password received"); + bstate->password_received = true; + return 2; + } + break; + +case BPMSG_FILE: /* File information */ + log("M_FILE"); + if (bstate->mode != bmode_transfer) { + log("unexpected M_FILE"); + return -1; + } + s_bpfinfo recvfi; + if( binkp_parsfinfo(buf+1, &recvfi, true) ) { + log ("M_FILE parse error: %s", buf + 1); + return -1; + } + bstate->batch_recv_count += 1; + if (bstate->frs == frs_data) { + log("overlapping M_FILE received"); + return -1; + } + + if (bstate->frs == frs_didget) { + log("is it what we want?"); + if( bstate->pi->recv && p_compfinfo(bstate->pi->recv, recvfi.fn, recvfi.sz, recvfi.tm) == 0 + && bstate->pi->recv->bytes_skipped == recvfi.offs && bstate->pi->recv->fp ) { + log("resuming %s from offset %d", recvfi.fn, recvfi.offs); + bstate->frs = frs_data; + return 1; + } + log("no, skipping (TODO: accept it)"); + if( bstate->extracmd[0] != -1 ) return 0; + bstate->extracmd[0] = BPMSG_SKIP; + sprintf(bstate->extracmd+1, "%s %ld %ld %ld", recvfi.fn, recvfi.sz, recvfi.tm); + bstate->extraislast = false; + return 1; + } + + if (bstate->frs!=frs_nothing && bstate->frs!=frs_skipping) { + log("strange receiving mode %d", bstate->frs); + return -1; + } + + if( bstate->extracmd[0] != -1 ) return 0; + switch(p_rx_fopen(bstate->pi, recvfi.fn, recvfi.sz, recvfi.tm, 0)) { +case 0: + if (bstate->pi->recv->bytes_skipped == recvfi.offs) { + log("accepting file %s from offset %d", recvfi.fn, recvfi.offs); + bstate->frs = frs_data; + return 1; + } + log("making M_GET to skip downloaded part"); + bstate->extracmd[0] = BPMSG_GET; + sprintf(bstate->extracmd+1, "%s %ld %ld %ld", + bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time, + (long)bstate->pi->recv->bytes_skipped); + bstate->extraislast = false; + bstate->frs = frs_didget; + return 1; +case 1: + log("SKIP (non-destructive)"); + bstate->extracmd[0] = BPMSG_SKIP; + sprintf(bstate->extracmd+1, "%s %ld %ld", bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + bstate->frs = frs_skipping; + return 1; +case 2: + log("SKIP (destructive)"); + bstate->extracmd[0] = BPMSG_GOT; + sprintf(bstate->extracmd+1, "%s %ld %ld", + bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + bstate->frs = frs_skipping; + return 1; +default: + log("p_rx_fopen_error"); + return -1; + } + log("never get here"); + return -1; + +case BPMSG_OK: /* Password was acknowleged (data ignored) */ + log("M_OK received"); + if (bstate->mode != bmode_outgoing_handshake) { + log("unexpected M_OK"); + return -1; + } + if (session_addrs_lock(bstate->remote_data->addrs, bstate->remote_data->anum)) { + log("error: unable to lock"); + if (bstate->extracmd[0]!=-1) return 0; + bstate->extracmd[0] = BPMSG_BSY; + strcpy(bstate->extracmd+1, "All addresses are busy"); + bstate->extraislast = true; + return 2; + } + log("outoing handshake successfully complete"); + bstate->complete = true; + return 2; + +case BPMSG_EOB: /* End Of Batch (data ignored) */ + log("M_EOB received"); + if (bstate->mode != bmode_transfer) { + log("unexpected M_EOB"); + return -1; + } + bstate->batchreceivecomplete += 1; + return 1; // continue receiving as M_GOT may and would arrive + +case BPMSG_GOT: /* File received */ +case BPMSG_SKIP: + log("received GOT/SKIP"); + if (bstate->mode != bmode_transfer) { + log("unexpected M_GOT/M_SKIP"); + return -1; + } + s_bpfinfo fi; + int i; + if (binkp_parsfinfo (buf+1, &fi, false)) { + log("error parsing"); + return -1; + } + + if (strcmp (bstate->pi->send->net_name, fi.fn) == 0 && bstate->pi->send->status != FSTAT_WAITACK) { + log("aborting current file"); + if (bstate->pi->send->netspool) { + log("cannot abort netspool in progress"); + return -1; + } + p_tx_fclose(bstate->pi); + bstate->phase = 0; + } + + for(i = 0; i < bstate->pi->n_sentfiles; i++ ) { + if (p_compfinfo (&bstate->pi->sentfiles[i], fi.fn, fi.sz, fi.tm) == 0) { + s_finfo *tmp = bstate->pi->send; + bstate->pi->send = &bstate->pi->sentfiles[i]; + if (buf[0] == BPMSG_SKIP) { + if (bstate->pi->send->netspool) { + log("cannot skip netspool"); + return -1; + } + log("skipped %s", fi.fn); + bstate->pi->send->status = FSTAT_REFUSED; + } else { + if (bstate->pi->send->status == FSTAT_WAITACK) { + log("confirmed %s", fi.fn); + bstate->pi->send->status = FSTAT_SUCCESS; + } else { + log("confirmed not sent file - skipped %s", fi.fn); + if (bstate->pi->send->netspool) { + log("cannot skip netspool"); + return -1; + } + bstate->pi->send->status = FSTAT_SKIPPED; + } + } + log("closing file"); + p_tx_fclose(bstate->pi); + bstate->pi->send = tmp; + goto check_that_all_files_are_confirmed; + } + } + log("unmatched file name"); + return -1; + +check_that_all_files_are_confirmed: + { + int i; + for (i = 0; i < bstate->pi->n_sentfiles; i++) { + if (bstate->pi->sentfiles[i].status == FSTAT_WAITACK) { + log("sent file %d waits for acknowlede", i); + return 1; + } + } + } + log("all files are confirmed"); + bstate->waiting_got = false; + return 1; + + +case BPMSG_ERR: /* Misc errors */ + log("remote error: %s", buf+1); + return 3; +case BPMSG_BSY: /* All AKAs are busy */ + log("remote busy: %s", buf+1); + return 3; + +case BPMSG_GET: /* Get a file from offset */ + log("received M_GET: cancel transmitting current file and send requested file if it is in outbound"); + if (bstate->mode != bmode_transfer) { + log("unexpected M_GET"); + return -1; + } + s_bpfinfo getfi; + if (binkp_parsfinfo(buf+1, &getfi, true) != 0) { + log("error parsing M_GET %s", buf+1); + return -1; + } + log("M_GET file %s size %d time %d offset %d", getfi.fn, getfi.sz, getfi.tm, getfi.offs); + + if (bstate->extracmd[0] != -1) return 0; + + if (p_compfinfo(bstate->pi->send, getfi.fn, getfi.sz, getfi.tm)==0) { + log("M_GET for currently transmitted file"); + if (getfi.offs==bstate->pi->send->bytes_sent) { + log("M_GET offset match current (seems NR mode)"); + // go to sending M_FILE + bstate->phase = 2; + bstate->extracmd[0] = BPMSG_FILE; + sprintf(bstate->extracmd+1, "%s %ld %ld %ld", + bstate->pi->send->net_name, (long)bstate->pi->send->bytes_total, + (long)bstate->pi->send->mod_time, (long)bstate->pi->send->bytes_sent); + bstate->extraislast = false; + return 1; + + } + } + + if (bstate->pi->send->netspool) { + log("ignore differing M_GET for netspool"); + return 1; + } + + if (bstate->pi->send && p_compfinfo(bstate->pi->send, getfi.fn, getfi.sz, getfi.tm)==0) { + if( p_tx_rewind(bstate->pi, getfi.offs) != 0 ) { + log("failed to rewind"); + p_tx_fclose(bstate->pi); + return -1; + } + log("sending \"%s\" from %ld offset", bstate->pi->send->fname, (long)getfi.offs); + bstate->pi->send->bytes_skipped = getfi.offs; + bstate->pi->send->bytes_sent = getfi.offs; + bstate->extracmd[0] = BPMSG_FILE; + sprintf(bstate->extracmd+1, "%s %ld %ld %ld", bstate->pi->send->net_name, (long)bstate->pi->send->bytes_total, + (long)bstate->pi->send->mod_time, (long)getfi.offs); + bstate->extraislast = false; + bstate->phase = 2; + return 1; + } + + if( bstate->pi->send ) { + log("aborting current file"); + p_tx_fclose(bstate->pi); + } + + s_filehint hint; + hint.fn = getfi.fn; + hint.sz = getfi.sz; + hint.tm = getfi.tm;; + if( p_tx_fopen(bstate->pi, &hint) != 0 ) { + log("could not satisfy M_GET"); + return -1; + } + if( p_tx_rewind(bstate->pi, getfi.offs) != 0 ) { + log("failed to rewind"); + p_tx_fclose(bstate->pi); + return -1; + } + bstate->waiting_got = true; + log("sending \"%s\" from %ld offset", bstate->pi->send->fname, (long)getfi.offs); + bstate->pi->send->bytes_skipped = getfi.offs; + bstate->pi->send->bytes_sent = getfi.offs; + bstate->extracmd[0] = BPMSG_FILE; + sprintf(bstate->extracmd+1, "%s %ld %ld %ld", bstate->pi->send->net_name, (long)bstate->pi->send->bytes_total, + (long)bstate->pi->send->mod_time, (long)getfi.offs); + bstate->extraislast = false; + bstate->phase = 2; + return 1; + } + log("unknown command %d received", buf[0]); + return -1; + +case BINKP_BLK_DATA: + //if there is file in progress + log("data block received length=%d", block_length); + if (block_length==0) { + log("ignore zero length data block, argus workaround"); + return 1; + } + if (bstate->frs == frs_nothing) { + log("unexpected data block"); + return -1; + } + if (bstate->frs == frs_didget || bstate->frs == frs_skipping) { + log("did M_GET or M_GOT or M_SKIP, skipping data"); + return 1; + } + + if (bstate->extracmd[0] != -1) return 0; + + long int n; + n = p_rx_writefile(buf, block_length, bstate->pi); + + if( n < 0 ) { + log("error writing file"); + if( n == -2 ) { + bstate->extracmd[0] = BPMSG_GOT; + sprintf(bstate->extracmd+1, "%s %ld %ld", bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + } + else { + bstate->extracmd[0] = BPMSG_SKIP; + sprintf(bstate->extracmd+1, "%s %ld %ld", bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + } + bstate->frs = frs_skipping; + p_rx_fclose(bstate->pi); + return 1; + } + else { + bstate->pi->recv->bytes_received += block_length; + + /* Was it the last data block? */ + if( bstate->pi->recv->bytes_received > bstate->pi->recv->bytes_total ) { + log("binkp got too many data (%ld, %ld expected)", + (long)bstate->pi->recv->bytes_received, (long)bstate->pi->recv->bytes_total); + + bstate->frs = frs_skipping; + bstate->pi->recv->status = FSTAT_REFUSED; + p_rx_fclose(bstate->pi); + return -1; + } + else if( bstate->pi->recv->bytes_received == bstate->pi->recv->bytes_total ) { + log("receive completed"); + bstate->frs = frs_nothing; + bstate->pi->recv->status = FSTAT_SUCCESS; + if( !p_rx_fclose(bstate->pi) ) { + bstate->extracmd[0] = BPMSG_GOT; + sprintf(bstate->extracmd+1, "%s %ld %ld", + bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + return 1; + } + else { + log("some error committing file"); + bstate->extracmd[0] = BPMSG_SKIP; + sprintf(bstate->extracmd+1, "%s %ld %ld", + bstate->pi->recv->net_name, (long)bstate->pi->recv->bytes_total, + (long)bstate->pi->recv->mod_time); + bstate->extraislast = false; + return 1; + } + } else { + log("data block accepted"); + return 1; + } + } + log("never should be here"); + return -1; +default: + log("impossible block_type"); + return -1; + } +} + + +// ---- inherent code ---- void binkp_process_NUL(s_binkp_sysinfo *remote_data, char *buffer) { @@ -91,7 +1132,7 @@ void binkp_process_NUL(s_binkp_sysinfo *remote_data, char *buffer) strnxcpy(remote_data->progname, buffer+4, sizeof(remote_data->progname)); } else - log("BinkP got invalid NUL: \"%s\"", string_printable(buffer)); + log("BinkP NUL: \"%s\"", string_printable(buffer)); // NUL cannot be invalid as it is optional info } void binkp_process_ADR(s_binkp_sysinfo *remote_data, char *buffer) @@ -99,8 +1140,7 @@ void binkp_process_ADR(s_binkp_sysinfo *remote_data, char *buffer) s_faddr addr; char *p, *q; - for( p = string_token(buffer, &q, NULL, 0); p; - p = string_token(NULL, &q, NULL, 0) ) + for( p = string_token(buffer, &q, NULL, 0); p; p = string_token(NULL, &q, NULL, 0) ) { if( ftn_addrparse(&addr, p, FALSE) ) log("BinkP got unparsable address \"%s\"", string_printable(p)); @@ -109,154 +1149,16 @@ void binkp_process_ADR(s_binkp_sysinfo *remote_data, char *buffer) } } -int binkp_outgoing(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) -{ - s_bpinfo bpi; - binkp_outgoing_state binkp_state = BPO_SendSysInfo; - int rc = HRC_OK; - int recv_rc = 0; - int send_rc = 0; - bool send_ready = FALSE; - bool recv_ready = FALSE; - - binkp_init_bpinfo(&bpi); - - while(1) - { - switch(binkp_state) { - case BPO_SendSysInfo: - binkp_queue_sysinfo(&bpi, local_data); - binkp_state = BPO_WaitNUL; - break; - - case BPO_SendPWD: - if( *local_data->passwd == '\0' ) - { - binkp_queuemsg(&bpi, BPMSG_PWD, NULL, "-"); - } - else if( remote_data->options & BINKP_OPT_MD5 ) - { - char digest_bin[16]; - char digest_hex[33]; - - md5_cram_get(local_data->passwd, remote_data->challenge, - remote_data->challenge_length, digest_bin); - - /* Encode digest to the hex string */ - string_bin_to_hex(digest_hex, digest_bin, 16); - - binkp_queuemsg(&bpi, BPMSG_PWD, "CRAM-MD5-", digest_hex); - } - else - binkp_queuemsg(&bpi, BPMSG_PWD, NULL, local_data->passwd); - - binkp_state = BPO_WaitADR; - break; - - case BPO_Auth: - /* Set remote password same as local */ - strncpy(remote_data->passwd, local_data->passwd, BINKP_MAXPASSWD); - remote_data->passwd[BINKP_MAXPASSWD] = '\0'; - - if( !remote_data->anum ) - { - binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "No addresses was presented"); - GOTO(Exit, HRC_BUSY); - } - else if( session_addrs_check_genuine(remote_data->addrs, remote_data->anum, - state.node.addr) ) - { - binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Sorry, you are not who I need"); - GOTO(Exit, HRC_NO_ADDRESS); - } - else if( session_addrs_check(remote_data->addrs, remote_data->anum, - remote_data->passwd, NULL, 0) ) - { - binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Security violation"); - GOTO(Exit, HRC_BAD_PASSWD); - } - else if( session_addrs_lock(remote_data->addrs, remote_data->anum) ) - { - binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "All addresses are busy"); - GOTO(Exit, HRC_BUSY); - } - binkp_state = BPO_WaitOK; - break; - - default: - break; - } - - /* - * Receive/Send next data block - */ - send_ready = recv_ready = FALSE; - - if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? - &send_ready : NULL, bpi.timeout) < 0 ) - GOTO(Abort, HRC_OTHER_ERR); - - recv_rc = BPMSG_NONE; - send_rc = 0; - - if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) - GOTO(Abort, HRC_OTHER_ERR); - - if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) - GOTO(Abort, HRC_OTHER_ERR); - - /* - * Handle received message - */ - switch(recv_rc) { - case BPMSG_NONE: - break; - - case BPMSG_NUL: - binkp_process_NUL(remote_data, bpi.ibuf+1); - if( binkp_state == BPO_WaitNUL ) - binkp_state = BPO_SendPWD; - break; - - case BPMSG_ADR: - if( binkp_state == BPO_WaitADR ) - { - binkp_process_ADR(remote_data, bpi.ibuf+1); - binkp_state = BPO_Auth; - } - break; - - case BPMSG_OK: - if( binkp_state == BPO_WaitOK ) - GOTO(Exit, HRC_OK); - break; - - case BPMSG_ERR: - log("BinkP error: \"%s\"", string_printable(bpi.ibuf+1)); - GOTO(Abort, HRC_FATAL_ERR); - - case BPMSG_BSY: - log("BinkP busy: \"%s\"", string_printable(bpi.ibuf+1)); - GOTO(Abort, HRC_TEMP_ERR); - } - } - -Exit: - if( binkp_flush_queue(&bpi, bpi.timeout) && rc == HRC_OK ) - rc = HRC_OTHER_ERR; - -Abort: - binkp_deinit_bpinfo(&bpi); - - return rc; -} - - int binkp_auth_incoming(s_binkp_sysinfo *remote_data) { if( remote_data->challenge_length > 0 && strncmp(remote_data->passwd, "CRAM-MD5-", 9) == 0 ) { + log("md5 auth addrs %s", remote_data->addrs); + log("md5 auth anum %d", remote_data->anum); + log("md5 auth passwd %s", remote_data->passwd + 9); + log("md5 auth challenge %s", remote_data->challenge); + log("md5 auth challenge len %d", remote_data->challenge_length); return session_addrs_check(remote_data->addrs, remote_data->anum, remote_data->passwd + 9, @@ -264,461 +1166,7 @@ int binkp_auth_incoming(s_binkp_sysinfo *remote_data) remote_data->challenge_length); } + log("plain-text auth"); return session_addrs_check(remote_data->addrs, remote_data->anum, remote_data->passwd, NULL, 0); } - -int binkp_incoming(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) -{ - s_bpinfo bpi; - binkp_incoming_state binkp_state = BPI_SendSysInfo; - int rc = HRC_OK; - int recv_rc = 0; - int send_rc = 0; - bool send_ready = FALSE; - bool recv_ready = FALSE; - - binkp_init_bpinfo(&bpi); - - while(1) - { - switch(binkp_state) { - case BPI_SendSysInfo: - binkp_queue_sysinfo(&bpi, local_data); - binkp_state = BPI_WaitADR; - break; - - case BPI_Auth: - /* Set challenge string same as local */ - memcpy(remote_data->challenge, local_data->challenge, - sizeof(remote_data->challenge)); - remote_data->challenge_length = local_data->challenge_length; - - /* Do authorization */ - if( !remote_data->anum ) - { - binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "No addresses was presented"); - GOTO(Exit, HRC_BUSY); - } - else if( binkp_auth_incoming(remote_data) ) - { - binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Security violation"); - GOTO(Exit, HRC_BAD_PASSWD); - } - else if( session_addrs_lock(remote_data->addrs, remote_data->anum) ) - { - binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "All addresses are busy"); - GOTO(Exit, HRC_BUSY); - } - else - { - binkp_queuemsg(&bpi, BPMSG_OK, NULL, NULL); - GOTO(Exit, HRC_OK); - } - break; - - default: - break; - } - - /* - * Receive/Send next data block - */ - send_ready = recv_ready = FALSE; - - if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? - &send_ready : NULL, bpi.timeout) < 0 ) - GOTO(Abort, HRC_OTHER_ERR); - - recv_rc = BPMSG_NONE; - send_rc = 0; - - if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) - GOTO(Abort, HRC_OTHER_ERR); - - if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) - GOTO(Abort, HRC_OTHER_ERR); - - /* - * Handle received message - */ - switch(recv_rc) { - case BPMSG_NONE: - break; - - case BPMSG_NUL: - binkp_process_NUL(remote_data, bpi.ibuf+1); - break; - - case BPMSG_ADR: - if( binkp_state == BPI_WaitADR ) - { - int i; - char *szOpt = xstrcpy (" MB"); - s_override ovr; - binkp_process_ADR(remote_data, bpi.ibuf+1); - for(i = 0; i < remote_data->anum; i++) - { - ovr.sFlags = ""; - override_get (&ovr, remote_data->addrs[i].addr, 0); - if (!nodelist_checkflag (ovr.sFlags, "NR")) - { -#ifndef NETSPOOL - szOpt = xstrcat (szOpt, " NR"); -#endif - break; - } - } - binkp_queuemsg(&bpi,BPMSG_NUL,"OPT",szOpt); - free (szOpt); - binkp_state = BPI_WaitPWD; - } - break; - - case BPMSG_PWD: - if( binkp_state == BPI_WaitPWD ) - { - strnxcpy(remote_data->passwd, bpi.ibuf+1, sizeof(remote_data->passwd)); - binkp_state = BPI_Auth; - } - break; - - case BPMSG_ERR: - log("BinkP error: \"%s\"", string_printable(bpi.ibuf+1)); - GOTO(Abort, HRC_FATAL_ERR); - - case BPMSG_BSY: - log("BinkP busy: \"%s\"", string_printable(bpi.ibuf+1)); - GOTO(Abort, HRC_TEMP_ERR); - } - } - -Exit: - if( binkp_flush_queue(&bpi, bpi.timeout) && rc == HRC_OK ) - rc = HRC_OTHER_ERR; - -Abort: - binkp_deinit_bpinfo(&bpi); - - return rc; -} - -int binkp_transfer(s_protinfo *pi) { - - int i, n, rc = PRC_NOERROR; - bool recv_ready = FALSE; - bool send_ready = FALSE; - bool rcvd_EOB = FALSE; - bool recv_file = FALSE; - int recv_rc = 0; - int send_rc = 0; - char *fname = NULL; - size_t fsize = 0; - time_t ftime = 0; - size_t foffs = 0; - s_bpinfo bpi; - s_binkp_sysinfo *remote; - enum { - BPT_Start_Send_File, - BPT_Wait_M_GET, - BPT_Send_File, - BPT_Wait_M_GOT, - BPT_No_Files, - BPT_EOB - } binkp_send_state = BPT_Start_Send_File; - remote = (s_binkp_sysinfo *) state.handshake->remote_data; - - binkp_init_bpinfo(&bpi); - - while (1) { - if (binkp_send_state == BPT_Start_Send_File) { - if (p_tx_fopen (pi)) { - binkp_send_state = BPT_No_Files; - } else { - char *name = pi->send->net_name; - long total = (long) pi->send->bytes_total; - long time = (long) pi->send->mod_time; - if (remote->options & BINKP_OPT_NR) { - binkp_queuemsgf(&bpi,BPMSG_FILE,"%s %ld %ld -1",name,total,time); - binkp_send_state = BPT_Wait_M_GET; - /*log("binkp going to BPT_Wait_M_GET");*/ - } else { - binkp_queuemsgf(&bpi,BPMSG_FILE,"%s %ld %ld 0", name,total,time); - binkp_send_state = BPT_Send_File; - } - } - } - if (binkp_send_state == BPT_Send_File) { - /*log("binkp BPT_Send_File");*/ - if (bpi.opos == 0 && bpi.n_msgs == 0) { - if((n = p_tx_readfile (bpi.obuf+BINKP_BLK_HDRSIZE,4096,pi))<0) { - p_tx_fclose (pi); - binkp_send_state = BPT_Start_Send_File; - } else { - binkp_puthdr (bpi.obuf, (unsigned) (n & 0x7fff)); - bpi.opos = n + BINKP_BLK_HDRSIZE; - pi->send->bytes_sent += n; - if (pi->send->eofseen) { - pi->send->status = FSTAT_WAITACK; - if (remote->options & BINKP_OPT_NR) - binkp_send_state = BPT_Wait_M_GOT; - else binkp_send_state = BPT_Start_Send_File; - } - } - } - } - if (binkp_send_state == BPT_No_Files) { - for (i = 0; i < pi->n_sentfiles; i++) { - if (pi->sentfiles[i].status == FSTAT_WAITACK) break; - } - if (i == pi->n_sentfiles) { - binkp_queuemsg (&bpi, BPMSG_EOB, NULL, NULL); - binkp_send_state = BPT_EOB; - } - } - /* End of the current batch (start the next batch if need). */ - if (binkp_send_state == BPT_EOB && rcvd_EOB) { - if (remote->options & BINKP_OPT_MB && bpi.msgs_in_batch > 2) { - bpi.msgs_in_batch = 0; - binkp_send_state = BPT_Start_Send_File; - rcvd_EOB = FALSE; - continue; - } - break; - } - recv_ready = send_ready = FALSE; - if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? - &send_ready : NULL, bpi.timeout) < 0 ) - gotoexit(PRC_ERROR); - - recv_rc = BPMSG_NONE; - send_rc = 0; - - if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) - gotoexit(PRC_ERROR); - if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) - gotoexit(PRC_ERROR); - - switch(recv_rc) { - case BPMSG_NONE: - break; - case BPMSG_DATA: /* Got new data block */ - if( recv_file ) - { - if( (n = p_rx_writefile(bpi.ibuf, bpi.isize, pi)) < 0 ) - { - /* error writing file */ - if( n == -2 ) - { - binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - } - else - { - binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - } - recv_file = FALSE; - p_rx_fclose(pi); - } - else - { - pi->recv->bytes_received += bpi.isize; - - /* Was it the last data block? */ - if( pi->recv->bytes_received > pi->recv->bytes_total ) - { - log("binkp got too many data (%ld, %ld expected)", - (long)pi->recv->bytes_received, - (long)pi->recv->bytes_total); - - recv_file = FALSE; - pi->recv->status = FSTAT_REFUSED; - (void)p_rx_fclose(pi); - - binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - } - else if( pi->recv->bytes_received == pi->recv->bytes_total ) - { - recv_file = FALSE; - pi->recv->status = FSTAT_SUCCESS; - if( !p_rx_fclose(pi) ) - { - binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - } - else - { - binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - } - } - } - } -#ifdef DEBUG - else - DEB((D_PROT, "ignore received data block")); -#endif - break; - - case BPMSG_FILE: - - if( binkp_parsfinfo(bpi.ibuf+1, &fname, - &fsize, &ftime, &foffs) ) - { - log ("BinkP error: M_FILE: %s", bpi.ibuf + 1); - binkp_queuemsg(&bpi, BPMSG_ERR, "FILE: ", "unparsable arguments"); - goto FinishSession; - } - - if( pi->recv && !p_compfinfo(pi->recv, fname, fsize, ftime) - && pi->recv->bytes_skipped == foffs && pi->recv->fp ) - { - recv_file = TRUE; - break; - } - - if (recv_file) { - p_rx_fclose (pi); - recv_file = FALSE; - } - switch(p_rx_fopen(pi, fname, fsize, ftime, 0)) { - case 0: - if (pi->recv->bytes_skipped == foffs) - { - recv_file = TRUE; - break; - } - binkp_queuemsgf(&bpi, BPMSG_GET, "%s %ld %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time, - (long)pi->recv->bytes_skipped); - break; - case 1: - /* SKIP (non-destructive) */ - binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - break; - case 2: - /* SKIP (destructive) */ - binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", - pi->recv->net_name, (long)pi->recv->bytes_total, - (long)pi->recv->mod_time); - break; - default: - ASSERT_MSG(); - } - break; - - case BPMSG_EOB: /* End Of Batch */ - if( recv_file ) - { - p_rx_fclose(pi); - recv_file = FALSE; - } - rcvd_EOB = TRUE; - break; - - case BPMSG_GOT: - case BPMSG_SKIP: - if (binkp_parsfinfo (bpi.ibuf+1,&fname,&fsize,&ftime,NULL)) { - char *m = recv_rc == BPMSG_GOT ? "M_GOT" : "M_SKIP"; - binkp_queuemsgf (&bpi, BPMSG_ERR, "%s: %s", m, bpi.ibuf + 1); - log ("BinkP error: %s: %s", m, bpi.ibuf + 1); - binkp_send_state = BPT_No_Files; - rc = PRC_ERROR; - break; - } - for(i = 0; i < pi->n_sentfiles; i++ ) { - if (!p_compfinfo (&pi->sentfiles[i], fname, fsize, ftime)) { - s_finfo *tmp = pi->send; - pi->send = &pi->sentfiles[i]; - if (recv_rc == BPMSG_SKIP) { - pi->send->status = FSTAT_REFUSED; - } else { - if (pi->send->status == FSTAT_WAITACK) { - pi->send->status = FSTAT_SUCCESS; - } else { - pi->send->status = FSTAT_SKIPPED; - } - } - p_tx_fclose(pi); - pi->send = tmp; - break; - } - } - if (!strcmp (pi->send->net_name, fname)) { - if (binkp_send_state == BPT_Send_File || - binkp_send_state == BPT_Wait_M_GET || - binkp_send_state == BPT_Wait_M_GOT) { - binkp_send_state = BPT_Start_Send_File; - } - } - break; - - case BPMSG_ERR: - log("remote report error: \"%s\"", bpi.ibuf+1); - gotoexit(PRC_ERROR); - break; - - case BPMSG_BSY: - log("remote busy error: \"%s\"", bpi.ibuf+1); - gotoexit(PRC_ERROR); - break; - - case BPMSG_GET: - if( binkp_parsfinfo(bpi.ibuf+1, &fname, &fsize, &ftime, &foffs) == 0 ) - { - if(!p_compfinfo(pi->send,fname,fsize,ftime)) - { - if( fseek(pi->send->fp, foffs, SEEK_SET) == -1 ) - { - log("cannot send file from requested offset %ld", (long)foffs); - p_tx_fclose(pi); - binkp_send_state = BPT_Start_Send_File; - } - else - { - log("sending \"%s\" from %ld offset", - pi->send->fname, (long)foffs); - pi->send->bytes_skipped = foffs; - pi->send->bytes_sent = foffs; - binkp_queuemsgf(&bpi, BPMSG_FILE, "%s %ld %ld %ld", - pi->send->net_name, (long)pi->send->bytes_total, - (long)pi->send->mod_time, (long)foffs); - binkp_send_state = BPT_Send_File; - } - } - } - break; - - default: - log("binkp got unhandled msg #%d", recv_rc); - break; - } - } /* end of while( !sent_EOB || !rcvd_EOB ) */ - - -FinishSession: - if( binkp_flush_queue(&bpi, bpi.timeout) && rc == PRC_NOERROR ) - rc = PRC_ERROR; - - -exit: - if( pi->send && pi->send->fp ) p_tx_fclose(pi); - if( pi->recv && pi->recv->fp ) p_rx_fclose(pi); - - binkp_deinit_bpinfo(&bpi); - - DEB((D_PROT, "binkp: BINKP exit = %d", rc)); - - return rc; -} - diff --git a/source/bforce/prot_binkp_misc.c b/source/bforce/prot_binkp_misc.c index 8321f86..f0456b4 100644 --- a/source/bforce/prot_binkp_misc.c +++ b/source/bforce/prot_binkp_misc.c @@ -21,198 +21,12 @@ #include "prot_common.h" #include "prot_binkp.h" -/***************************************************************************** - * Initialise binkp state structure, allocate memory for buffers, etc. - * - * Arguments: - * bpi pointer to the binkp state structure (s_bpinfo) - * - * Return value: - * None - */ -void binkp_init_bpinfo(s_bpinfo *bpi) -{ - memset(bpi, '\0', sizeof(s_bpinfo)); - - bpi->obuf = (char*)xmalloc(BINKP_MAX_BLKSIZE + BINKP_BLK_HDRSIZE + 1); - bpi->opos = 0; - bpi->optr = bpi->obuf; - - bpi->inew = TRUE; - bpi->isize = -1; - bpi->ibuf = (char*)xmalloc(BINKP_MAX_BLKSIZE + BINKP_BLK_HDRSIZE + 1); - - bpi->timeout = conf_number(cf_binkp_timeout); - if( !bpi->timeout ) - bpi->timeout = 300; -} - -/***************************************************************************** - * DeInitialise binkp state structure, release allocated memory, etc. - * - * Arguments: - * bpi pointer to the binkp state structure (s_bpinfo) - * - * Return value: - * None - */ -void binkp_deinit_bpinfo(s_bpinfo *bpi) -{ - if( bpi->obuf ) - free(bpi->obuf); - if( bpi->ibuf ) - free(bpi->ibuf); - if( bpi->msgqueue ) - free(bpi->msgqueue); - - memset(bpi, '\0', sizeof(s_bpinfo)); -} - -/***************************************************************************** - * Fills s[0] and s[1] with binkp frame header using value of u - * - * Arguments: - * s pointer to the binkp's frame header (2 bytes) - * val value to put - * - * Return value: - * None - */ -void binkp_puthdr(char *s, unsigned int val) -{ - s[0] = ( (unsigned long) val >> 8 ) & 0xff; - s[1] = ( (unsigned long) val ) & 0xff; -} - -/***************************************************************************** - * Fills s[0] with binkp message type value - * - * Arguments: - * s pointer to the destination buffer - * msg message type - * - * Return value: - * None - */ -void binkp_putmsgtype(char *s, e_bpmsg msg) -{ - s[0] = ( (unsigned int) msg ) & 0xff; -} - -/***************************************************************************** - * Extract size from binkp frame header - * - * Arguments: - * s pointer to the source buffer - * - * Return value: - * Value, extracted from binkp header - */ -int binkp_gethdr(const char *s) -{ - return ( (unsigned int) (((unsigned char) s[0]) & 0x7f) << 8 ) - | ( (unsigned int) (((unsigned char) s[1]) & 0xff) ); -} - -/***************************************************************************** - * Extract message type from s[0] - * - * Arguments: - * s pointer to the source buffer (1 byte) - * - * Return value: - * Value, extracted from binkp header, or -1 if extracted message type is - * out of range - */ -int binkp_getmsgtype(char ch) -{ - int val = ( ((unsigned char)ch) & 0x7f ); - - if( BPMSG_MIN > val || val > BPMSG_MAX ) - return -1; - else - return val; -} - -/***************************************************************************** - * Puts a message to the output messages queue. These msgs will be send - * right after the current data block - * - * Arguments: - * bpi binkp state structure - * msg message type - * s1 message text - * s2 message text (will be concatenated with s1) - * - * Return value: - * None - */ -void binkp_queuemsg(s_bpinfo *bpi, e_bpmsg msg, const char *s1, const char *s2) -{ - bpi->msgqueue = xrealloc(bpi->msgqueue, sizeof(s_bpmsg)*(bpi->n_msgs + 1)); - memset(&bpi->msgqueue[bpi->n_msgs], '\0', sizeof(s_bpmsg)); - - /* Set message type */ - bpi->msgqueue[bpi->n_msgs].type = msg; - - /* Set message data size (without frame header) */ - bpi->msgqueue[bpi->n_msgs].size = 1; - if( s1 ) bpi->msgqueue[bpi->n_msgs].size += strlen(s1); - if( s2 ) bpi->msgqueue[bpi->n_msgs].size += strlen(s2); - - /* Set message data */ - bpi->msgqueue[bpi->n_msgs].data = xmalloc(bpi->msgqueue[bpi->n_msgs].size+3); - binkp_puthdr(bpi->msgqueue[bpi->n_msgs].data, - (unsigned)(bpi->msgqueue[bpi->n_msgs].size | 0x8000)); - - binkp_putmsgtype(bpi->msgqueue[bpi->n_msgs].data + 2, msg); - - bpi->msgqueue[bpi->n_msgs].data[3] = '\0'; - if( s1 ) strcat(bpi->msgqueue[bpi->n_msgs].data + 3, s1); - if( s2 ) strcat(bpi->msgqueue[bpi->n_msgs].data + 3, s2); - - DEB((D_PROT, "binkp_queuemsg: queued message #%d, %ld bytes, \"%s\"", - (int)bpi->msgqueue[bpi->n_msgs].type, - (long)bpi->msgqueue[bpi->n_msgs].size, - (char*)bpi->msgqueue[bpi->n_msgs].data+3)); - - ++bpi->n_msgs; - ++bpi->msgs_in_batch; -} - -/***************************************************************************** - * Sends a message using format string - * - * Arguments: - * bpi binkp state structure - * msg message type - * fmt pointer to the format string, (man printf) - * - * Return value: - * None - */ -void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...) -{ - char msg_text[2048]; - va_list ap; - - va_start(ap, fmt); -#ifdef HAVE_SNPRINTF - vsnprintf(msg_text, sizeof(msg_text), fmt, ap); -#else - vsprintf(msg_text, fmt, ap); -#endif - va_end(ap); - - binkp_queuemsg(bpi, msg, msg_text, NULL); -} - /***************************************************************************** * Parse most common message arguments, send error message to remote * if needed. * * Arguments: - * s pointer to the string to parse + * str pointer to the string to parse * fn pointer to the pointer for extracted file name * sz pointer to the extracted file size * tm pointer to the extracted file modification time @@ -221,272 +35,21 @@ void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...) * Return value: * non-zero value on error, zero on success */ -int binkp_parsfinfo(char *str,char **fn,size_t *sz,time_t *tm,size_t *offs){ - char *n; - char *p_fname = NULL; - char *p_size = NULL; - char *p_time = NULL; - char *p_offs = NULL; - - static char *s = NULL; - - /* Attention, offs may be NULL! */ - - ASSERT(str != NULL && fn != NULL && sz != NULL && tm != NULL); - - DEB((D_PROT, "binkp_parsemsg: want parse \"%s\"", s)); - - if (s) free (s); - s = xstrcpy (str); - p_fname = string_token(s, &n, NULL, 0); - p_size = string_token(NULL, &n, NULL, 0); - p_time = string_token(NULL, &n, NULL, 0); - if( offs ) p_offs = string_token(NULL, &n, NULL, 0); - - if( p_fname && p_size && p_time && (!offs || p_offs) ) - { - if( ISDEC(p_size) && ISDEC(p_time) && - (!offs || ISDEC(p_offs) || !strcmp (p_offs, "-1")) ) - { - (*fn) = p_fname; - (*sz) = atol(p_size); - (*tm) = atol(p_time); - if( offs ) *offs = atol(p_offs); - DEB((D_PROT, "binkp_parsemsg: file = \"%s\", size = %d, time = %d", - *fn, *sz, *tm)); - return 0; - } - } - return 1; -} - -/***************************************************************************** - * Put message to a buffer - * - * Arguments: - * bpi binkp state structure - * msg message - * - * Return value: - * Zero on success, and non-zero value if no more free space left - * in the buffer - */ -int binkp_buffer_message(s_bpinfo *bpi, s_bpmsg *msg) -{ - DEB((D_PROT, "binkp_buffer_message: buffer message #%d, %ld byte(s)", - (int)msg->type, (long)msg->size)); - - /* Check for possible internal error */ - if( msg->size > BINKP_MAX_BLKSIZE ) - { - log("size of msg we want to send is too big (%db)", msg->size); - return 1; - } - - /* Is there space for the new msg? */ - if( bpi->opos + msg->size > BINKP_MAX_BLKSIZE ) return 1; - - if( msg->data ) - { - memcpy(bpi->obuf + bpi->opos, msg->data, msg->size + BINKP_BLK_HDRSIZE); - bpi->opos += msg->size + BINKP_BLK_HDRSIZE; - free(msg->data); - msg->data = NULL; - } - - return 0; -} - -/***************************************************************************** - * Send as much buffered data as possible (non-blocking) - * - * Arguments: - * bpi binkp state structure - * - * Return value: - * Zero on success, and non-zero value on errors - */ -int binkp_send_buffer(s_bpinfo *bpi) -{ - int n; - - DEB((D_PROT, "binkp_send_buffer: sending %ld byte(s)", (long)bpi->opos)); - - n = tty_write(bpi->optr, bpi->opos); - - if( n >= bpi->opos ) - { bpi->optr = bpi->obuf; bpi->opos = 0; } - else if( n > 0 ) - { bpi->optr += n; bpi->opos -= n; } - else - return -1; - - return 0; -} - -/***************************************************************************** - * Send as much buffered data or messages from the queue as possible - * - * Arguments: - * bpi binkp state structure - * - * Return value: - * Zero on success, and non-zero value on errors - */ -int binkp_send(s_bpinfo *bpi) +int binkp_parsfinfo(const char *str, s_bpfinfo *fi, bool with_offset) { - int i; - - if( bpi->opos == 0 && bpi->msgqueue ) - { - /* - * Buffer is empty and there are unsent msgs - */ - for( i = 0; i < bpi->n_msgs; i++ ) - { - if( bpi->msgqueue[i].sent == FALSE ) - { - if( binkp_buffer_message(bpi, &bpi->msgqueue[i]) ) - break; - else - bpi->msgqueue[i].sent = TRUE; - } - } - /* If the message queue is empty, free it */ - if( i >= bpi->n_msgs ) - { - if( bpi->msgqueue ) - { free(bpi->msgqueue); bpi->msgqueue = NULL; } - bpi->n_msgs = 0; - } - } - - return bpi->opos ? binkp_send_buffer(bpi) : 0; -} - -/***************************************************************************** - * Flush all buffers and queues that can contain unsent data - * - * Arguments: - * bpi binkp state structure - * timeout abort flushing if this time will be exceeded - * - * Return value: - * Zero on success, and non-zero value on errors - */ -int binkp_flush_queue(s_bpinfo *bpi, int timeout) -{ - bool send_ready = FALSE; - time_t flush_timer; - - timer_set(&flush_timer, timeout); - - while( bpi->opos > 0 || bpi->n_msgs > 0 ) - { - if( timer_expired(flush_timer) - || tty_select(NULL, &send_ready, 10) < 0 ) - return -1; - - if( send_ready && binkp_send(bpi) < 0 ) - return -1; - } - - return 0; -} - -/***************************************************************************** - * Try to receive next message or data block in non-blocking mode - * - * Arguments: - * bpi binkp state structure - * - * Return value: - * One of the BPMSG_* values - */ -int binkp_recv(s_bpinfo *bpi) -{ - int n = 0; - int size; - - if( bpi->inew || bpi->isize == -1 ) - { - bpi->inew = FALSE; - bpi->isize = -1; - size = BINKP_BLK_HDRSIZE; - } - else - size = bpi->isize; - - if( size > 0 ) - { - n = tty_read(bpi->ibuf + bpi->ipos, size - bpi->ipos); - if( n <= 0 ) return BPMSG_EXIT; - } - - bpi->ipos += n; - - if( bpi->ipos == size ) - { - if( bpi->isize == -1 ) - { - /* We got block header */ - bpi->ipos = 0; - bpi->imsg = ((bpi->ibuf[0] >> 7) & 0377) ? TRUE : FALSE; - bpi->isize = binkp_gethdr(bpi->ibuf); - DEB((D_PROT, "binkp_recv: received header: %ld byte(s) (%s)", - (long)bpi->isize, bpi->imsg ? "msg" : "data")); - if( bpi->isize > BINKP_MAX_BLKSIZE ) - { - log("internal error: got %ld bytes block size", bpi->isize); - return BPMSG_EXIT; - } - else if( bpi->isize == 0 ) - { - bpi->ipos = 0; - bpi->inew = TRUE; - bpi->isize = -1; - if( bpi->imsg == TRUE ) - log("zero length message from remote"); - } - } - else /* We got whole data block/message */ - { - if( bpi->imsg == TRUE ) /* Is it message? */ - { - bpi->ipos = 0; - bpi->inew = TRUE; - bpi->ibuf[size] = '\0'; - bpi->imsgtype = binkp_getmsgtype(bpi->ibuf[0]); - DEB((D_PROT, "binkp_recv: got message #%d, %ld byte(s), \"%s\"", - (int)bpi->imsgtype, bpi->isize, bpi->ibuf+1)); - ++bpi->msgs_in_batch; - if( bpi->imsgtype < 0 ) - { - bpi->isize = -1; - log("got incorrect message type"); - if( ++bpi->junkcount >= 5 ) - { - log("junk count exceeded"); - return BPMSG_EXIT; - } - return BPMSG_NONE; - } - return bpi->imsgtype; - } - else /* It is data */ - { - bpi->ipos = 0; - bpi->inew = TRUE; - bpi->ibuf[size] = '\0'; - DEB((D_PROT, "binkp_recv: got data block, %ld byte(s)", - (long)bpi->isize)); - return BPMSG_DATA; - } - } - } - - return BPMSG_NONE; + int r; + if( strlen(str)>PATH_MAX ) { + log("too long string, overflow may occur"); + return -1; + } + r = sscanf(str, with_offset? "%s %d %d %d": "%s %d %d", &fi->fn, &fi->sz, &fi->tm, &fi->offs); + if (r==(with_offset? 4: 3)) { + return 0; + } + else { + return -1; + } } /***************************************************************************** @@ -499,6 +62,7 @@ int binkp_recv(s_bpinfo *bpi) * Return value: * None */ +/* void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp) { int i; @@ -549,6 +113,7 @@ void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp) free (szOpt); } } +*/ /***************************************************************************** * Write options to the log @@ -574,6 +139,7 @@ void binkp_log_options(s_binkp_sysinfo *remote) * Return value: * None */ + void binkp_log_sysinfo(s_binkp_sysinfo *binkp) { int i; @@ -628,6 +194,7 @@ void binkp_log_sysinfo(s_binkp_sysinfo *binkp) log(" Time : %s", string_printable(binkp->timestr)); } + /***************************************************************************** * Set our local system information * @@ -727,6 +294,7 @@ void binkp_set_sysinfo(s_binkp_sysinfo *binkp, s_faddr *remote_addr, bool caller } } + void binkp_parse_options(s_binkp_sysinfo *binkp, char *options) { char *p, *n; @@ -734,11 +302,9 @@ void binkp_parse_options(s_binkp_sysinfo *binkp, char *options) for( p = string_token(options, &n, NULL, 0); p; p = string_token(NULL, &n, NULL, 0) ) { -#ifndef NETSPOOL if( !strcmp(p, "NR") ) { binkp->options |= BINKP_OPT_NR; } else -#endif if( !strcmp(p, "MB") ) binkp->options |= BINKP_OPT_MB; else if( !strcmp(p, "MPWD") ) @@ -776,3 +342,4 @@ void binkp_parse_options(s_binkp_sysinfo *binkp, char *options) } } + diff --git a/source/bforce/prot_common.c b/source/bforce/prot_common.c index 06ceecc..252a13e 100644 --- a/source/bforce/prot_common.c +++ b/source/bforce/prot_common.c @@ -40,8 +40,10 @@ const char *Protocols[] = * Return value: * Zero value on success and non-zero if nothing to send */ -static int prot_get_next_file(s_filelist **dest, s_protinfo *pi) + +static int prot_get_next_file(s_filelist **dest, s_protinfo *pi, s_filehint *hint) { + log("prot_get_next_file %d", hint); s_filelist *ptrl = NULL; s_filelist *best = NULL; s_fsqueue *q = &state.queue; @@ -49,7 +51,9 @@ static int prot_get_next_file(s_filelist **dest, s_protinfo *pi) *dest = NULL; /* local queue */ - for( ptrl = q->fslist; ptrl; ptrl = ptrl->next ) + for( ptrl = q->fslist; ptrl; ptrl = ptrl->next ) { + //log("scan %s", ptrl->fname); + if (hint) if (strcmp(hint->fn, ptrl->fname) !=0 || hint->sz != ptrl->size) continue; if( ptrl->status == STATUS_WILLSEND ) { if( pi->reqs_only ) @@ -85,6 +89,8 @@ static int prot_get_next_file(s_filelist **dest, s_protinfo *pi) else best = ptrl; } + } + //log("scan1 done"); if( best ) { @@ -92,16 +98,21 @@ static int prot_get_next_file(s_filelist **dest, s_protinfo *pi) return 0; } - for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next ) + for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next ) { + if (hint) if (strcmp(hint->fn, ptrl->fname) !=0 || hint->sz != ptrl->size) continue; if( ptrl->status == STATUS_WILLSEND ) { *dest = ptrl; return 0; } + } + //log("scan2 done"); /* network queue */ #ifdef NETSPOOL + if (hint) return 1; // cannot choose + /*log("netspool next file");*/ if(state.netspool.state == NS_NOTINIT) { /*log("new netspool connection");*/ @@ -132,7 +143,7 @@ static int prot_get_next_file(s_filelist **dest, s_protinfo *pi) } if(state.netspool.state == NS_RECEIVING) { - /*log("netspool begin receive");*/ + log("netspool begin receive"); netspool_receive(&state.netspool); } else { log("netspool could not start receive"); @@ -208,7 +219,7 @@ void prot_update_traffic(s_protinfo *pi, const s_fsqueue *q) * Return value: * Zero value on success and non-zero if have nothing to send */ -int p_tx_fopen(s_protinfo *pi) +int p_tx_fopen(s_protinfo *pi, s_filehint *hint) { FILE *fp; struct stat st; @@ -218,11 +229,14 @@ int p_tx_fopen(s_protinfo *pi) return 1; get_next_file: - if( prot_get_next_file(&ptrl, pi) ) - return 1; - + if( prot_get_next_file(&ptrl, pi, hint) ) { + log("no next file"); + return 1; + } + if( ptrl ) { + log("sending local file"); /* Mark this file as "processed" */ ptrl->status = STATUS_SENDING; @@ -261,12 +275,14 @@ get_next_file: */ if( pi->sentfiles && pi->n_sentfiles > 0 ) { + log("adding file to sentfile"); pi->sentfiles = (s_finfo *)xrealloc(pi->sentfiles, sizeof(s_finfo)*(pi->n_sentfiles+1)); memset(&pi->sentfiles[pi->n_sentfiles], '\0', sizeof(s_finfo)); pi->send = &pi->sentfiles[pi->n_sentfiles++]; } else { + log("adding file to new sentfile"); pi->sentfiles = (s_finfo *)xmalloc(sizeof(s_finfo)); memset(pi->sentfiles, '\0', sizeof(s_finfo)); pi->send = pi->sentfiles; @@ -292,6 +308,8 @@ get_next_file: pi->send->status = FSTAT_PROCESS; pi->send->action = ACTION_ACKNOWLEDGE; pi->send->flodsc = -1; + pi->send->waitack = true; + pi->send->netspool = true; } else { #endif @@ -310,7 +328,8 @@ get_next_file: pi->send->type = ptrl->type; pi->send->action = ptrl->action; pi->send->flodsc = ptrl->flodsc; - + pi->send->waitack = false; + pi->send->netspool = false; #ifdef NETSPOOL } #endif @@ -332,6 +351,15 @@ get_next_file: return 0; } +int p_tx_rewind(s_protinfo *pi, size_t pos) +{ + if( !pi || !pi->send || !pi->send->fp) { + log("cannot rewind"); + return -1; + } + return fseek(pi->send->fp, pos, SEEK_SET); +} + void prot_traffic_update(s_traffic *traf, size_t size, int xtime, int type) { if( type & TYPE_REQANSW ) @@ -387,6 +415,11 @@ int p_tx_fclose(s_protinfo *pi) long trans_time = 0; long cps = 0; + if (!pi->send) { + log("already closed"); + return -1; + } + if( pi->send->fp ) { (void)file_close(pi->send->fp); @@ -462,6 +495,8 @@ int p_tx_fclose(s_protinfo *pi) } } + pi->send = NULL; + return 0; } @@ -478,14 +513,14 @@ int p_tx_fclose(s_protinfo *pi) * -1 - error reading file (must try to send file later) * -2 - file must be skipped (send never) */ -int p_tx_readfile(char *buffer, size_t buflen, s_protinfo *pi) +long int p_tx_readfile(char *buffer, size_t buflen, s_protinfo *pi) { int n; struct stat st; long ftell_pos; #ifdef NETSPOOL - if(pi->send->fname==NULL && strcmp(pi->send->local_name, "NETSPOOL")==0 ) { + if (pi->send->netspool) { /*log("reading netspool file");*/ if( state.netspool.state != NS_RECVFILE ) { log("send: wrong netspool state"); @@ -575,7 +610,7 @@ int p_tx_readfile(char *buffer, size_t buflen, s_protinfo *pi) * -1 - error writing file (receive later) * -2 - file must be skipped (receive never) */ -int p_rx_writefile(const char *buffer, size_t buflen, s_protinfo *pi) +long int p_rx_writefile(const char *buffer, size_t buflen, s_protinfo *pi) { struct stat st; long ftell_pos = ftell(pi->recv->fp); @@ -918,7 +953,7 @@ int p_rx_fopen(s_protinfo *pi, char *fn, size_t sz, time_t tm, mode_t mode) * directory, do you know who could left it here ? :) */ - log("recv: allready have \"%s\"", pi->recv->fname); + log("recv: already have \"%s\"", pi->recv->fname); if( p_move2inbound(pi) == 0 ) pi->recv->status = FSTAT_SKIPPED; diff --git a/source/bforce/prot_hydra.c b/source/bforce/prot_hydra.c index a6521d7..ec7e26c 100644 --- a/source/bforce/prot_hydra.c +++ b/source/bforce/prot_hydra.c @@ -1327,7 +1327,7 @@ int hydra_batch(s_hydrainfo *hi, s_protinfo *pi) if( pi->send && pi->send->fp ) p_tx_fclose(pi); - send_EOB = p_tx_fopen(pi) ? TRUE : FALSE; + send_EOB = p_tx_fopen(pi, NULL) ? TRUE : FALSE; txtries = 0; txstate = HTX_FINFO; diff --git a/source/bforce/prot_zmsend.c b/source/bforce/prot_zmsend.c index 63b91d2..1874303 100644 --- a/source/bforce/prot_zmsend.c +++ b/source/bforce/prot_zmsend.c @@ -213,7 +213,7 @@ int tx_zmodem(s_protinfo *pi, bool caller) if( pi->send && pi->send->fp ) p_tx_fclose(pi); txtries = 0; - txstate = p_tx_fopen(pi) ? ZTX_FIN : ZTX_FINFO; + txstate = p_tx_fopen(pi, NULL) ? ZTX_FIN : ZTX_FINFO; break; case ZTX_FINFO: diff --git a/source/bforce/sess_main.c b/source/bforce/sess_main.c index a0ed39d..c4eaaab 100644 --- a/source/bforce/sess_main.c +++ b/source/bforce/sess_main.c @@ -132,7 +132,7 @@ int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd, char pbuf[32]; bool failure = FALSE; bool success = FALSE; - bool cram = (challenge && *challenge); + bool cram = challenge; if( !anum ) return -1; @@ -156,11 +156,12 @@ int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd, { char digest_bin[16]; char digest_hex[33]; - + md5_cram_get(pbuf, challenge, challenge_length, digest_bin); - + /* Encode digest to the hex string */ string_bin_to_hex(digest_hex, digest_bin, 16); + log("good password is %s", digest_hex); if( strcasecmp(passwd, digest_hex) == 0 ) good_passwd = TRUE; @@ -185,7 +186,7 @@ int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd, } } else - /* not password protected address */ + log("not password protected address"); addrs[i].good = TRUE; } @@ -813,7 +814,7 @@ int session(void) switch(state.handshake->protocol) { case PROT_BINKP: - rc = binkp_transfer(&pi); + rc = binkp_transfer((s_binkp_sysinfo *)state.handshake->local_data, (s_binkp_sysinfo *)state.handshake->remote_data, &pi); break; case PROT_ZMODEM: case PROT_ZEDZAP: diff --git a/source/include/bforce.h b/source/include/bforce.h index b4c607e..8a4324e 100644 --- a/source/include/bforce.h +++ b/source/include/bforce.h @@ -154,7 +154,6 @@ /* * Definition of new pretty types */ -typedef char bool; typedef unsigned long UINT32; typedef unsigned short UINT16; typedef unsigned char UINT8; diff --git a/source/include/includes.h b/source/include/includes.h index 0944199..685b939 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -16,6 +16,7 @@ #include "config.h" +#include #include #include #include diff --git a/source/include/prot_binkp.h b/source/include/prot_binkp.h index 15dc44b..ad124e0 100644 --- a/source/include/prot_binkp.h +++ b/source/include/prot_binkp.h @@ -54,6 +54,16 @@ #define BINKP_OPT_SHA1 0x10 /* CRAM-SHA1 authentication */ #define BINKP_OPT_DES 0x20 /* CRAM-DES authentication */ +typedef enum binkp_mode { + bmode_failoff, + bmode_incoming_handshake, + bmode_outgoing_handshake, + bmode_transfer, + bmode_complete +} e_binkp_mode; + + + typedef struct { s_sysaddr *addrs; int anum; @@ -79,9 +89,9 @@ typedef enum { /* * Pseudo message types, returned by binkp_recv() */ - BPMSG_EXIT = -3, /* Terminate session */ - BPMSG_NONE = -2, /* Got nothing intresting */ - BPMSG_DATA = -1, /* Got data block */ +// BPMSG_EXIT = -3, /* Terminate session */ +// BPMSG_NONE = -2, /* Got nothing intresting */ +// BPMSG_DATA = -1, /* Got data block */ /* * Real BinkP message types */ @@ -101,62 +111,70 @@ typedef enum { } e_bpmsg; -typedef struct { - bool sent; /* Sent message (queued) */ - e_bpmsg type; /* Message type */ - int size; /* Message size (length of text) */ - char *data; /* Message text */ -} s_bpmsg; - +//typedef struct { +// bool sent; /* Sent message (queued) */ +// e_bpmsg type; /* Message type */ +// int size; /* Message size (length of text) */ +// char *data; /* Message text */ +//} s_bpmsg; + + +//typedef struct { +// char *obuf; /* Output buffer */ +// int opos; /* Unsent bytes left in buffer */ +// char *optr; /* Send data from this position */ +// +// char *ibuf; /* Our input buffer */ +// int ipos; +// int isize; +//// bool imsg; /* Is it message? */ +/// bool inew; +// e_bpmsg imsgtype; /* Message type */ + // +// int junkcount; +// s_bpmsg *msgqueue; /* Outgoing messages queue */ +// int n_msgs; /* Number of messages in queue */ +// int msgs_in_batch; /* Number of messages in batch */ + +// int timeout; +//} s_bpinfo; typedef struct { - char *obuf; /* Output buffer */ - int opos; /* Unsent bytes left in buffer */ - char *optr; /* Send data from this position */ - - char *ibuf; /* Our input buffer */ - int ipos; - int isize; - bool imsg; /* Is it message? */ - bool inew; - e_bpmsg imsgtype; /* Message type */ - - int junkcount; - s_bpmsg *msgqueue; /* Outgoing messages queue */ - int n_msgs; /* Number of messages in queue */ - int msgs_in_batch; /* Number of messages in batch */ - - int timeout; -} s_bpinfo; + char fn[PATH_MAX]; + size_t sz; + time_t tm; + size_t offs; +} s_bpfinfo; /* prot_binkp.c */ int binkp_outgoing(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data); int binkp_incoming(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data); -int binkp_transfer(s_protinfo *pi); +int binkp_transfer(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data, s_protinfo *pi); /* prot_binkp_misc.c */ -void binkp_init_bpinfo(s_bpinfo *bpi); -void binkp_deinit_bpinfo(s_bpinfo *bpi); +//void binkp_init_bpinfo(s_bpinfo *bpi); +//void binkp_deinit_bpinfo(s_bpinfo *bpi); int binkp_gethdr(const char *s); int binkp_getmsgtype(char ch); void binkp_puthdr(char *s, unsigned int u); void binkp_putmsgtype(char *s, e_bpmsg msg); -void binkp_queuemsg(s_bpinfo *bpi, e_bpmsg msg, const char *s1, const char *s2); -void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...); -int binkp_parsfinfo(char *s, char **fn, size_t *sz, time_t *tm, size_t *offs); -int binkp_buffer_message(s_bpinfo *bpi, s_bpmsg *msg); -int binkp_send_buffer(s_bpinfo *bpi); -int binkp_send(s_bpinfo *bpi); -int binkp_flush_queue(s_bpinfo *bpi, int timeout); -int binkp_recv(s_bpinfo *bpi); +//void binkp_queuemsg(s_bpinfo *bpi, e_bpmsg msg, const char *s1, const char *s2); +//void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...); +int binkp_parsfinfo(const char *s, s_bpfinfo *fi, bool with_offset); +//int binkp_buffer_message(s_bpinfo *bpi, s_bpmsg *msg); +//int binkp_send_buffer(s_bpinfo *bpi); +//int binkp_send(s_bpinfo *bpi); +//int binkp_flush_queue(s_bpinfo *bpi, int timeout); +//int binkp_recv(s_bpinfo *bpi); void binkp_update_sysinfo(s_binkp_sysinfo *binkp); void binkp_log_options(s_binkp_sysinfo *remote); void binkp_log_sysinfo(s_binkp_sysinfo *binkp); -void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp); +//void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp); void binkp_set_sysinfo(s_binkp_sysinfo *binkp, s_faddr *remote_addr, bool caller); void binkp_parse_options(s_binkp_sysinfo *binkp, char *options); /* prot_binkp_api.c */ extern s_handshake_protocol handshake_protocol_binkp; + #endif /* _P_BINKP_H_ */ diff --git a/source/include/prot_common.h b/source/include/prot_common.h index a4f99d0..462fceb 100644 --- a/source/include/prot_common.h +++ b/source/include/prot_common.h @@ -50,22 +50,24 @@ typedef struct traffic { * Information on currently receiveing/transmitting file */ typedef struct finfo { - FILE *fp; /* File descriptor of current file */ - char *local_name; /* Local file name that is used at our side */ - char *net_name; /* File name as it known to the remote side */ - char *fname; /* Local file name with full path */ - time_t start_time; /* Start of current file rx/tx transactions */ - time_t mod_time; /* File last modification time */ - mode_t mode; - size_t bytes_total; /* File size */ - size_t bytes_sent; - size_t bytes_received; - size_t bytes_skipped; /* crash recovery */ - int eofseen; /* end of file seen */ - int status; - int action; - int type; - int flodsc; /* Index number in flo files table */ + FILE *fp; /* File descriptor of current file */ + char *local_name; /* Local file name that is used at our side */ + char *net_name; /* File name as it known to the remote side */ + char *fname; /* Local file name with full path */ + time_t start_time; /* Start of current file rx/tx transactions */ + time_t mod_time; /* File last modification time */ + mode_t mode; + size_t bytes_total; /* File size */ + size_t bytes_sent; + size_t bytes_received; + size_t bytes_skipped; /* crash recovery */ + int eofseen; /* end of file seen */ + int status; + int action; + int type; + int flodsc; /* Index number in flo files table */ + bool waitack; + bool netspool; } s_finfo; /* @@ -113,10 +115,17 @@ typedef struct protinfo { extern const char *Protocols[]; /* Protocol names */ -int p_tx_fopen(s_protinfo *pi); +typedef struct { + char *fn; + size_t sz; + time_t tm; +} s_filehint; + +int p_tx_fopen(s_protinfo *pi, s_filehint *hint); int p_tx_fclose(s_protinfo *pi); -int p_tx_readfile(char *buf, size_t sz, s_protinfo *pi); -int p_rx_writefile(const char *buf, size_t sz, s_protinfo *pi); +int p_tx_rewind(s_protinfo *pi, size_t pos); +long int p_tx_readfile(char *buf, size_t sz, s_protinfo *pi); +long int p_rx_writefile(const char *buf, size_t sz, s_protinfo *pi); int p_compfinfo(s_finfo *finf, const char *fn, size_t sz, time_t tm); int p_rx_fopen(s_protinfo *pi, char *f_name, size_t f_size, time_t f_modtime, mode_t f_mode); int p_rx_fclose(s_protinfo *pi); diff --git a/source/openwrt-conf b/source/openwrt-conf old mode 100644 new mode 100755 index 9638897..ffe57bd --- a/source/openwrt-conf +++ b/source/openwrt-conf @@ -11,4 +11,6 @@ CC=$PREFIX-gcc export PATH CC CPP +#make clean #./configure --prefix=/opt/bforce --host=mips-openwrt-linux --disable-syslog --enable-netspool +make && scp bin/bforce root@gw-home:/opt/bforce/bin