mirror of
https://github.com/QB64Official/qb64.git
synced 2024-07-18 04:45:16 +00:00
Merge branch 'linux_tcpip'
This commit is contained in:
commit
ff27678f98
|
@ -92,7 +92,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
//OS/compiler specific includes
|
//OS/compiler specific includes
|
||||||
#ifdef QB64_WINDOWS
|
#ifdef QB64_WINDOWS
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
|
|
||||||
|
|
||||||
#ifdef QB64_WINDOWS
|
#ifdef QB64_WINDOWS
|
||||||
#include <fcntl.h>
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -22976,6 +22975,7 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
|
|
||||||
|
|
||||||
//Referenced: http://johnnie.jerrata.com/winsocktutorial/
|
//Referenced: http://johnnie.jerrata.com/winsocktutorial/
|
||||||
|
//Much of the unix sockets code based on http://beej.us/guide/bgnet/
|
||||||
#ifdef QB64_WINDOWS
|
#ifdef QB64_WINDOWS
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
|
@ -22983,6 +22983,7 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -22994,33 +22995,45 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
static int32 init=0;
|
static int32 init=0;
|
||||||
if (!init){
|
if (!init){
|
||||||
init=1;
|
init=1;
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
sockVersion = MAKEWORD(1, 1);
|
sockVersion = MAKEWORD(1, 1);
|
||||||
WSAStartup(sockVersion, &wsaData);
|
WSAStartup(sockVersion, &wsaData);
|
||||||
|
#elif defined(QB64_LINUX)
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_done(){
|
void tcp_done(){
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
#elif defined(QB64_LINUX)
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tcp_connection{
|
struct tcp_connection{
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
SOCKET socket;
|
SOCKET socket;
|
||||||
|
#elif defined(QB64_LINUX)
|
||||||
|
int socket;
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
int32 port;//connection to host & clients only
|
int32 port;//connection to host & clients only
|
||||||
uint8 ip4[4];//connection to host only
|
uint8 ip4[4];//connection to host only
|
||||||
uint8* hostname;//clients only
|
uint8* hostname;//clients only
|
||||||
|
int connected;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *tcp_host_open(int64 port){
|
void *tcp_host_open(int64 port){
|
||||||
tcp_init();
|
tcp_init();
|
||||||
if ((port<0)||(port>65535)) return NULL;
|
if ((port<0)||(port>65535)) return NULL;
|
||||||
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
return NULL;
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
//Ref. from 'winsock.h': typedef u_int SOCKET;
|
//Ref. from 'winsock.h': typedef u_int SOCKET;
|
||||||
static SOCKET listeningSocket;
|
static SOCKET listeningSocket;
|
||||||
listeningSocket = socket(AF_INET, // Go over TCP/IP
|
listeningSocket = socket(AF_INET, // Go over TCP/IP
|
||||||
|
@ -23047,10 +23060,46 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
static tcp_connection *connection;
|
static tcp_connection *connection;
|
||||||
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
||||||
connection->socket=listeningSocket;
|
connection->socket=listeningSocket;
|
||||||
|
connection->connected = -1;
|
||||||
return (void*)connection;
|
return (void*)connection;
|
||||||
#endif
|
#elif defined(QB64_LINUX)
|
||||||
|
struct addrinfo hints, *servinfo, *p;
|
||||||
|
int sockfd;
|
||||||
|
char str_port[6];
|
||||||
|
int yes = 1;
|
||||||
|
snprintf(str_port, 6, "%d", port);
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
if (getaddrinfo(NULL, str_port, &hints, &servinfo) != 0) return NULL;
|
||||||
|
for(p = servinfo; p != NULL; p = p->ai_next) {
|
||||||
|
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||||
|
if (sockfd == -1) continue;
|
||||||
|
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||||
|
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||||
|
close(sockfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; //if we get here, all is good
|
||||||
|
}
|
||||||
|
freeaddrinfo(servinfo);
|
||||||
|
if (p == NULL) return NULL; //indicates none of the entries succeeded
|
||||||
|
fcntl(sockfd, F_SETFL, O_NONBLOCK); //make socket non-blocking
|
||||||
|
|
||||||
|
if (listen(sockfd, SOMAXCONN) == -1) {
|
||||||
|
close(sockfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_connection *connection;
|
||||||
|
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
||||||
|
connection->socket=sockfd;
|
||||||
|
connection->connected = -1;
|
||||||
|
return (void*)connection;
|
||||||
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23066,8 +23115,9 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
tcp_init();
|
tcp_init();
|
||||||
|
|
||||||
if ((port<0)||(port>65535)) return NULL;
|
if ((port<0)||(port>65535)) return NULL;
|
||||||
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
return NULL;
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
static LPHOSTENT hostEntry;
|
static LPHOSTENT hostEntry;
|
||||||
hostEntry=gethostbyname((char*)host);
|
hostEntry=gethostbyname((char*)host);
|
||||||
if (!hostEntry) return NULL;
|
if (!hostEntry) return NULL;
|
||||||
|
@ -23100,18 +23150,51 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
||||||
connection->socket=theSocket;
|
connection->socket=theSocket;
|
||||||
connection->port=port;
|
connection->port=port;
|
||||||
connection->hostname=(uint8*)malloc(strlen((char*)host));
|
connection->connected = -1;
|
||||||
|
connection->hostname=(uint8*)malloc(strlen((char*)host)+1);
|
||||||
memcpy(connection->hostname,host,strlen((char*)host)+1);
|
memcpy(connection->hostname,host,strlen((char*)host)+1);
|
||||||
return (void*)connection;
|
return (void*)connection;
|
||||||
#endif
|
#elif defined(QB64_LINUX)
|
||||||
|
struct addrinfo hints, *servinfo, *p;
|
||||||
|
int sockfd;
|
||||||
|
char str_port[6];
|
||||||
|
snprintf(str_port, 6, "%d", port);
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if (getaddrinfo((char*)host, str_port, &hints, &servinfo) != 0) return NULL;
|
||||||
|
for(p = servinfo; p != NULL; p = p->ai_next) {
|
||||||
|
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||||
|
if (sockfd == -1) continue;
|
||||||
|
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||||
|
close(sockfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; //if we get here, all is good
|
||||||
|
}
|
||||||
|
freeaddrinfo(servinfo);
|
||||||
|
if (p == NULL) return NULL; //indicates none of the entries succeeded
|
||||||
|
fcntl(sockfd, F_SETFL, O_NONBLOCK); //make socket non-blocking
|
||||||
|
|
||||||
|
//now we just need to create a struct tcp_connection to return
|
||||||
|
tcp_connection *connection;
|
||||||
|
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
||||||
|
connection->socket=sockfd;
|
||||||
|
connection->port=port;
|
||||||
|
connection->connected = -1;
|
||||||
|
connection->hostname=(uint8*)malloc(strlen((char*)host)+1);
|
||||||
|
memcpy(connection->hostname,host,strlen((char*)host)+1);
|
||||||
|
return (void*)connection;
|
||||||
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *tcp_connection_open(void *host_tcp){
|
void *tcp_connection_open(void *host_tcp){
|
||||||
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
return NULL;
|
||||||
|
#elif defined(QB64_WINDOWS)
|
||||||
static tcp_connection *host; host=(tcp_connection*)host_tcp;
|
static tcp_connection *host; host=(tcp_connection*)host_tcp;
|
||||||
static sockaddr sa;
|
static sockaddr sa;
|
||||||
static int sa_size;
|
static int sa_size;
|
||||||
|
@ -23129,38 +23212,70 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
connection->socket=new_socket;
|
connection->socket=new_socket;
|
||||||
//IPv4: port,port,ip,ip,ip,ip
|
//IPv4: port,port,ip,ip,ip,ip
|
||||||
connection->port=*((uint16*)sa.sa_data);
|
connection->port=*((uint16*)sa.sa_data);
|
||||||
|
connection->connected = -1;
|
||||||
*((uint32*)(connection->ip4))=*((uint32*)(sa.sa_data+2));
|
*((uint32*)(connection->ip4))=*((uint32*)(sa.sa_data+2));
|
||||||
return (void*)connection;
|
return (void*)connection;
|
||||||
#endif
|
#elif defined(QB64_LINUX)
|
||||||
|
tcp_connection *host; host=(tcp_connection*)host_tcp;
|
||||||
|
struct sockaddr remote_addr;
|
||||||
|
socklen_t addr_size;
|
||||||
|
int fd;
|
||||||
|
|
||||||
return NULL;
|
addr_size = sizeof(remote_addr);
|
||||||
|
fd = accept(host->socket, &remote_addr, &addr_size);
|
||||||
|
if (fd == -1) return NULL;
|
||||||
|
fcntl(fd, F_SETFL, O_NONBLOCK); //make socket non-blocking
|
||||||
|
|
||||||
|
tcp_connection *connection;
|
||||||
|
connection=(tcp_connection*)calloc(sizeof(tcp_connection),1);
|
||||||
|
connection->socket=fd;
|
||||||
|
connection->connected = -1;
|
||||||
|
//IPv4: port,port,ip,ip,ip,ip
|
||||||
|
connection->port=*((uint16*)remote_addr.sa_data);
|
||||||
|
*((uint32*)(connection->ip4))=*((uint32*)(remote_addr.sa_data+2));
|
||||||
|
return (void*)connection;
|
||||||
|
#else
|
||||||
|
return NULL:
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_close(void* connection){
|
void tcp_close(void* connection){
|
||||||
static tcp_connection *tcp=(tcp_connection*)connection;
|
tcp_connection *tcp=(tcp_connection*)connection;
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
if (tcp->socket) {
|
||||||
shutdown(tcp->socket,SD_BOTH);
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
closesocket(tcp->socket);
|
#elif defined(QB64_WINDOWS)
|
||||||
|
shutdown(tcp->socket,SD_BOTH);
|
||||||
|
closesocket(tcp->socket);
|
||||||
|
#elif defined(QB64_LINUX)
|
||||||
|
shutdown(tcp->socket, SHUT_RDWR);
|
||||||
|
close(tcp->socket);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
if (tcp->hostname) free(tcp->hostname);
|
if (tcp->hostname) free(tcp->hostname);
|
||||||
free(tcp);
|
free(tcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_out(void *connection,void *offset,ptrszint bytes){
|
void tcp_out(void *connection,void *offset,ptrszint bytes){
|
||||||
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
|
#elif defined(QB64_WINDOWS) || defined(QB64_LINUX)
|
||||||
|
tcp_connection *tcp; tcp=(tcp_connection*)connection;
|
||||||
|
int total = 0; // how many bytes we've sent
|
||||||
|
int bytesleft = bytes; // how many we have left to send
|
||||||
|
int n;
|
||||||
|
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
while(total < bytes) {
|
||||||
static tcp_connection *tcp; tcp=(tcp_connection*)connection;
|
n = send(tcp->socket, (char*)(offset + total), bytesleft, 0);
|
||||||
static int nret;
|
if (n < 0) {
|
||||||
nret = send(tcp->socket,
|
tcp->connected = 0;
|
||||||
(char*)offset,
|
return;
|
||||||
bytes,
|
}
|
||||||
0);
|
total += n;
|
||||||
|
bytesleft -= n;
|
||||||
|
}
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int32 cloud_port_redirect=-1;
|
int32 cloud_port_redirect=-1;
|
||||||
struct connection_struct{
|
struct connection_struct{
|
||||||
int8 in_use;//0=not being used, 1=in use
|
int8 in_use;//0=not being used, 1=in use
|
||||||
|
@ -23188,8 +23303,8 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
|
|
||||||
|
|
||||||
void stream_update(stream_struct *stream){
|
void stream_update(stream_struct *stream){
|
||||||
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
#elif defined(QB64_WINDOWS) || defined(QB64_LINUX)
|
||||||
//assume tcp
|
//assume tcp
|
||||||
|
|
||||||
static connection_struct *connection;
|
static connection_struct *connection;
|
||||||
|
@ -23207,28 +23322,31 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
expand_and_retry:
|
expand_and_retry:
|
||||||
|
|
||||||
//expand buffer if 'in' stream is full
|
//expand buffer if 'in' stream is full
|
||||||
|
//also guarantees that bytes requested from recv() is not 0
|
||||||
if (stream->in_size==stream->in_limit){
|
if (stream->in_size==stream->in_limit){
|
||||||
stream->in_limit*=2; stream->in=(uint8*)realloc(stream->in,stream->in_limit);
|
stream->in_limit*=2; stream->in=(uint8*)realloc(stream->in,stream->in_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bytes = recv(tcp->socket,(char*)(stream->in+stream->in_size),
|
bytes = recv(tcp->socket,(char*)(stream->in+stream->in_size),
|
||||||
stream->in_limit-stream->in_size,
|
stream->in_limit-stream->in_size,
|
||||||
0);
|
0);
|
||||||
if (bytes==SOCKET_ERROR){
|
if (bytes < 0) { //some kind of error
|
||||||
//Known error codes:
|
#ifdef QB64_WINDOWS
|
||||||
//10035 WSAEWOULDBLOCK Resource temporarily unavailable. This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. It is a nonfatal error, and the operation should be retried later. It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect on a nonblocking SOCK_STREAM socket, since some time must elapse for the connection to be established.
|
if (WSAGetLastError() != WSAEWOULDBLOCK) tcp->connected = 0; //fatal error
|
||||||
static ptrszint e;
|
#else
|
||||||
e=WSAGetLastError();
|
if (errno != EAGAIN && errno != EWOULDBLOCK) tcp->connected = 0;
|
||||||
return;
|
#endif
|
||||||
}
|
}
|
||||||
if (bytes<=0) return;
|
else if (bytes == 0) { //graceful shutdown occured
|
||||||
stream->in_size+=bytes;
|
tcp->connected = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (stream->in_size==stream->in_limit) goto expand_and_retry;
|
stream->in_size+=bytes;
|
||||||
|
if (stream->in_size==stream->in_limit) goto expand_and_retry;
|
||||||
|
}
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23512,20 +23630,14 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 tcp_connected (void *connection){
|
int32 tcp_connected (void *connection){
|
||||||
static tcp_connection *tcp=(tcp_connection*)connection;
|
tcp_connection *tcp=(tcp_connection*)connection;
|
||||||
#if defined(QB64_WINDOWS) && defined(DEPENDENCY_SOCKETS)
|
#if !defined(DEPENDENCY_SOCKETS)
|
||||||
char buf;
|
return 0;
|
||||||
int length=recv(tcp->socket, &buf, 0, 0);
|
#elif defined(QB64_WINDOWS) || defined(QB64_LINUX)
|
||||||
int nError=WSAGetLastError();
|
return tcp->connected;
|
||||||
if(nError!=WSAEWOULDBLOCK&&nError!=0)
|
#else
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
if (nError==0){
|
|
||||||
if (length==0) return 0;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 func__connected(int32 i){
|
int32 func__connected(int32 i){
|
||||||
|
|
Loading…
Reference in a new issue