// iForth Server C-part, for Windows NT 4.0 // makestr() is a function that converts a c-addr u to a C-string (it uses a buffer) // iserror is a C-variable that iForth can access. An iForth SYSCALL works like // this: SYSCALL ( {param}*n n function# -- Creturnvalue iserror ) ... // call this once when iForth starts void OpenSockets(void) { WORD wVersionRequested = MAKEWORD(2,0); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); } // call this once when iForth exits to the OS void CloseSockets(void) {WSACleanup();} static char * SAerr[18] = { "A successful SAStartup must occur before using this function.", "The Sockets implementation has detected that the network subsystem has failed.", "Authoritative Answer Host not found.", "Non-Authoritative Host not found, or SERVERFAIL.", "Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.", "Valid name, no data record of requested type.", "A blocking Sockets operation is in progress.", "The (blocking) call was canceled using SACancelBlockingCall.", "The namelen parameter is too small.", "Software caused connection abort.", "Connection refused.", "Connection reset by peer.", "Connection timed out.", "Graceful shutdown in progress.", "Socket operation on non-socket.", "The specified address is already in use.", "The socket has been shutdown, recv() not possible.", "Error text not available." }; // Ask OS what an error code means. int getSerr (int err) { /* 220 */ switch (err) { case WSANOTINITIALISED: err=0; break; case WSAENETDOWN: err=1; break; case WSAHOST_NOT_FOUND: err=2; break; case WSATRY_AGAIN: err=3; break; case WSANO_RECOVERY: err=4; break; case WSANO_DATA: err=5; break; case WSAEINPROGRESS: err=6; break; case WSAEINTR: err=7; break; case WSAEFAULT: err=8; break; case WSAECONNABORTED: err=9; break; case WSAECONNREFUSED: err=10; break; case WSAECONNRESET: err=11; break; case WSAETIMEDOUT: err=12; break; case WSAEDISCON: err=13; break; case WSAENOTSOCK: err=14; break; case WSAEADDRINUSE: err=15; break; case WSAESHUTDOWN: err=16; break; default: err=17; } iserror=strlen(SAerr[err]); return (int)SAerr[err]; } // Get the local computer's name in a buffer int GetHName (char *name, int size) { /* 221 */ iserror = gethostname (name,size) ? WSAGetLastError() : 0; if (iserror==0) return strlen(name); return 0; } struct sockaddr_in sinhim = { AF_INET }; // With NT it is not possible to use a socket like a file handle (!) // recv, send and closesocket are required .. // This sets up a service listening to the given port. 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))==INVALID_SOCKET) {iserror=WSAGetLastError(); return (int)-1;} if (bind(fd,&sinhim,sizeof(sinhim)) == SOCKET_ERROR) {iserror=WSAGetLastError(); return (int)-1;} iserror=0; return fd; } // This connects to a service (ftp, www, telnet..). The service lives at the internet URL // given by the string and listens to the given port. You have to know the magic port#. int open_server (char* hostname, int size, int port) { /* 223 */ int fd; struct hostent *hp; if ((fd=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) {iserror=WSAGetLastError(); return (int)-1;} sinhim.sin_family = AF_INET; sinhim.sin_port = htons(port); hp = gethostbyname (makestr(hostname,size)); if (hp == NULL) {iserror=WSAGetLastError(); return (int)-1;} memcpy(&sinhim.sin_addr,hp->h_addr,hp->h_length); if (connect(fd,&sinhim,sizeof(sinhim))==SOCKET_ERROR) {iserror=WSAGetLastError(); return (int)-1;} iserror=0; return fd; } // Like read() int recv4 (SOCKET s, char *buf, int len) { /* 224 */ int numbytes=recv(s,buf,len,0); if (numbytes==SOCKET_ERROR) {iserror=WSAGetLastError(); return 0;} iserror=0; return numbytes;} // So you don't hang on the socket (like KEY?) int setnonblocking (SOCKET s, int on_off) { /* 225 */ iserror = ioctlsocket (s,FIONBIO,(u_long *)&on_off); if (iserror==SOCKET_ERROR) iserror=WSAGetLastError(); return iserror; } // Like write() int send4 (SOCKET s, char *buf, int len) { /* 226 */ iserror=send (s,buf,len,0); if (iserror==SOCKET_ERROR) {iserror=WSAGetLastError(); return 0;} return iserror=0;} // like close() int closesocket4 (SOCKET s) { /* 227 */ if (closesocket(s)==SOCKET_ERROR) {iserror=WSAGetLastError(); return 0;} return iserror=0;} // To enable your own server int listen4 (int socket, int backlog) { /* 228 */ if (listen(socket,backlog) < 0) return errno; return 0;} // backlog == queue limit incoming connections // Again to enable your own server to serve. int accept4 (int listening) {int socket,alen=sizeof(sinhim); /* 229 */ if ((socket=accept(listening,(struct sockaddr *)&sinhim,&alen)) < 0) {iserror=errno; return (int)-1;} iserror=0; return socket;} // name: //./pipe/ (a new process runs locally of course) // iForths named pipes are non-blocking. int createnamedpipe4(char *name, int sz, int backlog) { /* 230 */ HANDLE ret; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; // Attach a NULL discretionary access control list to the pipe to optimize access to it InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; ret = CreateNamedPipe( makestr(name,sz), PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, backlog, // maximum number of instances 4096, // output buffer size, in bytes (disregarded) 4096, // input buffer size, in bytes (disregarded) 3000, // time-out time, in milliseconds &sa); // address of security attributes structure if (ret==INVALID_HANDLE_VALUE) {iserror=GetLastError(); return -2;} iserror=0; return (int)ret; } // The server tests for a client to access the named pipe int connectnamedpipe4(int pipe) { /* 231 */ if (FALSE==ConnectNamedPipe((HANDLE)pipe, NULL)) return (GetLastError()==ERROR_PIPE_CONNECTED); return (int)-1; } // the client connects to the server, over the network: //servername/pipe/ int opennamedpipe4(char *name, int sz, DWORD timeo) { /* 232 */ HANDLE h; int res=WaitNamedPipe(makestr(name,sz),timeo); if (res==0) {iserror=GetLastError(); return (int)-2;} h=CreateFile( makestr(name,sz), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL); iserror=GetLastError(); return (int)h; } // It looks like read / write / close can't be done with standard file functions int readnamedpipe(char *buf, int sz, HANDLE h) {int dwBytes; /* 233 */ if (FALSE==ReadFile(h,buf,sz,&dwBytes,NULL)) {iserror=GetLastError(); return (int)-1;} iserror=0; return dwBytes; } int writenamedpipe(char *buf, int sz, HANDLE h) {int dwBytes; /* 234 */ if (FALSE==WriteFile(h,buf,sz,&dwBytes,NULL)) {iserror=GetLastError(); return (int)-1;} iserror=0; return dwBytes; } int closenamedpipe(HANDLE h) { /* 235 */ FlushFileBuffers(h); DisconnectNamedPipe(h); if (FALSE==CloseHandle(h)) return GetLastError(); return 0;} ... /* EOF */