| /* wrapsock.c provides access to socket related system calls. | |
| Copyright (C) 2008-2022 Free Software Foundation, Inc. | |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. | |
| This file is part of GNU Modula-2. | |
| GNU Modula-2 is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3, or (at your option) | |
| any later version. | |
| GNU Modula-2 is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| Under Section 7 of GPL version 3, you are granted additional | |
| permissions described in the GCC Runtime Library Exception, version | |
| 3.1, as published by the Free Software Foundation. | |
| You should have received a copy of the GNU General Public License and | |
| a copy of the GCC Runtime Library Exception along with this program; | |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| <http://www.gnu.org/licenses/>. */ | |
| #include "config.h" | |
| #include <stdbool.h> | |
| #define EXPORT(FUNC) m2iso ## _wrapsock_ ## FUNC | |
| #define IMPORT(MODULE,FUNC) m2iso ## _ ## MODULE ## _ ## FUNC | |
| #define M2EXPORT(FUNC) m2iso ## _M2_wrapsock_ ## FUNC | |
| #define M2LIBNAME "m2iso" | |
| /* This module should be rewritten to use C++. */ | |
| typedef void (*proc_con) (int, char **, char **); | |
| typedef void (*proc_dep) (void); | |
| extern void m2iso_M2RTS_RequestDependant (const char *modulename, const char *libname, const char *dependancy); | |
| extern void m2iso_M2RTS_RegisterModule (const char *modulename, const char *libname, | |
| proc_con init, proc_con fini, proc_dep dependencies); | |
| #if defined(HAVE_SYS_TYPES_H) | |
| #include "sys/types.h" | |
| #endif | |
| #if defined(HAVE_SYS_SOCKET_H) | |
| #include "sys/socket.h" | |
| #endif | |
| #if defined(HAVE_NETINET_IN_H) | |
| #include "netinet/in.h" | |
| #endif | |
| #if defined(HAVE_NETDB_H) | |
| #include "netdb.h" | |
| #endif | |
| #if defined(HAVE_UNISTD_H) | |
| #include "unistd.h" | |
| #endif | |
| #if defined(HAVE_SIGNAL_H) | |
| #include "signal.h" | |
| #endif | |
| #if defined(HAVE_SYS_ERRNO_H) | |
| #include "sys/errno.h" | |
| #endif | |
| #if defined(HAVE_ERRNO_H) | |
| #include "errno.h" | |
| #endif | |
| #if defined(HAVE_MALLOC_H) | |
| #include "malloc.h" | |
| #endif | |
| #if defined(HAVE_MALLOC_H) | |
| #include "signal.h" | |
| #endif | |
| #if defined(HAVE_STRING_H) | |
| #include "string.h" | |
| #endif | |
| #if defined(HAVE_STDLIB_H) | |
| #include "stdlib.h" | |
| #endif | |
| #include "ChanConsts.h" | |
| #define MAXHOSTNAME 1024 | |
| #define MAXPBBUF 1024 | |
| #if defined(HAVE_NETINET_IN_H) | |
| typedef struct | |
| { | |
| char hostname[MAXHOSTNAME]; | |
| struct hostent *hp; | |
| struct sockaddr_in sa; | |
| int sockFd; | |
| int portNo; | |
| int hasChar; | |
| char pbChar[MAXPBBUF]; | |
| } clientInfo; | |
| static openResults clientConnect (clientInfo *c); | |
| /* clientOpen - returns an ISO Modula-2 OpenResult. It attempts to | |
| connect to: hostname:portNo. If successful then the data | |
| structure, c, will have its fields initialized. */ | |
| openResults | |
| EXPORT(clientOpen) (clientInfo *c, char *hostname, unsigned int length, | |
| int portNo) | |
| { | |
| /* remove SIGPIPE which is raised on the server if the client is killed. */ | |
| signal (SIGPIPE, SIG_IGN); | |
| c->hp = gethostbyname (hostname); | |
| if (c->hp == NULL) | |
| return noSuchFile; | |
| memset ((void *)&c->sa, 0, sizeof (c->sa)); | |
| c->sa.sin_family = AF_INET; | |
| memcpy ((void *)&c->sa.sin_addr, (void *)c->hp->h_addr, c->hp->h_length); | |
| c->portNo = portNo; | |
| c->sa.sin_port = htons (portNo); | |
| c->hasChar = 0; | |
| /* Open a TCP socket (an Internet stream socket) */ | |
| c->sockFd = socket (c->hp->h_addrtype, SOCK_STREAM, 0); | |
| return clientConnect (c); | |
| } | |
| /* clientOpenIP - returns an ISO Modula-2 OpenResult. It attempts to | |
| connect to: ipaddress:portNo. If successful then the data | |
| structure, c, will have its fields initialized. */ | |
| openResults | |
| EXPORT(clientOpenIP) (clientInfo *c, unsigned int ip, int portNo) | |
| { | |
| /* remove SIGPIPE which is raised on the server if the client is killed. */ | |
| signal (SIGPIPE, SIG_IGN); | |
| memset ((void *)&c->sa, 0, sizeof (c->sa)); | |
| c->sa.sin_family = AF_INET; | |
| memcpy ((void *)&c->sa.sin_addr, (void *)&ip, sizeof (ip)); | |
| c->portNo = portNo; | |
| c->sa.sin_port = htons (portNo); | |
| /* Open a TCP socket (an Internet stream socket) */ | |
| c->sockFd = socket (PF_INET, SOCK_STREAM, 0); | |
| return clientConnect (c); | |
| } | |
| /* clientConnect - returns an ISO Modula-2 OpenResult once a connect | |
| has been performed. If successful the clientInfo will include the | |
| file descriptor ready for read/write operations. */ | |
| static openResults | |
| clientConnect (clientInfo *c) | |
| { | |
| if (connect (c->sockFd, (struct sockaddr *)&c->sa, sizeof (c->sa)) < 0) | |
| return noSuchFile; | |
| return opened; | |
| } | |
| /* getClientPortNo - returns the portNo from structure, c. */ | |
| int | |
| EXPORT(getClientPortNo) (clientInfo *c) | |
| { | |
| return c->portNo; | |
| } | |
| /* getClientHostname - fills in the hostname of the server the to | |
| which the client is connecting. */ | |
| void | |
| EXPORT(getClientHostname) (clientInfo *c, char *hostname, unsigned int high) | |
| { | |
| strncpy (hostname, c->hostname, high + 1); | |
| } | |
| /* getClientSocketFd - returns the sockFd from structure, c. */ | |
| int | |
| EXPORT(getClientSocketFd) (clientInfo *c) | |
| { | |
| return c->sockFd; | |
| } | |
| /* getClientIP - returns the sockFd from structure, s. */ | |
| unsigned int | |
| EXPORT(getClientIP) (clientInfo *c) | |
| { | |
| #if 0 | |
| printf("client ip = %s\n", inet_ntoa (c->sa.sin_addr.s_addr)); | |
| #endif | |
| return c->sa.sin_addr.s_addr; | |
| } | |
| /* getPushBackChar returns true if a pushed back character is | |
| available. */ | |
| bool | |
| EXPORT(getPushBackChar) (clientInfo *c, char *ch) | |
| { | |
| if (c->hasChar > 0) | |
| { | |
| c->hasChar--; | |
| *ch = c->pbChar[c->hasChar]; | |
| return true; | |
| } | |
| return false; | |
| } | |
| /* setPushBackChar returns true if it is able to push back a | |
| character. */ | |
| bool | |
| EXPORT(setPushBackChar) (clientInfo *c, char ch) | |
| { | |
| if (c->hasChar == MAXPBBUF) | |
| return false; | |
| c->pbChar[c->hasChar] = ch; | |
| c->hasChar++; | |
| return true; | |
| } | |
| /* getSizeOfClientInfo - returns the sizeof (opaque data type). */ | |
| unsigned int | |
| EXPORT(getSizeOfClientInfo) (void) | |
| { | |
| return sizeof (clientInfo); | |
| } | |
| #endif | |
| /* GNU Modula-2 linking hooks. */ | |
| void | |
| M2EXPORT(init) (int, char **, char **) | |
| { | |
| } | |
| void | |
| M2EXPORT(fini) (int, char **, char **) | |
| { | |
| } | |
| void | |
| M2EXPORT(dep) (void) | |
| { | |
| } | |
| void __attribute__((__constructor__)) | |
| M2EXPORT(ctor) (void) | |
| { | |
| m2iso_M2RTS_RegisterModule ("wrapsock", M2LIBNAME, | |
| M2EXPORT(init), M2EXPORT(fini), | |
| M2EXPORT(dep)); | |
| } |