From 4848ddb3ff044721cbd23b68e8c2d1d72b10832f Mon Sep 17 00:00:00 2001 From: Kevin Primm Date: Tue, 28 Nov 2023 00:29:48 -0500 Subject: [PATCH] Adapted socket module to macos/POSIX --- src/modules/bb/sockets/CMakeLists.txt | 2 +- src/modules/bb/sockets/sockets.cpp | 136 ++++++++++++++------------ src/modules/bb/string/string.cpp | 3 +- test/all.bb | 1 + test/modules/sockets.bb | 71 ++++++++++++++ 5 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 test/modules/sockets.bb diff --git a/src/modules/bb/sockets/CMakeLists.txt b/src/modules/bb/sockets/CMakeLists.txt index fd38eec5..1c8479e9 100644 --- a/src/modules/bb/sockets/CMakeLists.txt +++ b/src/modules/bb/sockets/CMakeLists.txt @@ -1,4 +1,4 @@ -IF(BB_DESKTOP) +IF(NOT BB_EMSCRIPTEN) bb_start_module(sockets) set(DEPENDS_ON bb.stream) set(SOURCES sockets.cpp sockets.h) diff --git a/src/modules/bb/sockets/sockets.cpp b/src/modules/bb/sockets/sockets.cpp index a8f0929b..4e3526d4 100644 --- a/src/modules/bb/sockets/sockets.cpp +++ b/src/modules/bb/sockets/sockets.cpp @@ -15,19 +15,32 @@ #include #include #include +#include +#include +#include typedef int SOCKET; typedef hostent HOSTENT; +#define ioctlsocket(fd,flags,ptr) ioctl(fd,flags,ptr) +#define closesocket(fd) close(fd) +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 #else typedef int socklen_t; #endif -#ifndef FIXME +#ifdef WIN32 #include #endif +#ifdef WIN32 +#define S_ADDR( a ) a.S_un.S_addr +#else +#define S_ADDR( a ) a.s_addr +#endif + static bool socks_ok=0; -#ifndef FIXME +#ifdef WIN32 static WSADATA wsadata; #endif static int recv_timeout; @@ -35,13 +48,13 @@ static int read_timeout; static int accept_timeout; static void close( SOCKET sock,int e ){ -#ifndef FIXME if( e<0 ){ int opt=1; +#ifndef FIXME setsockopt( sock,SOL_SOCKET,SO_DONTLINGER,(char*)&opt,sizeof(opt) ); +#endif } closesocket( sock ); -#endif } class UDPStream; @@ -112,7 +125,6 @@ int UDPStream::eof(){ //fill buffer, return sender int UDPStream::recv(){ -#ifndef FIXME if( e ) return 0; int tout; if( recv_timeout ) tout=bbMilliSecs()+recv_timeout; @@ -122,70 +134,59 @@ int UDPStream::recv(){ dt=tout-bbMilliSecs(); if( dt<0 ) dt=0; } +#ifdef WIN32 fd_set fd={ 1,sock }; timeval tv={ dt/1000,(dt%1000)*1000 }; int n=::select( 0,&fd,0,0,&tv ); +#else + pollfd fd={ sock,POLLIN|POLLPRI,0 }; + int n=poll( &fd,1,recv_timeout ); + if( !(fd.revents&POLLIN) ) return 0; +#endif if( !n ) return 0; if( n!=1 ){ e=-1;return 0; } +#ifdef WIN32 unsigned long sz=-1; +#else + int sz=-1; +#endif if( ioctlsocket( sock,FIONREAD,&sz ) ){ e=-1;return 0; } in_buf.resize( sz );in_get=0; - int len=sizeof(in_addr); + socklen_t len=sizeof(in_addr); n=::recvfrom( sock,&in_buf[0],sz,0,(sockaddr*)&in_addr,&len ); if( n==SOCKET_ERROR ) continue; //{ e=-1;return 0; } in_buf.resize( n ); return getMsgIP(); } -#endif return 0; } //send, empty buffer int UDPStream::send( int ip,int port ){ -#ifdef FIXME - return 0; -#else if( e ) return 0; int sz=out_buf.size(); - out_addr.sin_addr.S_un.S_addr=htonl( ip ); + S_ADDR(out_addr.sin_addr)=htonl( ip ); out_addr.sin_port=htons( port ? port : addr.sin_port ); int n=::sendto( sock,&out_buf[0],sz,0,(sockaddr*)&out_addr,sizeof(out_addr) ); if( n!=sz ) return e=-1; out_buf.clear(); return sz; -#endif } int UDPStream::getIP(){ -#ifdef FIXME - return 0; -#else - return ntohl( addr.sin_addr.S_un.S_addr ); -#endif + return ntohl( S_ADDR( addr.sin_addr ) ); } int UDPStream::getPort(){ -#ifdef FIXME - return 0; -#else return ntohs( addr.sin_port ); -#endif } int UDPStream::getMsgIP(){ -#ifdef FIXME - return 0; -#else - return ntohl( in_addr.sin_addr.S_un.S_addr ); -#endif + return ntohl( S_ADDR( in_addr.sin_addr ) ); } int UDPStream::getMsgPort(){ -#ifdef FIXME - return 0; -#else return ntohs( in_addr.sin_port ); -#endif } class TCPStream : public BBStream{ @@ -223,29 +224,22 @@ class TCPServer{ }; TCPStream::TCPStream( SOCKET s,TCPServer *t ):sock(s),server(t),e(0){ -#ifndef FIXME sockaddr_in addr; - int len=sizeof(addr); + socklen_t len=sizeof(addr); if( getpeername( s,(sockaddr*)&addr,&len ) ){ ip=port=0; return; } - ip=ntohl(addr.sin_addr.S_un.S_addr); + ip=ntohl( S_ADDR(addr.sin_addr ) ); port=ntohs(addr.sin_port); -#endif } TCPStream::~TCPStream(){ if( server ) server->remove( this ); -#ifndef FIXME close( sock,e ); -#endif } int TCPStream::read( char *buff,int size ){ -#ifdef FIXME - return 0; -#else if( e ) return 0; char *b=buff,*l=buff+size; int tout; @@ -256,39 +250,40 @@ int TCPStream::read( char *buff,int size ){ dt=tout-bbMilliSecs(); if( dt<0 ) dt=0; } - fd_set fd={ 1,sock }; timeval tv={ dt/1000,(dt%1000)*1000 }; +#ifdef WIN32 + fd_set fd={ 1,sock }; int n=::select( 0,&fd,0,0,&tv ); if( n!=1 ){ e=-1;break; } +#else + pollfd fd={ sock,POLLIN|POLLPRI,0 }; + int n=poll( &fd,1,read_timeout ); + if( !(fd.revents&POLLIN) ){ e=-1;break; } +#endif n=::recv( sock,b,l-b,0 ); if( n==0 ){ e=1;break; } if( n==SOCKET_ERROR ){ e=-1;break; } b+=n; } return b-buff; -#endif } int TCPStream::write( const char *buff,int size ){ -#ifdef FIXME - return 0; -#else if( e ) return 0; int n=::send( sock,buff,size,0 ); if( n==SOCKET_ERROR ){ e=-1;return 0; } return n; -#endif } int TCPStream::avail(){ -#ifdef FIXME - return 0; +#ifdef WIN32 + unsigned long t=-1; #else - unsigned long t; + int t=-1; +#endif int n=::ioctlsocket( sock,FIONREAD,&t ); if( n==SOCKET_ERROR ){ e=-1;return 0; } return t; -#endif } int TCPStream::eof(){ @@ -315,26 +310,24 @@ TCPServer::TCPServer( SOCKET s ):sock(s),e(0){ } TCPServer::~TCPServer(){ - while( accepted_set.size() ) delete *accepted_set.begin(); + while( accepted_set.size() ) bbCloseTCPStream( *accepted_set.begin() ); close( sock,e ); } TCPStream *TCPServer::accept(){ -#ifdef FIXME - return 0; -#else if( e ) return 0; +#ifdef WIN32 fd_set fd={ 1,sock }; timeval tv={ accept_timeout/1000,(accept_timeout%1000)*1000 }; int n=::select( 0,&fd,0,0,&tv ); if( n==0 ) return 0; if( n!=1 ){ e=-1;return 0; } +#endif SOCKET t=::accept( sock,0,0 ); if( t==INVALID_SOCKET ){ e=-1;return 0; } TCPStream *s=d_new TCPStream( t,this ); accepted_set.insert( s ); return s; -#endif } void TCPServer::remove( TCPStream *s ){ @@ -362,6 +355,9 @@ static inline void debugTCPServer( TCPServer *p ){ static std::vector host_ips; bb_int_t BBCALL bbCountHostIPs( BBStr *host ){ +#ifndef WIN32 + if( *host=="" ) *host="localhost"; +#endif host_ips.clear(); HOSTENT *h=gethostbyname( host->c_str() ); delete host;if( !h ) return 0; @@ -380,11 +376,14 @@ bb_int_t BBCALL bbHostIP( bb_int_t index ){ } UDPStream * BBCALL bbCreateUDPStream( bb_int_t port ){ -#ifndef FIXME if( !socks_ok ) return 0; SOCKET s=::socket( AF_INET,SOCK_DGRAM,0 ); if( s!=INVALID_SOCKET ){ +#ifndef BB_MACOS sockaddr_in addr={AF_INET,htons(port)}; +#else + sockaddr_in addr={sizeof(sockaddr_in),AF_INET,htons(port)}; +#endif if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ UDPStream *p=d_new UDPStream( s ); udp_set.insert( p ); @@ -392,7 +391,6 @@ UDPStream * BBCALL bbCreateUDPStream( bb_int_t port ){ } ::closesocket( s ); } -#endif return 0; } @@ -442,7 +440,6 @@ BBStr * BBCALL bbDottedIP( bb_int_t ip ){ itoa((ip>>8)&255)+"."+itoa(ip&255) ); } -#ifndef FIXME static int findHostIP( const std::string &t ){ int ip=inet_addr( t.c_str() ); if( ip!=INADDR_NONE ) return ip; @@ -454,10 +451,8 @@ static int findHostIP( const std::string &t ){ } return 0; } -#endif TCPStream * BBCALL bbOpenTCPStream( BBStr *server,bb_int_t port,bb_int_t local_port ){ -#ifndef FIXME if( !socks_ok ){ delete server; return 0; @@ -467,14 +462,22 @@ TCPStream * BBCALL bbOpenTCPStream( BBStr *server,bb_int_t port,bb_int_t local_p SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); if( s!=INVALID_SOCKET ){ if( local_port ){ +#ifndef BB_MACOS sockaddr_in addr={AF_INET,htons(local_port)}; +#else + sockaddr_in addr={sizeof(sockaddr_in),AF_INET,htons(local_port)}; +#endif if( ::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ ::closesocket( s ); return 0; } } +#ifndef BB_MACOS sockaddr_in addr={AF_INET,htons(port)}; - addr.sin_addr.S_un.S_addr=ip; +#else + sockaddr_in addr={sizeof(sockaddr_in),AF_INET,htons(port)}; +#endif + S_ADDR(addr.sin_addr)=ip; if( !::connect( s,(sockaddr*)&addr,sizeof(addr) ) ){ TCPStream *p=d_new TCPStream( s,0 ); tcp_set.insert( p ); @@ -482,7 +485,6 @@ TCPStream * BBCALL bbOpenTCPStream( BBStr *server,bb_int_t port,bb_int_t local_p } ::closesocket( s ); } -#endif return 0; } @@ -493,10 +495,13 @@ void BBCALL bbCloseTCPStream( TCPStream *p ){ } TCPServer * BBCALL bbCreateTCPServer( bb_int_t port ){ -#ifndef FIXME SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); if( s!=INVALID_SOCKET ){ +#ifndef BB_MACOS sockaddr_in addr={AF_INET,htons(port)}; +#else + sockaddr_in addr={sizeof(sockaddr_in),AF_INET,htons(port)}; +#endif if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ if( !::listen( s,SOMAXCONN ) ){ TCPServer *p=d_new TCPServer( s ); @@ -506,7 +511,6 @@ TCPServer * BBCALL bbCreateTCPServer( bb_int_t port ){ } ::closesocket(s); } -#endif return 0; } @@ -542,8 +546,10 @@ void BBCALL bbTCPTimeouts( bb_int_t rt,bb_int_t at ){ } BBMODULE_CREATE( sockets ){ -#ifndef FIXME +#ifdef WIN32 socks_ok=WSAStartup( 0x0101,&wsadata )==0; +#else + socks_ok=true; #endif recv_timeout=0; read_timeout=10000; @@ -555,7 +561,7 @@ BBMODULE_DESTROY( sockets ){ while( udp_set.size() ) bbCloseUDPStream( *udp_set.begin() ); while( tcp_set.size() ) bbCloseTCPStream( *tcp_set.begin() ); while( server_set.size() ) bbCloseTCPServer( *server_set.begin() ); -#ifndef FIXME +#ifdef WIN32 if( socks_ok ) WSACleanup(); #endif return true; diff --git a/src/modules/bb/string/string.cpp b/src/modules/bb/string/string.cpp index 8fcdb21e..1bd6fb8b 100644 --- a/src/modules/bb/string/string.cpp +++ b/src/modules/bb/string/string.cpp @@ -15,7 +15,8 @@ BBStr * BBCALL bbString( BBStr *s,bb_int_t n ){ BBStr * BBCALL bbLeft( BBStr *s,bb_int_t n ){ CHKPOS( n ); const char *last=s->data(); - while( n-->0 ){ + const char *end=last+s->size(); + while( n-->0&&last0,"At least one IP for localhost" +ExpectStr DottedIP(HostIP(1)),"127.0.0.1" + +; TCP +TCPTimeouts 1000,1000 + +tcp=OpenTCPStream( "github.com",80,8080 ) +Expect tcp, "Opened TCP stream" +Expect TCPStreamIP(tcp)<>0,"TCP stream has IP" +ExpectInt TCPStreamPort(tcp),80,"TCP stream is on port 80" + +WriteLine tcp,"GET / HTTP/1.0" +WriteLine tcp,"" + +res$="" +While Not Eof(tcp) + res=res+ReadLine$( tcp )+Chr(10) +Wend +Expect Instr( res, "HTTP/1.1 301 Moved Permanently")>0,"Expect 301 response" + +CloseTCPStream tcp + +SeedRnd MilliSecs() +server_port=9090+Rand(0, 100) ; a little dangerous, but avoid issues in dev + +tcp_server=CreateTCPServer( server_port ) +Expect tcp_server,"Creates a TCP server on port "+server_port + +tcp_out=OpenTCPStream( "127.0.0.1",server_port ) +Expect tcp_out,"Opens a TCP connection to the server" +WriteLine tcp_out,"hello, world" + +tcp_in=AcceptTCPStream(tcp_server) +Expect tcp_in,"Accepts the TCP connection" +ExpectStr ReadLine(tcp_in),"hello, world" + +CloseTCPServer tcp_server + +; UDP +UDPTimeouts 1000 + +udp_out=CreateUDPStream( 8080 ) +Expect udp_out<>0,"Opened outgoing UDP socket" +ExpectInt UDPStreamIP(udp_out),0 +ExpectInt UDPStreamPort(udp_out),8080 + +udp_in=CreateUDPStream( 8081 ) +Expect udp_in<>0,"Opened incoming UDP socket" +ExpectInt UDPStreamIP(udp_in),0 +ExpectInt UDPStreamPort(udp_in),8081,"Incoming socket is on port 8081" + +For i=0 To 9 ; send a bunch just to be safe... + WriteString udp_out,"hello world" + SendUDPMsg udp_out,HostIP(1),8081 +Next + +ExpectInt RecvUDPMsg(udp_in),HostIP(1),"Receives a message" +ExpectInt UDPMsgIP(udp_in),HostIP(1) +ExpectInt UDPMsgPort(udp_in),8080 + +Expect ReadAvail(udp_in)>0,"There is message content" +ExpectStr ReadString(udp_in),"hello world" +Expect Eof(udp_in),"udp_in EOF" + +CloseUDPStream udp_in +CloseUDPStream udp_out