TEST_F(RingBuf, RingBufRW2_1) { RingBuf_t ringbuf; uint8_t wbuf[3]; uint8_t rbuf[3]; size_t sz; for (int i = 0; i < 3; i++) { RingBufAlloc(&ringbuf, 3); ringbuf.wpos = i; //ずらす ringbuf.rpos = (ringbuf.wpos + 1) % 3; memset(ringbuf.buf, 0xdd, 3); ringbuf.empty = false; //1回ずつ書いて、1回ずつ読む //書ける wbuf[0] = 0x12; sz = 1; RingBufWrite(&ringbuf, wbuf, &sz); ASSERT_EQ(1UL, sz); //書けない wbuf[0] = 0x78; sz = 1; RingBufWrite(&ringbuf, wbuf, &sz); ASSERT_EQ(0UL, sz); //読める sz = 1; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(1UL, sz); ASSERT_EQ(0xdd, rbuf[0]); //読める sz = 1; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(1UL, sz); ASSERT_EQ(0xdd, rbuf[0]); //読める sz = 1; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(1UL, sz); ASSERT_EQ(0x12, rbuf[0]); //読めない sz = 1; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(0UL, sz); RingBufFree(&ringbuf); } }
TEST_F(RingBuf, RingBufRW1_2) { RingBuf_t ringbuf; uint8_t wbuf[3]; uint8_t rbuf[5]; size_t sz; for (int i = 0; i < 3; i++) { RingBufAlloc(&ringbuf, 3); ringbuf.rpos = ringbuf.wpos = i; //ずらす //2回で書いて、1回で読む //書ける wbuf[0] = 0x12; wbuf[1] = 0x34; sz = 2; RingBufWrite(&ringbuf, wbuf, &sz); ASSERT_EQ(2UL, sz); //書ける wbuf[0] = 0x56; wbuf[1] = 0x78; sz = 2; RingBufWrite(&ringbuf, wbuf, &sz); ASSERT_EQ(1UL, sz); //書けない wbuf[0] = 0x78; sz = 1; RingBufWrite(&ringbuf, wbuf, &sz); ASSERT_EQ(0UL, sz); //読める sz = 5; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(3UL, sz); ASSERT_EQ(0x12, rbuf[0]); ASSERT_EQ(0x34, rbuf[1]); ASSERT_EQ(0x56, rbuf[2]); //読めない sz = 1; RingBufRead(&ringbuf, rbuf, &sz); ASSERT_EQ(0UL, sz); RingBufFree(&ringbuf); } }
//RingBufRead_{rpos}_{wpos}_{sz} TEST_F(RingBuf2, RingBufRead2_2_2) { //書込みデータ // !empty // +---+ // RW2| 3 | // 1| 2 | // 0| 1 | // +---+ RingBuf2::mBuf.rpos = 2; RingBuf2::mBuf.wpos = 2; RingBuf2::mBuf.empty = false; RingBuf2::mBuf.buf[0] = 1; RingBuf2::mBuf.buf[1] = 2; RingBuf2::mBuf.buf[2] = 3; uint8_t data[3]; memset(data, 0xdd, sizeof(data)); size_t sz = 2; RingBufRead(&RingBuf2::mBuf, data, &sz); //下エリア用のバッファが足りないパターン ASSERT_EQ(1, RingBuf2::mBuf.rpos); ASSERT_EQ(2, RingBuf2::mBuf.wpos); ASSERT_EQ(2UL, sz); ASSERT_EQ(3, data[0]); ASSERT_EQ(1, data[1]); ASSERT_EQ(0xdd, data[2]); ASSERT_FALSE(RingBuf2::mBuf.empty); }
//RingBufRead_{rpos}_{wpos}_{sz} TEST_F(RingBuf2, RingBufRead2_0_3) { //書込みデータ // !empty // +---+ // R2| 3 | // 1| 2 | // W0| 1 | // +---+ RingBuf2::mBuf.rpos = 2; RingBuf2::mBuf.wpos = 0; RingBuf2::mBuf.empty = false; RingBuf2::mBuf.buf[0] = 1; RingBuf2::mBuf.buf[1] = 2; RingBuf2::mBuf.buf[2] = 3; uint8_t data[3]; memset(data, 0xdd, sizeof(data)); size_t sz = 3; RingBufRead(&RingBuf2::mBuf, data, &sz); ASSERT_EQ(0, RingBuf2::mBuf.rpos); ASSERT_EQ(0, RingBuf2::mBuf.wpos); ASSERT_EQ(1UL, sz); ASSERT_EQ(3, data[0]); ASSERT_EQ(0xdd, data[1]); ASSERT_EQ(0xdd, data[2]); ASSERT_TRUE(RingBuf2::mBuf.empty); }
//RingBufRead_{rpos}_{wpos}_{sz} TEST_F(RingBuf2, RingBufRead0_0_2) { //書込みデータ // !empty // +---+ // 2| 3 | // 1| 2 | // RW0| 1 | // +---+ RingBuf2::mBuf.rpos = 0; RingBuf2::mBuf.wpos = 0; RingBuf2::mBuf.empty = false; RingBuf2::mBuf.buf[0] = 1; RingBuf2::mBuf.buf[1] = 2; RingBuf2::mBuf.buf[2] = 3; uint8_t data[3]; memset(data, 0xdd, sizeof(data)); size_t sz = 2; RingBufRead(&RingBuf2::mBuf, data, &sz); ASSERT_EQ(2, RingBuf2::mBuf.rpos); ASSERT_EQ(0, RingBuf2::mBuf.wpos); ASSERT_EQ(2UL, sz); ASSERT_EQ(1, data[0]); ASSERT_EQ(2, data[1]); ASSERT_FALSE(RingBuf2::mBuf.empty); }
TEST_F(RingBuf2, RingBufRead_empty) { //書込みデータ無し // empty // +---+ // 2| | // 1| | // RW0| | // +---+ uint8_t data[5]; memset(data, 0xdd, sizeof(data)); size_t sz = sizeof(data); RingBufRead(&RingBuf2::mBuf, data, &sz); ASSERT_EQ(0, RingBuf2::mBuf.rpos); ASSERT_EQ(0, RingBuf2::mBuf.wpos); ASSERT_TRUE(RingBuf2::mBuf.empty); ASSERT_EQ(0UL, sz); for (int i = 0; i < (int)sizeof(data); i++) { ASSERT_EQ(0xdd, data[i]); } }
unsigned vdd_read(BYTE* p, unsigned count) { sem_wait(rdbuf.sem); count=RingBufRead(&rdbuf,p,count); if(count==0) lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0"); return(count); }
//--------------------------------------------------------------------------- void __fastcall TSpyForm::SpyTimerTick(TObject *Sender) { uchar buf[1024]; int rd; if(*outbuf==NULL) return; rd=RingBufRead(*outbuf,buf,sizeof(buf)-1); if(rd) { rd=strip_telnet(buf,rd); Terminal->WriteBuffer(buf,rd); Timer->Interval=1; } else Timer->Interval=250; }
//***************************************************************************** // // This function is called in the context of the main loop to process any // touch screen messages that have been sent. Messages are posted to a // queue from the message handler and pulled off here. This is required // since it is not safe to have two different execution contexts performing // graphics operations using the same graphics context. // //***************************************************************************** void ProcessTouchMessages(void) { tScribbleMessage sMsg; // // Loop while there are more messages to process. // while(!RingBufEmpty(&g_sMsgQueue)) { // // Get the next message. // RingBufRead(&g_sMsgQueue, (uint8_t *)&sMsg, sizeof(tScribbleMessage)); // // Dispatch it to the handler. // TSMainHandler(sMsg.ui32Msg, sMsg.i32X, sMsg.i32Y); } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL SBBSExecInt16::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE ch; DWORD avail; vm_t* vm = find_vm(hVM); if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_IN)) { return(FALSE); // Tells VMM that interrupt was not handled } // DBTRACExx(0,"Int16 (hVM, AX)", hVM, _clientAX); avail=RingBufFull(&vm->in); switch(_clientAH) { case 0x00: // Read char from keyboard case 0x10: // Read char from enhanced keyboard if(avail) { RingBufRead(&vm->in, &ch, 1); _clientAX=ch; return(TRUE); } break; case 0x01: // Get keyboard status case 0x11: // Get enhanced keyboard status if(avail) { RingBufPeek(&vm->in, &ch, 1); _clientFlags&=~(1<<6); // clear zero flag _clientAX=ch; return(TRUE); } break; default: DBTRACEx(0,"!UNHANDLED INT16 function", _clientAH); break; } return(FALSE); }
DWORD SBBSExec::OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL) { DWORD rd; DWORD wr; DWORD avail; vm_t* vm; // DBTRACEd(0,"SBBSEXEC ioctl" //,pIOCTL->dioc_IOCtlCode); switch(pIOCTL->dioc_IOCtlCode) { case DIOC_OPEN: DBTRACEd(0,"IOCTL: OPEN",Get_System_Time()); break; case DIOC_CLOSEHANDLE: DBTRACEd(0,"IOCTL: CLOSE",Get_System_Time()); break; case SBBSEXEC_IOCTL_START: DBTRACEd(0,"IOCTL: START",Get_System_Time()); DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle()); if(start.event) { DBTRACE(0,"Exec already started!"); return(SBBSEXEC_ERROR_INUSE); } if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(start)) { return(SBBSEXEC_ERROR_INBUF); } start=*(sbbsexec_start_t*)pIOCTL->dioc_InBuf; break; case SBBSEXEC_IOCTL_COMPLETE: DBTRACEd(0,"IOCTL: COMPLETE",Get_System_Time()); if(start.event || new_vm==NULL) { DBTRACE(0,"!VM never created"); start.event=0; return(SBBSEXEC_ERROR_INUSE); } if(pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf<sizeof(VMHANDLE)) { DBTRACE(0,"!Invalid OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } *(VMHANDLE*)pIOCTL->dioc_OutBuf=new_vm->handle; DBTRACEx(0,"CREATED VM HANDLE", new_vm->handle); new_vm=NULL; if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = sizeof(VMHANDLE); break; case SBBSEXEC_IOCTL_READ: if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf==0) { DBTRACE(0,"!INVALID OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } rd = RingBufFull(&vm->out); if(rd>pIOCTL->dioc_cbOutBuf) { DBTRACEdd(0,"Reducing read size" ,rd, pIOCTL->dioc_cbOutBuf); rd=pIOCTL->dioc_cbOutBuf; } RingBufRead(&vm->out, (BYTE*)pIOCTL->dioc_OutBuf, rd); if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = rd; if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); if(rd>1) { DBTRACEd(1,"IOCTL_READ bytes", rd); } break; case SBBSEXEC_IOCTL_WRITE: if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf<sizeof(VMHANDLE)+1) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf!=sizeof(DWORD)) { DBTRACE(0,"!INVALID OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } wr = pIOCTL->dioc_cbInBuf-sizeof(VMHANDLE); avail = RingBufFree(&vm->in); if(wr>avail) { DBTRACEdd(0,"Reducing write size", wr, avail); wr=avail; } RingBufWrite(&vm->in, (BYTE*)pIOCTL->dioc_InBuf+sizeof(VMHANDLE), wr); *(DWORD *)pIOCTL->dioc_OutBuf = wr; if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = sizeof(DWORD); if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); // Wake up the VDM (improves keyboard response - dramatically!) Wake_Up_VM(vm->handle); break; case SBBSEXEC_IOCTL_DISCONNECT: DBTRACEd(0,"IOCTL: DISCONNECT",Get_System_Time()); if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } vm->online=false; if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); break; case SBBSEXEC_IOCTL_STOP: DBTRACEd(0,"IOCTL: STOP",Get_System_Time()); if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } DBTRACEx(0,"CLOSING VM HANDLE", vm->handle); vm->handle=NULL; // Mark as available RingBufDispose(&vm->in); RingBufDispose(&vm->out); if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); vm->input_sem=NULL; vm->output_sem=NULL; break; default: DBTRACEdx(0,"!UNKNOWN IOCTL" ,pIOCTL->dioc_IOCtlCode,pIOCTL->dioc_IOCtlCode); return(SBBSEXEC_ERROR_IOCTL); } return (0); // DEVIOCTL_NOERROR); }
BOOL SBBSExecInt14::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE* buffer; BYTE ch; WORD buflen; WORD rd,wr; WORD avail; vm_t* vm = find_vm(hVM); if(vm==NULL || vm->mode!=SBBSEXEC_MODE_FOSSIL) { return(FALSE); // Tells VMM that interrupt was not handled } DBTRACEx(4,"Int14 func",_clientAH); switch(_clientAH) { case 0x00: /* Initialize/Set baud rate */ DBTRACE(0,"Int14 init"); _clientAX=PortStatus(vm); break; case 0x01: /* write char to com port */ if(RingBufFree(&vm->out)<2) { DBTRACEx(1,"!OUTPUT BUFFER OVERFLOW, hVM", hVM); vm->output_sem=Create_Semaphore(0); Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->output_sem); vm->output_sem=NULL; if(!vm->online) { DBTRACE(0,"!USER HUNG UP"); return(true); } } ch=_clientAL; RingBufWrite(&vm->out,&ch,1); #if 0 /* Now done in SBBS.DLL/XTRN.CPP */ if(ch==0xff) { /* escape TELNET IAC */ RingBufWrite(&vm->out,&ch,1); DBTRACE(1,"Escaped IAC in output stream"); } #endif vm->overrun=false; _clientAX=PortStatus(vm); break; case 0x02: /* read char from com port */ if(!RingBufFull(&vm->in)) { DBTRACEx(0,"Waiting on input semaphore, hVM", hVM); vm->input_sem=Create_Semaphore(0); Wait_Semaphore(vm->input_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->input_sem); vm->input_sem=NULL; #if 0 _clientAH=0x80; /* timed-out */ return(TRUE); #endif } RingBufRead(&vm->in,&ch,1); _clientAH=0; _clientAL=ch; break; case 0x03: /* request status */ _clientAX=PortStatus(vm); break; case 0x04: /* initialize */ DBTRACE(0,"Int14 func 4 init"); _clientAX=0x1954; /* magic number = success */ _clientBH=5; /* FOSSIL rev */ _clientBL=0x1B; /* maximum FOSSIL func supported */ break; case 0x08: // flush output buffer DBTRACE(0,"Int14 FLUSH OUTPUT BUFFER"); vm->output_sem=Create_Semaphore(0); Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->output_sem); vm->output_sem=NULL; break; case 0x09: // purge output buffer DBTRACE(0,"Int14 PURGE OUTPUT BUFFER"); RingBufReInit(&vm->out); break; case 0x0A: // purge input buffer DBTRACE(0,"Int14 PURGE INPUT BUFFER"); RingBufReInit(&vm->in); break; case 0x0B: /* write char to com port, no wait */ if(RingBufFree(&vm->out)<2) { _clientAX=0; // char was not accepted break; } ch=_clientAL; RingBufWrite(&vm->out,&ch,1); #if 0 /* Now done in SBBS.DLL/XTRN.CPP */ if(ch==0xff) { /* escape TELNET IAC */ RingBufWrite(&vm->out,&ch,1); DBTRACE(1,"Escaped IAC in output stream"); } #endif _clientAX=1; // char was accepted break; case 0x0C: // non-destructive read-ahead if(!RingBufFull(&vm->in)) { _clientAX=0xffff; // no char available break; } RingBufPeek(&vm->in,&ch,1); _clientAH=0; _clientAL=ch; break; case 0x13: /* write to display */ dprintf("%c",_clientAL); break; case 0x18: /* read bock */ rd=_clientCX; avail=RingBufFull(&vm->in); if(rd>avail) rd=avail; if(rd) { buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); rd = RingBufRead(&vm->in, buffer, rd); } _clientAX = rd; break; case 0x19: /* write block */ wr=_clientCX; avail=RingBufFree(&vm->out); if(wr>avail) wr=avail; if(wr) { buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); wr = RingBufWrite(&vm->out, buffer, wr); } _clientAX = wr; break; #if 1 case 0x1B: // driver info { DBTRACE(1,"Int14 driver info"); struct { WORD info_size; BYTE curr_fossil; BYTE curr_rev; DWORD id_string; WORD inbuf_size; WORD inbuf_free; WORD outbuf_size; WORD outbuf_free; BYTE screen_width; BYTE screen_height; BYTE baud_rate; } info={ sizeof(info), 5, 1, 0 ,RINGBUF_SIZE_IN-1, RingBufFree(&vm->in) ,RINGBUF_SIZE_OUT-1, RingBufFree(&vm->out) ,80,25 ,1 // 38400 }; // Map_Lin_To_VM_Addr buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); wr=sizeof(info); if(wr>_clientCX) wr=_clientCX; memcpy(buffer, &info, wr); _clientAX=wr; break; } #endif default: DBTRACEx(0,"!UNHANDLED INTERRUPT 14h function",_clientAH); break; } return(TRUE); // Tells VMM that interrupt was handled }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL SBBSExecInt21::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE ch; BYTE* buffer; WORD buflen; vm_t* vm = find_vm(hVM); if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) { #if 0 if(vm && !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) { DBTRACEx(0,"Int21 on unsupported VM", hVM); } #endif return(FALSE); // Tells VMM that interrupt was not handled } DBTRACEx(1,"Int21 function", _clientAH); DWORD avail = RingBufFree(&vm->out); switch(_clientAH) { case 0x01: DBTRACE(0,"!Int21 Char input WITH echo"); break; case 0x06: // Direct console I/O DBTRACEx(0,"DOS DIRECT CONSOLE IO, DL", _clientDL); if(_clientDL==0xff) { avail=RingBufFull(&vm->in); if(avail) { DBTRACEd(0,"avail",avail); RingBufRead(&vm->in, &ch, 1); _clientFlags&=~(1<<6); // clear zero flag _clientAX=ch; return(TRUE); } break; } // fall-through case 0x02: // Character output DBTRACEx(1,"Int21 function", _clientAH); if(!avail) { DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM); vm->overrun=true; break; } ch=_clientDL; RingBufWrite(&vm->out,&ch,1); vm->overrun=false; break; case 0x09: // Display string DBTRACE(0,"!Int21 func 09 - DISPLAY STRING"); break; case 0x0A: // Buffered keyboard input DBTRACE(0,"Int21 Func 0A - Buffered Keyboard Input"); /* Need to get a string from the user, echo, and copy to DS:DX */ /* byte 0 = max length, byte 1 = actual read (minus CR) */ break; case 0x40: // Write file or device if(_clientBX!=1 && _clientBX!=2) { // !stdout and !stderr DBTRACEd(1,"!Int21 write to unsupported device", _clientBX); break; } DBTRACEdd(1,"Int21 write file", _clientBX, _clientCX); buffer = (BYTE*)MAPFLAT(CRS.Client_DS, CWRS.Client_DX); buflen = _clientCX; if(avail<buflen) { DBTRACEd(0,"!OUTPUT BUFFER OVERFLOW, avail", avail); vm->overrun=true; if(!avail) break; buflen=avail; } RingBufWrite(&vm->out,buffer,buflen); vm->overrun=false; break; } return(FALSE); // Tells VMM that interrupt was not handled }
static void output_thread(void* arg) { char stats[128]; BYTE buf[MAX_OUTBUF_SIZE]; int i; ulong avail; ulong total_sent=0; ulong total_pkts=0; ulong short_sends=0; ulong bufbot=0; ulong buftop=0; fd_set socket_set; struct timeval tv; #if 0 /* def _DEBUG */ fprintf(statfp,"output thread started\n"); #endif while(sock!=INVALID_SOCKET && !terminate) { if(bufbot==buftop) avail=RingBufFull(&outbuf); else avail=buftop-bufbot; if(!avail) { #if !defined(RINGBUF_EVENT) SetEvent(outbuf_empty); #endif sem_wait(&outbuf.sem); if(outbuf.highwater_mark) sem_trywait_block(&outbuf.highwater_sem,outbuf_drain_timeout); continue; } /* Check socket for writability (using select) */ tv.tv_sec=0; tv.tv_usec=1000; FD_ZERO(&socket_set); #ifdef __unix__ if(stdio) FD_SET(STDOUT_FILENO,&socket_set); else #endif FD_SET(sock,&socket_set); i=select(sock+1,NULL,&socket_set,NULL,&tv); if(i==SOCKET_ERROR) { lprintf(LOG_ERR,"ERROR %d selecting socket %u for send" ,ERROR_VALUE,sock); break; } if(i<1) { select_errors++; continue; } if(bufbot==buftop) { /* linear buf empty, read from ring buf */ if(avail>sizeof(buf)) { lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)" ,avail, sizeof(buf)); avail=sizeof(buf); } buftop=RingBufRead(&outbuf, buf, avail); bufbot=0; } #ifdef __unix__ if(stdio) i=write(STDOUT_FILENO, (char*)buf+bufbot, buftop-bufbot); else #endif i=sendsocket(sock, (char*)buf+bufbot, buftop-bufbot); if(i==SOCKET_ERROR) { if(ERROR_VALUE == ENOTSOCK) lprintf(LOG_ERR,"client socket closed on send"); else if(ERROR_VALUE==ECONNRESET) lprintf(LOG_ERR,"connection reset by peer on send"); else if(ERROR_VALUE==ECONNABORTED) lprintf(LOG_ERR,"connection aborted by peer on send"); else lprintf(LOG_ERR,"ERROR %d sending on socket %d" ,ERROR_VALUE, sock); break; } if(debug_tx) dump(buf+bufbot,i); if(i!=(int)(buftop-bufbot)) { lprintf(LOG_ERR,"Short socket send (%u instead of %u)" ,i ,buftop-bufbot); short_sends++; } bufbot+=i; total_sent+=i; total_pkts++; } if(total_sent) sprintf(stats,"(sent %lu bytes in %lu blocks, %lu average, %lu short, %lu errors)" ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors); else stats[0]=0; lprintf(LOG_DEBUG,"output thread terminated\n%s", stats); }
//***************************************************************************** // // Gets a message from the UART buffer. // // \param pui8Msg is a pointer to storage allocated by the caller where the // message will be copied to. // // \param ui16Length is the length of the pui8Msg buffer. // // Copies a message from the UART buffer to the \e pui8Msg caller supplied // storage. If the caller supplied storage length is less than the next // UART message length then the UART message is dumped and no data is returned. // Therefore it is critical to make sure that caller supplies sufficient length // for the longest anticipated message from the RNP. 256 bytes is recommended. // // \return None. // //***************************************************************************** void RemoTIUARTGetMsg(uint8_t* pui8Msg, uint_fast16_t ui16Length) { bool bIntState; uint8_t ui8MsgLength; uint8_t ui8SOF; // // State previous state of master interrupt enable then disable all // interrupts. // bIntState = IntMasterDisable(); // // Determine if a message is in the buffer available for the caller. // if(g_ui16RxMsgCount != 0) { // // Read out the SOF and Msg Length characters. // ui8SOF = RingBufReadOne(&g_rbRemoTIRxRingBuf); ui8MsgLength = RingBufReadOne(&g_rbRemoTIRxRingBuf); // // Make sure that the user buffer has room for the message and the // packet overhead bytes. // if((ui8MsgLength + 5) <= ui16Length) { // // We have enough room, so store the two already bytes in the user // buffer. // pui8Msg[0] = ui8SOF; pui8Msg[1] = ui8MsgLength; // // Read the remaining bytes to the user buffer. // RingBufRead(&g_rbRemoTIRxRingBuf, pui8Msg + 2, ui8MsgLength + 3); } else { // // The user did not provide enough room and we cannot easily put // the first couple of bytes back into the buffer. Therefore, // we dump the remainder of the message. // RingBufAdvanceRead(&g_rbRemoTIRxRingBuf, ui8MsgLength + 3); } // // Decrement the msg counter. Now one less message in the UART buffer. // g_ui16RxMsgCount -= 1; } // // Restore the master interrupt enable state. // if(!bIntState) { IntMasterEnable(); } // // Finished. // }
void sbbs_t::telnet_gate(char* destaddr, ulong mode, char* client_user_name, char* server_user_name, char* term_type) { char* p; uchar buf[512]; int i; int rd; uint attempts; ulong l; bool gotline; ushort port; ulong ip_addr; ulong save_console; SOCKET remote_socket; SOCKADDR_IN addr; if(mode&TG_RLOGIN) port=513; else port=IPPORT_TELNET; p=strchr(destaddr,':'); if(p!=NULL) { *p=0; port=atoi(p+1); } ip_addr=resolve_ip(destaddr); if(ip_addr==INADDR_NONE) { lprintf(LOG_NOTICE,"!TELGATE Failed to resolve address: %s",destaddr); bprintf("!Failed to resolve address: %s\r\n",destaddr); return; } if((remote_socket = open_socket(SOCK_STREAM, client.protocol)) == INVALID_SOCKET) { errormsg(WHERE,ERR_OPEN,"socket",0); return; } memset(&addr,0,sizeof(addr)); addr.sin_addr.s_addr = htonl(startup->telnet_interface); addr.sin_family = AF_INET; if((i=bind(remote_socket, (struct sockaddr *) &addr, sizeof (addr)))!=0) { lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) binding to socket %d",i, ERROR_VALUE, remote_socket); bprintf("!ERROR %d (%d) binding to socket\r\n",i, ERROR_VALUE); close_socket(remote_socket); return; } memset(&addr,0,sizeof(addr)); addr.sin_addr.s_addr = ip_addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); if((i=connect(remote_socket, (struct sockaddr *)&addr, sizeof(addr)))!=0) { lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) connecting to server: %s" ,i,ERROR_VALUE, destaddr); bprintf("!ERROR %d (%d) connecting to server: %s\r\n" ,i,ERROR_VALUE, destaddr); close_socket(remote_socket); return; } l=1; if((i = ioctlsocket(remote_socket, FIONBIO, &l))!=0) { lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) disabling socket blocking" ,i, ERROR_VALUE); close_socket(remote_socket); return; } lprintf(LOG_INFO,"Node %d %s gate to %s port %u on socket %d" ,cfg.node_num ,mode&TG_RLOGIN ? "RLogin" : "Telnet" ,destaddr,port,remote_socket); if(!(mode&TG_CTRLKEYS)) console|=CON_RAW_IN; if(mode&TG_RLOGIN) { p=(char*)buf; *(p++)=0; p+=sprintf(p,"%s",client_user_name==NULL ? useron.alias : client_user_name); p++; // Add NULL p+=sprintf(p,"%s",server_user_name==NULL ? useron.name : server_user_name); p++; // Add NULL if(term_type!=NULL) p+=sprintf(p,"%s",term_type); else p+=sprintf(p,"%s/%u",terminal, cur_rate); p++; // Add NULL l=p-(char*)buf; sendsocket(remote_socket,(char*)buf,l); mode|=TG_NOLF; /* Send LF (to remote host) when Telnet client sends CRLF (when not in binary mode) */ } /* This is required for gating to Unix telnetd */ if(mode&TG_NOTERMTYPE) request_telnet_opt(TELNET_DONT,TELNET_TERM_TYPE, 3000); // Re-negotiation of terminal type /* Text/NVT mode by default */ request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX, 3000); if(!(telnet_mode&TELNET_MODE_OFF) && (mode&TG_PASSTHRU)) telnet_mode|=TELNET_MODE_GATE; // Pass-through telnet commands while(online) { if(!(mode&TG_NOCHKTIME)) gettimeleft(); rd=RingBufRead(&inbuf,buf,sizeof(buf)); if(rd) { #if 0 if(memchr(buf,TELNET_IAC,rd)) { char dump[2048]; dump[0]; p=dump; for(int i=0;i<rd;i++) p+=sprintf(p,"%u ",buf[i]); lprintf(LOG_DEBUG,"Node %d Telnet cmd from client: %s", cfg.node_num, dump); } #endif if(telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL) { if(*buf==0x1d) { // ^] save_console=console; console&=~CON_RAW_IN; // Allow Ctrl-U/Ctrl-P CRLF; while(online) { SYNC; mnemonics("\1n\r\n\1h\1bTelnet Gate: \1y~D\1wisconnect, " "\1y~E\1wcho toggle, \1y~L\1wist Users, \1y~P\1wrivate message, " "\1y~Q\1wuit: "); switch(getkeys("DELPQ",0)) { case 'D': closesocket(remote_socket); break; case 'E': mode^=TG_ECHO; bprintf(text[EchoIsNow] ,mode&TG_ECHO ? text[ON]:text[OFF]); continue; case 'L': whos_online(true); continue; case 'P': nodemsg(); continue; } break; } attr(LIGHTGRAY); console=save_console; } else if(*buf<' ' && (mode&TG_CTRLKEYS)) handle_ctrlkey(*buf, K_NONE); gotline=false; if((mode&TG_LINEMODE) && buf[0]!='\r') { ungetkey(buf[0]); l=K_CHAT; if(!(mode&TG_ECHO)) l|=K_NOECHO; rd=getstr((char*)buf,sizeof(buf)-1,l); if(!rd) continue; strcat((char*)buf,crlf); rd+=2; gotline=true; } if((mode&TG_CRLF) && buf[rd-1]=='\r') buf[rd++]='\n'; else if((mode&TG_NOLF) && buf[rd-1]=='\n') rd--; if(!gotline && (mode&TG_ECHO) && rd) { RingBufWrite(&outbuf,buf,rd); } } /* Not Telnet Binary mode */ if(rd > 0) { for(attempts=0;attempts<60 && online; attempts++) /* added retry loop here, Jan-20-2003 */ { if((i=sendsocket(remote_socket,(char*)buf,rd))>=0) break; if(ERROR_VALUE!=EWOULDBLOCK) break; mswait(500); } if(i<0) { lprintf(LOG_NOTICE,"!TELGATE ERROR %d sending on socket %d",ERROR_VALUE,remote_socket); break; } } } rd=recv(remote_socket,(char*)buf,sizeof(buf),0); if(rd<0) { if(ERROR_VALUE==EWOULDBLOCK) { if(mode&TG_NODESYNC) { SYNC; } else { // Check if the node has been interrupted getnodedat(cfg.node_num,&thisnode,0); if(thisnode.misc&NODE_INTR) break; } YIELD(); continue; } lprintf(LOG_NOTICE,"!TELGATE ERROR %d receiving on socket %d",ERROR_VALUE,remote_socket); break; } if(!rd) { lprintf(LOG_INFO,"Node %d Telnet gate disconnected",cfg.node_num); break; } #if 0 if(memchr(buf,TELNET_IAC,rd)) { char dump[2048]; dump[0]; p=dump; for(int i=0;i<rd;i++) p+=sprintf(p,"%u ",buf[i]); lprintf(LOG_DEBUG,"Node %d Telnet cmd from server: %s", cfg.node_num, dump); } #endif RingBufWrite(&outbuf,buf,rd); } console&=~CON_RAW_IN; telnet_mode&=~TELNET_MODE_GATE; /* Disable Telnet Terminal Echo */ request_telnet_opt(TELNET_WILL,TELNET_ECHO); close_socket(remote_socket); lprintf(LOG_INFO,"Node %d Telnet gate to %s finished",cfg.node_num,destaddr); }