1 /* sckt.c provide access to the socket layer.
3 Copyright (C) 2005-2022 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
30 #define EXPORT(FUNC) m2pim ## _sckt_ ## FUNC
31 #define M2EXPORT(FUNC) m2pim ## _M2_sckt_ ## FUNC
32 #define M2LIBNAME "m2pim"
34 #if defined(HAVE_SYS_TYPES_H)
35 #include <sys/types.h>
38 #if defined(HAVE_SYS_SOCKET_H)
39 #include <sys/socket.h>
42 #if defined(HAVE_NETINET_IN_H)
43 #include <netinet/in.h>
46 #if defined(HAVE_NETDB_H)
50 #if defined(HAVE_UNISTD_H)
54 #if defined(HAVE_SIGNAL_H)
58 #if defined(HAVE_SYS_ERRNO_H)
59 #include <sys/errno.h>
62 #if defined(HAVE_ERRNO_H)
66 #if defined(HAVE_MALLOC_H)
70 #if defined(HAVE_STRING_H)
74 #if defined(HAVE_STDLIB_H)
78 #if defined(HAVE_STDIO_H)
82 #define PORTSTART 7000
84 #define MAXHOSTNAME 256
88 #if defined(HAVE_SYS_SOCKET_H)
92 printf ("%s:%d:%s\n", __FILE__, __LINE__, X); \
100 printf ("%s:%d: assert(%s) failed\n", __FILE__, __LINE__, #X); \
107 char hostname
[MAXHOSTNAME
];
109 struct sockaddr_in sa
, isa
;
120 /* tcpServerEstablishPort returns a tcpState containing the relevant
121 information about a socket declared to receive tcp connections.
122 This method attempts to use the port specified by the parameter. */
124 extern "C" tcpServerState
*
125 EXPORT(tcpServerEstablishPort
) (int portNo
)
127 tcpServerState
*s
= (tcpServerState
*)malloc (sizeof (tcpServerState
));
131 ERROR ("no more memory");
133 /* Remove SIGPIPE which is raised on the server if the client is killed. */
134 signal (SIGPIPE
, SIG_IGN
);
136 if (gethostname (s
->hostname
, MAXHOSTNAME
) < 0)
137 ERROR ("cannot find our hostname");
139 s
->hp
= gethostbyname (s
->hostname
);
141 ERROR ("cannot get host name");
148 /* Open a TCP socket (an Internet stream socket). */
150 s
->sockFd
= socket (s
->hp
->h_addrtype
, SOCK_STREAM
, 0);
154 memset ((void *)&s
->sa
, 0, sizeof (s
->sa
));
155 ASSERT ((s
->hp
->h_addrtype
== AF_INET
));
156 s
->sa
.sin_family
= s
->hp
->h_addrtype
;
157 s
->sa
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
158 s
->sa
.sin_port
= htons (portNo
+ p
);
160 b
= bind (s
->sockFd
, (struct sockaddr
*)&s
->sa
, sizeof (s
->sa
));
162 while ((b
< 0) && (n
< NOOFTRIES
));
167 s
->portNo
= portNo
+ p
;
168 #if defined(DEBUGGING)
169 printf ("the receiving host is: %s, the port is %d\n", s
->hostname
,
172 listen (s
->sockFd
, 1);
176 /* tcpServerEstablish returns a tcpServerState containing the relevant
177 information about a socket declared to receive tcp connections. */
179 extern "C" tcpServerState
*
180 EXPORT(tcpServerEstablish
) (void)
182 return EXPORT(tcpServerEstablishPort
) (PORTSTART
);
185 /* tcpServerAccept returns a file descriptor once a client has connected and
189 EXPORT(tcpServerAccept
) (tcpServerState
*s
)
191 socklen_t i
= sizeof (s
->isa
);
194 #if defined(DEBUGGING)
195 printf ("before accept %d\n", s
->sockFd
);
197 t
= accept (s
->sockFd
, (struct sockaddr
*)&s
->isa
, &i
);
201 /* tcpServerPortNo returns the portNo from structure, s. */
204 EXPORT(tcpServerPortNo
) (tcpServerState
*s
)
209 /* tcpServerSocketFd returns the sockFd from structure, s. */
212 EXPORT(tcpServerSocketFd
) (tcpServerState
*s
)
217 /* getLocalIP returns the IP address of this machine. */
219 extern "C" unsigned int
220 EXPORT(getLocalIP
) (tcpServerState
*s
)
224 struct sockaddr_in sa
;
226 int ret
= gethostname (hostname
, sizeof (hostname
));
230 ERROR ("gethostname");
234 hp
= gethostbyname (hostname
);
237 ERROR ("gethostbyname");
241 if (sizeof (unsigned int) != sizeof (in_addr_t
))
243 ERROR ("bad ip length");
247 memset (&sa
, 0, sizeof (struct sockaddr_in
));
248 sa
.sin_family
= AF_INET
;
249 sa
.sin_port
= htons (80);
250 if (hp
->h_length
== sizeof (unsigned int))
252 memcpy (&ip
, hp
->h_addr_list
[0], hp
->h_length
);
259 /* tcpServerIP returns the IP address from structure s. */
262 EXPORT(tcpServerIP
) (tcpServerState
*s
)
264 return *((int *)s
->hp
->h_addr_list
[0]);
267 /* tcpServerClientIP returns the IP address of the client who
268 has connected to server s. */
270 extern "C" unsigned int
271 EXPORT(tcpServerClientIP
) (tcpServerState
*s
)
275 ASSERT (s
->isa
.sin_family
== AF_INET
);
276 ASSERT (sizeof (ip
) == 4);
277 memcpy (&ip
, &s
->isa
.sin_addr
, sizeof (ip
));
281 /* tcpServerClientPortNo returns the port number of the client who
282 has connected to server s. */
284 extern "C" unsigned int
285 EXPORT(tcpServerClientPortNo
) (tcpServerState
*s
)
287 return s
->isa
.sin_port
;
291 ****************************************************************
292 *** C L I E N T R O U T I N E S
293 ****************************************************************
298 char hostname
[MAXHOSTNAME
];
300 struct sockaddr_in sa
;
305 /* tcpClientSocket returns a file descriptor (socket) which has
306 connected to, serverName:portNo. */
308 extern "C" tcpClientState
*
309 EXPORT(tcpClientSocket
) (char *serverName
, int portNo
)
311 tcpClientState
*s
= (tcpClientState
*)malloc (sizeof (tcpClientState
));
314 ERROR ("no more memory");
316 /* Remove SIGPIPE which is raised on the server if the client is killed. */
317 signal (SIGPIPE
, SIG_IGN
);
319 s
->hp
= gethostbyname (serverName
);
322 fprintf (stderr
, "cannot find host: %s\n", serverName
);
326 memset ((void *)&s
->sa
, 0, sizeof (s
->sa
));
327 s
->sa
.sin_family
= AF_INET
;
328 memcpy ((void *)&s
->sa
.sin_addr
, (void *)s
->hp
->h_addr
, s
->hp
->h_length
);
330 s
->sa
.sin_port
= htons (portNo
);
332 /* Open a TCP socket (an Internet stream socket). */
334 s
->sockFd
= socket (s
->hp
->h_addrtype
, SOCK_STREAM
, 0);
338 /* tcpClientSocketIP returns a file descriptor (socket) which has
339 connected to, ip:portNo. */
341 extern "C" tcpClientState
*
342 EXPORT(tcpClientSocketIP
) (unsigned int ip
, int portNo
)
344 tcpClientState
*s
= (tcpClientState
*)malloc (sizeof (tcpClientState
));
347 ERROR ("no more memory");
349 /* Remove SIGPIPE which is raised on the server if the client is killed. */
350 signal (SIGPIPE
, SIG_IGN
);
352 memset ((void *)&s
->sa
, 0, sizeof (s
->sa
));
353 s
->sa
.sin_family
= AF_INET
;
354 memcpy ((void *)&s
->sa
.sin_addr
, (void *)&ip
, sizeof (ip
));
356 s
->sa
.sin_port
= htons (portNo
);
358 /* Open a TCP socket (an Internet stream socket). */
360 s
->sockFd
= socket (PF_INET
, SOCK_STREAM
, 0);
364 /* tcpClientConnect returns the file descriptor associated with s,
365 once a connect has been performed. */
368 EXPORT(tcpClientConnect
) (tcpClientState
*s
)
370 if (connect (s
->sockFd
, (struct sockaddr
*)&s
->sa
, sizeof (s
->sa
)) < 0)
371 ERROR ("failed to connect to the TCP server");
376 /* tcpClientPortNo returns the portNo from structure s. */
379 EXPORT(tcpClientPortNo
) (tcpClientState
*s
)
384 /* tcpClientSocketFd returns the sockFd from structure s. */
387 EXPORT(tcpClientSocketFd
) (tcpClientState
*s
)
392 /* tcpClientIP returns the sockFd from structure s. */
395 EXPORT(tcpClientIP
) (tcpClientState
*s
)
397 #if defined(DEBUGGING)
398 printf ("client ip = %s\n", inet_ntoa (s
->sa
.sin_addr
.s_addr
));
400 return s
->sa
.sin_addr
.s_addr
;
404 /* GNU Modula-2 link fodder. */
407 M2EXPORT(init
) (int, char *[], char *[])
412 M2EXPORT(finish
) (int, char *[], char *[])
421 extern "C" void __attribute__((__constructor__
))
422 M2EXPORT(ctor
) (void)
424 m2pim_M2RTS_RegisterModule ("sckt", M2LIBNAME
,
425 M2EXPORT(init
), M2EXPORT(finish
),