static void send_telnet_cmd(uchar cmd, uchar opt) { char buf[16]; if(cmd<TELNET_WILL) { if(debug_telnet) lprintf(LOG_INFO,"TX Telnet command: %s" ,telnet_cmd_desc(cmd)); sprintf(buf,"%c%c",TELNET_IAC,cmd); sendsocket(sock,buf,2); } else { if(debug_telnet) lprintf(LOG_INFO,"TX Telnet command: %s %s" ,telnet_cmd_desc(cmd), telnet_opt_desc(opt)); sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt); sendsocket(sock,buf,3); } }
void input_thread(void* arg) { BYTE ch; lprintf(LOG_DEBUG,"Input thread started"); while(!call_terminated) { if(!comReadByte(com_handle, &ch)) { YIELD(); continue; } if(telnet && ch==TELNET_IAC) sendsocket(sock, &ch, sizeof(ch)); /* escape Telnet IAC char (255) when in telnet mode */ sendsocket(sock, &ch, sizeof(ch)); bytes_received++; } lprintf(LOG_DEBUG,"Input thread terminated"); input_thread_terminated=TRUE; }
void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt) { uchar buf[3]; buf[0]=TELNET_IAC; buf[1]=cmd; buf[2]=opt; if(debug_telnet) lprintf(LOG_DEBUG,"Sending telnet command: %s %s" ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2])); if(sendsocket(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet) lprintf(LOG_ERR,"FAILED"); }
int send_byte(void* unused, uchar ch, unsigned timeout) { uchar buf[2] = { TELNET_IAC, TELNET_IAC }; int len=1; int i; fd_set socket_set; struct timeval tv; FD_ZERO(&socket_set); #ifdef __unix__ if(stdio) FD_SET(STDOUT_FILENO,&socket_set); else #endif FD_SET(sock,&socket_set); tv.tv_sec=timeout; tv.tv_usec=0; if(select(sock+1,NULL,&socket_set,NULL,&tv)<1) return(ERROR_VALUE); if(telnet && ch==TELNET_IAC) /* escape IAC char */ len=2; else buf[0]=ch; #ifdef __unix__ if(stdio) i=write(STDOUT_FILENO,buf,len); else #endif i=sendsocket(sock,buf,len); if(i==len) { if(debug_tx) lprintf(LOG_DEBUG,"TX: %s",chr(ch)); return(0); } return(-1); }
void ident_server_thread(void* arg) { int result; SOCKET sock; SOCKADDR_IN server_addr={0}; fd_set socket_set; struct timeval tv; lprintf(LOG_DEBUG,"Ident server thread started"); if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { lprintf(LOG_ERR,"ERROR %u creating socket", ERROR_VALUE); return; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_addr.s_addr = htonl(ident_interface); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(ident_port); if(bind(sock,(struct sockaddr *)&server_addr,sizeof(server_addr))!=0) { lprintf(LOG_ERR,"ERROR %u binding ident server socket", ERROR_VALUE); close_socket(&sock); return; } if(listen(sock, 1)) { lprintf(LOG_ERR,"!ERROR %u listening on ident server socket", ERROR_VALUE); close_socket(&sock); return; } while(!terminated) { /* now wait for connection */ FD_ZERO(&socket_set); FD_SET(sock,&socket_set); tv.tv_sec=5; tv.tv_usec=0; if((result=select(sock+1,&socket_set,NULL,NULL,&tv))<1) { if(result==0) continue; if(ERROR_VALUE==EINTR) lprintf(LOG_DEBUG,"Ident Server listening interrupted"); else if(ERROR_VALUE == ENOTSOCK) lprintf(LOG_NOTICE,"Ident Server sockets closed"); else lprintf(LOG_WARNING,"!ERROR %d selecting ident socket",ERROR_VALUE); continue; } if(FD_ISSET(sock,&socket_set)) { SOCKADDR_IN client_addr; socklen_t client_addr_len; SOCKET client_socket=INVALID_SOCKET; char request[128]; char response[256]; int rd; client_addr_len = sizeof(client_addr); client_socket = accept(sock, (struct sockaddr *)&client_addr, &client_addr_len); if(client_socket != INVALID_SOCKET) { lprintf(LOG_INFO,"Ident request from %s : %u" ,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); FD_ZERO(&socket_set); FD_SET(client_socket,&socket_set); tv.tv_sec=5; tv.tv_usec=0; if(select(client_socket+1,&socket_set,NULL,NULL,&tv)==1) { lprintf(LOG_DEBUG,"Ident select"); if((rd=recv(client_socket, request, sizeof(request), 0)) > 0) { request[rd]=0; truncsp(request); lprintf(LOG_INFO,"Ident request: %s", request); /* example response: "40931,23:USERID:UNIX:cyan" */ SAFEPRINTF4(response,"%s:%s:%s %s\r\n" ,request, ident_response, cid_number, cid_name); sendsocket(client_socket,response,strlen(response)); } else lprintf(LOG_DEBUG,"ident recv=%d %d", rd, ERROR_VALUE); } close_socket(&client_socket); } } } close_socket(&sock); lprintf(LOG_DEBUG,"Ident server thread terminated"); }
BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen) { BYTE command; BYTE option; BYTE* first_iac; int i; if(inlen<1) { *outlen=0; return(inbuf); /* no length? No interpretation */ } first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen); if(!telnet_cmdlen && first_iac==NULL) { *outlen=inlen; return(inbuf); /* no interpretation needed */ } if(first_iac!=NULL) { *outlen=first_iac-inbuf; memcpy(outbuf, inbuf, *outlen); } else *outlen=0; for(i=*outlen;i<inlen;i++) { if(inbuf[i]==TELNET_IAC && telnet_cmdlen==1) { /* escaped 255 */ telnet_cmdlen=0; outbuf[(*outlen)++]=TELNET_IAC; continue; } if(inbuf[i]==TELNET_IAC || telnet_cmdlen) { if(telnet_cmdlen<sizeof(telnet_cmd)) telnet_cmd[telnet_cmdlen++]=inbuf[i]; command = telnet_cmd[1]; option = telnet_cmd[2]; if(telnet_cmdlen>=2 && command==TELNET_SB) { if(inbuf[i]==TELNET_SE && telnet_cmd[telnet_cmdlen-2]==TELNET_IAC) { if(debug_telnet) lprintf(LOG_INFO,"RX Telnet sub-negotiation command: %s" ,telnet_opt_desc(option)); /* sub-option terminated */ if(option==TELNET_TERM_TYPE && telnet_cmd[3]==TELNET_TERM_SEND) { BYTE buf[32]; int len=sprintf(buf,"%c%c%c%c%s%c%c" ,TELNET_IAC,TELNET_SB ,TELNET_TERM_TYPE,TELNET_TERM_IS ,termtype ,TELNET_IAC,TELNET_SE); if(debug_telnet) lprintf(LOG_INFO,"TX Telnet command: Terminal Type is %s", termtype); sendsocket(sock,buf,len); /* request_telnet_opt(TELNET_WILL, TELNET_TERM_SPEED); */ } else if(option==TELNET_TERM_SPEED && telnet_cmd[3]==TELNET_TERM_SEND) { BYTE buf[32]; int len=sprintf(buf,"%c%c%c%c%s%c%c" ,TELNET_IAC,TELNET_SB ,TELNET_TERM_SPEED,TELNET_TERM_IS ,termspeed ,TELNET_IAC,TELNET_SE); if(debug_telnet) lprintf(LOG_INFO,"TX Telnet command: Terminal Speed is %s", termspeed); sendsocket(sock,buf,len); } telnet_cmdlen=0; } } else if(telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) { telnet_cmdlen=0; } else if(telnet_cmdlen>=3) { /* telnet option negotiation */ if(debug_telnet) lprintf(LOG_INFO,"RX Telnet command: %s %s" ,telnet_cmd_desc(command),telnet_opt_desc(option)); if(command==TELNET_DO || command==TELNET_DONT) { /* local options */ if(telnet_local_option[option]!=command) { switch(option) { case TELNET_BINARY_TX: case TELNET_ECHO: case TELNET_TERM_TYPE: case TELNET_TERM_SPEED: case TELNET_SUP_GA: telnet_local_option[option]=command; send_telnet_cmd(telnet_opt_ack(command),option); break; case TELNET_SEND_LOCATION: if(command==TELNET_DO) { BYTE buf[128]; int len=safe_snprintf(buf,sizeof(buf),"%c%c%c%s %s%c%c" ,TELNET_IAC,TELNET_SB ,TELNET_SEND_LOCATION ,cid_number, cid_name ,TELNET_IAC,TELNET_SE); if(debug_telnet) lprintf(LOG_INFO,"TX Telnet command: Location is %s %s", cid_number, cid_name); sendsocket(sock,buf,len); } else send_telnet_cmd(telnet_opt_ack(command),option); break; default: /* unsupported local options */ if(command==TELNET_DO) /* NAK */ send_telnet_cmd(telnet_opt_nak(command),option); break; } } } else { /* WILL/WONT (remote options) */ if(telnet_remote_option[option]!=command) { switch(option) { case TELNET_BINARY_TX: case TELNET_ECHO: case TELNET_TERM_TYPE: case TELNET_SUP_GA: telnet_remote_option[option]=command; send_telnet_cmd(telnet_opt_ack(command),option); break; default: /* unsupported remote options */ if(command==TELNET_WILL) /* NAK */ send_telnet_cmd(telnet_opt_nak(command),option); break; } } } telnet_cmdlen=0; } } else outbuf[(*outlen)++]=inbuf[i]; } return(outbuf); }
bool sbbs_t::ftp_put(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest) { char cmd[512]; char rsp[512]; char path[MAX_PATH+1]; char buf[4097]; int rd; int result; ulong total=0; SOCKET data_sock; union xp_sockaddr addr; socklen_t addr_len; FILE* fp=NULL; bool error=false; struct timeval tv; fd_set socket_set; SAFECOPY(path,src); if(!fexistcase(path)) return(false); if((data_sock=ftp_data_sock(csi, ctrl_sock, &addr.in))==INVALID_SOCKET) { bprintf("ftp: failure, line %d",__LINE__); return(false); } if(csi->ftp_mode&CS_FTP_PASV) { #if 0 // Debug bprintf("Connecting to %s:%hd\r\n" ,inet_ntoa(addr.in.sin_addr) ,ntohs(addr.in.sin_port)); #endif if(connect(data_sock,&addr.addr,sizeof(addr.in))!=0) { bprintf("ftp: failure, line %d",__LINE__); csi->socket_error=ERROR_VALUE; close_socket(data_sock); return(false); } } if((fp=fopen(path,"rb"))==NULL) { bprintf("ftp: failure, line %d",__LINE__); close_socket(data_sock); return(false); } sprintf(cmd,"STOR %s",dest); if(!ftp_cmd(csi,ctrl_sock,cmd,rsp) || atoi(rsp)!=150 /* Open data connection */) { bprintf("ftp: failure, line %d",__LINE__); close_socket(data_sock); return(false); } if(!(csi->ftp_mode&CS_FTP_PASV)) { /* Normal (Active) FTP */ /* Setup for select() */ tv.tv_sec=TIMEOUT_SOCK_LISTEN; tv.tv_usec=0; FD_ZERO(&socket_set); FD_SET(data_sock,&socket_set); result=select(data_sock+1,&socket_set,NULL,NULL,&tv); if(result<1) { csi->socket_error=ERROR_VALUE; closesocket(data_sock); return(false); } SOCKET accept_sock; addr_len=sizeof(addr); if((accept_sock=accept_socket(data_sock,&addr,&addr_len)) ==INVALID_SOCKET) { csi->socket_error=ERROR_VALUE; closesocket(data_sock); return(false); } close_socket(data_sock); data_sock=accept_sock; } while(online && !feof(fp)) { rd=fread(buf,sizeof(char),sizeof(buf),fp); if(rd<1) /* EOF or READ error */ break; if(!socket_check(ctrl_sock,NULL,NULL,0)) break; /* Control connection lost */ if(sendsocket(data_sock,buf,rd)<1) { error=true; break; } total+=rd; if(csi->ftp_mode&CS_FTP_HASH) outchar('#'); } if(csi->ftp_mode&CS_FTP_HASH) { CRLF; } fclose(fp); close_socket(data_sock); if(!ftp_cmd(csi,ctrl_sock,NULL,rsp) || atoi(rsp)!=226 /* Upload complete */) return(false); if(!error) bprintf("ftp: %lu bytes sent.\r\n", total); return(!error); }
/* FTP Command/Response function */ bool sbbs_t::ftp_cmd(csi_t* csi, SOCKET sock, const char* cmdsrc, char* rsp) { char cmd[512]; int len; BOOL data_avail; time_t start; if(cmdsrc!=NULL) { sprintf(cmd,"%s\r\n",cmdsrc); if(csi->ftp_mode&CS_FTP_ECHO_CMD) bputs(cmd); len=strlen(cmd); if(sendsocket(sock,cmd,len)!=len) { csi->socket_error=ERROR_VALUE; return(FALSE); } } if(rsp!=NULL) { int rd; char ch; while(1) { rd=0; start=time(NULL); while(rd<500) { if(!online) return(FALSE); if(!socket_check(sock,&data_avail,NULL,1000)) return(FALSE); if(!data_avail) { if(time(NULL)-start>TIMEOUT_FTP_RESPONSE) { lprintf(LOG_WARNING,"!ftp_cmd: TIMEOUT_FTP_RESPONSE (%d) exceeded" ,TIMEOUT_FTP_RESPONSE); return(FALSE); } continue; } if(recv(sock, &ch, 1, 0)!=1) { csi->socket_error=ERROR_VALUE; return(FALSE); } if(ch=='\n' && rd>=1) break; rsp[rd++]=ch; } rsp[rd-1]=0; if(csi->ftp_mode&CS_FTP_ECHO_RSP) bprintf("%s\r\n",rsp); if(rsp[0]!=' ' && rsp[3]!='-') break; } } return(TRUE); }
/* TODO: IPv6 */ int sbbs_t::exec_net(csi_t* csi) { char str[512],rsp[512],buf[1025],ch,*p,**pp,**pp1,**pp2; ushort w; uint i; BOOL rd; int32_t *lp,*lp1,*lp2; time_t start; switch(*(csi->ip++)) { /* sub-op-code stored as next byte */ case CS_SOCKET_OPEN: lp=getintvar(csi,*(int32_t *)csi->ip); csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(csi->sockets>=MAX_SOCKETS) return(0); if(lp!=NULL) { SOCKET sock=open_socket(SOCK_STREAM, NULL); if(sock!=INVALID_SOCKET) { SOCKADDR_IN addr; memset(&addr,0,sizeof(addr)); addr.sin_addr.s_addr = htonl(startup->outgoing4.s_addr); addr.sin_family = AF_INET; if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) { csi->socket_error=ERROR_VALUE; close_socket(sock); return(0); } *lp=sock; for(i=0;i<csi->sockets;i++) if(!csi->socket[i]) break; csi->socket[i]=*lp; if(i==csi->sockets) csi->sockets++; csi->logic=LOGIC_TRUE; } } return(0); case CS_SOCKET_CLOSE: lp=getintvar(csi,*(int32_t *)csi->ip); csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(lp && *lp) { csi->logic=close_socket((SOCKET)*lp); csi->socket_error=ERROR_VALUE; for(i=0;i<csi->sockets;i++) if(csi->socket[i]==(SOCKET)*lp) csi->socket[i]=0; *lp=0; } return(0); case CS_SOCKET_CHECK: lp=getintvar(csi,*(int32_t *)csi->ip); csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(lp==NULL || *lp==INVALID_SOCKET) return(0); if(socket_check(*lp,NULL,NULL,0)==TRUE) csi->logic=LOGIC_TRUE; else csi->socket_error=ERROR_VALUE; return(0); case CS_SOCKET_CONNECT: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* address */ csi->ip+=4; w=*(ushort *)csi->ip; /* port */ csi->ip+=2; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !*lp || !pp || !*pp || !w) return(0); ulong ip_addr; if((ip_addr=resolve_ip(*pp))==INADDR_NONE) return(0); SOCKADDR_IN addr; memset(&addr,0,sizeof(addr)); addr.sin_addr.s_addr = ip_addr; addr.sin_family = AF_INET; addr.sin_port = htons(w); if((i=connect(*lp, (struct sockaddr *)&addr, sizeof(addr)))!=0) { csi->socket_error=ERROR_VALUE; return(0); } csi->logic=LOGIC_TRUE; return(0); case CS_SOCKET_ACCEPT: lp1=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; csi->socket_error=0; /* TODO */ return(0); case CS_SOCKET_NREAD: lp1=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; lp2=getintvar(csi,*(int32_t *)csi->ip); /* var */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp1 || !lp2) return(0); if(ioctlsocket(*lp1, FIONREAD, (ulong*)lp2)==0) csi->logic=LOGIC_TRUE; else csi->socket_error=ERROR_VALUE; return(0); case CS_SOCKET_PEEK: case CS_SOCKET_READ: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */ csi->ip+=4; w=*(ushort *)csi->ip; /* length */ csi->ip+=2; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp) return(0); if(w<1 || w>sizeof(buf)-1) w=sizeof(buf)-1; if((i=recv(*lp,buf,w ,*(csi->ip-13)==CS_SOCKET_PEEK ? MSG_PEEK : 0))>0) { csi->logic=LOGIC_TRUE; buf[i]=0; if(csi->etx) { p=strchr(buf,csi->etx); if(p) *p=0; } *pp=copystrvar(csi,*pp,buf); } else csi->socket_error=ERROR_VALUE; return(0); case CS_SOCKET_READLINE: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */ csi->ip+=4; w=*(ushort *)csi->ip; /* length */ csi->ip+=2; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp) return(0); if(w<1 || w>sizeof(buf)-1) w=sizeof(buf)-1; start=time(NULL); for(i=0;i<w;) { if(!online) return(1); if(!socket_check(*lp,&rd,NULL,1000)) return(0); if(!rd) { if(time(NULL)-start>TIMEOUT_SOCK_READLINE) { lprintf(LOG_WARNING,"!socket_readline: timeout (%d) exceeded" ,TIMEOUT_SOCK_READLINE); return(0); } continue; } if(recv(*lp, &ch, 1, 0)!=1) { csi->socket_error=ERROR_VALUE; return(0); } if(ch=='\n' && i>=1) break; buf[i++]=ch; } if(i>0 && buf[i-1]=='\r') buf[i-1]=0; else buf[i]=0; if(csi->etx) { p=strchr(buf,csi->etx); if(p) *p=0; } *pp=copystrvar(csi,*pp,buf); csi->logic=LOGIC_TRUE; return(0); case CS_SOCKET_WRITE: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* buffer */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp || !(*pp)) return(0); if(sendsocket(*lp,*pp,strlen(*pp))>0) csi->logic=LOGIC_TRUE; else csi->socket_error=ERROR_VALUE; return(0); /* FTP Functions */ case CS_FTP_LOGIN: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp1=getstrvar(csi,*(int32_t *)csi->ip); /* username */ csi->ip+=4; pp2=getstrvar(csi,*(int32_t *)csi->ip); /* password */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp1 || !pp2) return(0); if(!ftp_cmd(csi,*lp,NULL,rsp)) return(0); if(atoi(rsp)!=220) return(0); sprintf(str,"USER %s",*pp1); if(!ftp_cmd(csi,*lp,str,rsp)) return(0); if(atoi(rsp)==331) { /* Password needed */ sprintf(str,"PASS %s",*pp2); if(!ftp_cmd(csi,*lp,str,rsp)) return(0); } if(atoi(rsp)==230) /* Login successful */ csi->logic=LOGIC_TRUE; return(0); case CS_FTP_LOGOUT: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp) return(0); if(!ftp_cmd(csi,*lp,"QUIT",rsp)) return(0); if(atoi(rsp)==221) /* Logout successful */ csi->logic=LOGIC_TRUE; return(0); case CS_FTP_PWD: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp) return(0); if(!ftp_cmd(csi,*lp,"PWD",rsp)) return(0); if(atoi(rsp)==257) /* pathname */ csi->logic=LOGIC_TRUE; return(0); case CS_FTP_CWD: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp) return(0); sprintf(str,"CWD %s",*pp); if(!ftp_cmd(csi,*lp,str,rsp)) return(0); if(atoi(rsp)==250) csi->logic=LOGIC_TRUE; return(0); case CS_FTP_DIR: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp) return(0); if(ftp_get(csi,*lp,*pp,NULL /* unused */, true /* DIR */)==true) csi->logic=LOGIC_TRUE; return(0); case CS_FTP_DELETE: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp=getstrvar(csi,*(int32_t *)csi->ip); /* path */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp) return(0); sprintf(str,"DELE %s",*pp); if(!ftp_cmd(csi,*lp,str,rsp)) return(0); if(atoi(rsp)==250) csi->logic=LOGIC_TRUE; return(0); case CS_FTP_GET: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp1=getstrvar(csi,*(int32_t *)csi->ip); /* src path */ csi->ip+=4; pp2=getstrvar(csi,*(int32_t *)csi->ip); /* dest path */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp1 || !pp2) return(0); if(ftp_get(csi,*lp,*pp1,*pp2)==true) csi->logic=LOGIC_TRUE; return(0); case CS_FTP_PUT: lp=getintvar(csi,*(int32_t *)csi->ip); /* socket */ csi->ip+=4; pp1=getstrvar(csi,*(int32_t *)csi->ip); /* src path */ csi->ip+=4; pp2=getstrvar(csi,*(int32_t *)csi->ip); /* dest path */ csi->ip+=4; csi->logic=LOGIC_FALSE; csi->socket_error=0; if(!lp || !pp1 || !pp2) return(0); if(ftp_put(csi,*lp,*pp1,*pp2)==true) csi->logic=LOGIC_TRUE; return(0); default: errormsg(WHERE,ERR_CHK,"net sub-instruction",*(csi->ip-1)); return(0); } }
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); }
int DLLCALL sendfilesocket(int sock, int file, off_t *offset, off_t count) { char buf[1024*16]; off_t len; int rd; int wr=0; int total=0; int i; /* sendfile() on Linux may or may not work with non-blocking sockets ToDo */ len=filelength(file); if(offset!=NULL) if(lseek(file,*offset,SEEK_SET)<0) return(-1); if(count<1 || count>len) { count=len; count-=tell(file); /* don't try to read beyond EOF */ } #if USE_SENDFILE while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN) { total+=wr; SLEEP(1); } if(i==0) return((int)count); #endif if(count<0) { errno=EINVAL; return(-1); } while(total<count) { rd=read(file,buf,sizeof(buf)); if(rd==-1) return(-1); if(rd==0) break; for(i=wr=0;i<rd;i+=wr) { wr=sendsocket(sock,buf+i,rd-i); if(wr>0) continue; if(wr==SOCKET_ERROR && ERROR_VALUE==EWOULDBLOCK) { wr=0; SLEEP(1); continue; } return(wr); } if(i!=rd) return(-1); total+=rd; } if(offset!=NULL) (*offset)+=total; return(total); }
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); }