// Excerpts from iForth.c // char *makestr(char *name, int size) turns the forth string name // into a 0-delimited C-string (using a buffer) // iserror is a C-variable that iForth knows the address of. // Every call from Forth to one of the below C-functions results can be // stack-pictured as: // ( n*{int} n function_number -- C_result *iserror ) SYSCALL int getSerr (int err) { /* 220 */ iserror=strlen(strerror(err)); return (int)strerror(err); } // Get the local computer's name in a buffer int GetHName (char *name, int size) { /* 221 */ iserror = gethostname (name,size) ? errno : 0; if (iserror==0) return strlen(name); return 0; } /* struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; // Structure describing an Internet (IP) socket address. #define __SOCK_SIZE__ 16 // sizeof(struct sockaddr) struct sockaddr_in { short int sin_family; // Address family unsigned short int sin_port; // Port number struct in_addr sin_addr; // Internet address // Pad to size of Struct sockaddr'. unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; }; #define sin_zero __pad // for BSD UNIX comp. -FvK */ struct sockaddr_in sinhim; // With NT it is not possible to use a socket like a file handle (!) // recv, send and closesocket are required .. int open_service (int port) {int fd; /* 222 */ memset((char *)&sinhim,0,sizeof(sinhim)); sinhim.sin_family = AF_INET; sinhim.sin_addr.s_addr = INADDR_ANY; sinhim.sin_port = htons(port); if ((fd=socket(AF_INET,SOCK_STREAM,0)) < 0) { iserror=errno; return -1;} if (bind(fd,(struct sockaddr *)&sinhim,sizeof(sinhim)) < 0) { iserror=errno; return -1;} iserror=0; return fd; } int open_server (char* hostname, int size, int port) { /* 223 */ int fd; struct hostent *hp; if ((fd=socket(AF_INET,SOCK_STREAM,0)) < 0) { iserror=errno; return -1;} sinhim.sin_family = AF_INET; sinhim.sin_port = htons(port); hp = gethostbyname (makestr(hostname,size)); if (hp == NULL) { iserror=errno; return -1;} memcpy(&sinhim.sin_addr,hp->h_addr,hp->h_length); if (connect(fd,(struct sockaddr *)&sinhim,sizeof(sinhim)) < 0) { iserror=errno; return -1;} iserror=0; return fd; } int recv4 (int s, char *buf, int len) { /* 224 */ int numbytes = recv(s,buf,len,0); if (numbytes < 0) { iserror=errno; return -1;} iserror=0; return numbytes;} int setnonblocking (int s, int on_off) { /* 225 */ iserror = (on_off ? fcntl(s,F_SETFL,O_NONBLOCK) : fcntl(s,F_SETFL,0)); if (iserror < 0) iserror=errno; return iserror; } int send4 (int s, char *buf, int len) { /* 226 */ int numbytes = send(s,buf,len,0); if (numbytes < 0) { iserror=errno; return -1;} iserror=0; return numbytes;} int closesocket4 (int s) { /* 227 */ if (close(s) < 0) { iserror=errno; return -1;} return iserror=0;} int listen4 (int socket, int backlog) { /* 228 */ if (listen(socket, backlog) < 0) return errno; return 0;} // backlog == queue limit incoming connections int accept4 (int listening) {int socket,alen=sizeof(sinhim); /* 229 */ if ((socket=accept(listening,(struct sockaddr *)&sinhim,&alen)) < 0) { iserror=errno; return -1;} iserror=0; return socket;} // ------------------------------------------------------------------------------- // Linux's named pipes are a bit of a fake, they use sockets to connect processes // on the local machine (NT can do it over the network). I recommend to never use // them. Their only advantage is that instead of an arbitrary port# you now need // an arbitrary pipe name... // ------------------------------------------------------------------------------- // name: /dev/ // iForths named pipes for Linux are blocking. int createnamedpipe4(char *name, int sz, int backlog) { /* 230 */ int fd,len; struct sockaddr_un unix_addr; if ( (fd = socket(AF_UNIX,SOCK_STREAM,0)) < 0) { iserror=errno; return -1;} unlink(makestr(name,sz)); // in case it already exists memset(&unix_addr,0,sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; strcpy(unix_addr.sun_path,makestr(name,sz)); len = strlen(unix_addr.sun_path) + sizeof(unix_addr.sun_family); if (bind(fd,(struct sockaddr *)&unix_addr,len) < 0) { iserror=errno; return -1;} if (listen(fd,backlog) < 0) { iserror=errno; return -1;} // tell kernel we're a server iserror=0; return fd; } // The server tests for a client to access the named pipe // Wait for a client connection to arrive, and accept it. // Returns new fd if all OK, <0 on error #define STALE 30 // client's name can't be older than this (sec) int connectnamedpipe4(int listenfd) { /* 231 */ time_t staletime; struct sockaddr_un unix_addr; struct stat statbuf; int clifd, len = sizeof(unix_addr); if ( (clifd = accept(listenfd,(struct sockaddr *)&unix_addr,&len)) < 0) { iserror=errno; return -1;} // often errno=EINTR, if signal caught len -= sizeof(unix_addr.sun_family); // len of pathname unix_addr.sun_path[len] = 0; // null terminate if (stat(unix_addr.sun_path,&statbuf) < 0) { iserror=errno; return -1;} if (S_ISSOCK(statbuf.st_mode) == 0) { iserror=errno; return -1;} // not a socket if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) || (statbuf.st_mode & S_IRWXU) != S_IRWXU) { iserror=errno; return -1;} // is not rwx------ staletime = time(NULL) - STALE; if (statbuf.st_atime // returns fd if all OK, <0 on error #define CLI_PATH "/var/tmp/" // +5 for pid = 14 chars #define CLI_PERM S_IRWXU // rwx for user only int opennamedpipe4(char *name, int sz, int timeo) { /* 232 */ int fd,len; struct sockaddr_un unix_addr; // create a Unix domain stream socket if ( (fd = socket(AF_UNIX,SOCK_STREAM,0)) < 0) { iserror=errno; return -1;} // fill socket address structure w/our address memset(&unix_addr,0,sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; sprintf(unix_addr.sun_path,"%s%05d",CLI_PATH,getpid()); len = strlen(unix_addr.sun_path) + sizeof(unix_addr.sun_family); if (len != 16) { iserror = errno; return -1;} // hack unlink(unix_addr.sun_path); // in case it already exists if (bind(fd,(struct sockaddr *)&unix_addr,len) < 0) { iserror=errno; return -1;} if (chmod(unix_addr.sun_path,CLI_PERM) < 0) { iserror=errno; return -1;} // fill socket address structure w/server's addr memset(&unix_addr,0,sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; strcpy(unix_addr.sun_path,makestr(name,sz)); len = strlen(unix_addr.sun_path) + sizeof(unix_addr.sun_family); if (connect(fd,(struct sockaddr *)&unix_addr,len) < 0) { iserror=errno; return -1;} iserror=0; return fd;} int readnamedpipe(void *buf, unsigned len, int s) { /* 233 */ int numbytes = recv(s,buf,len,0); if (numbytes < 0) {iserror=errno; return 0;} iserror=0; return numbytes;} int writenamedpipe(void *buf, unsigned len, int s) { /* 234 */ int numbytes = send(s,buf,len,0); if (numbytes < 0) {iserror=errno; return 0;} iserror=0; return numbytes;} int closenamedpipe(int h) {ISOKAY(close(h)==0); return 0;} /* 235 */