home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mitsch75.zip
/
scheme-7_5_17-src.zip
/
scheme-7.5.17
/
src
/
microcode
/
uxsock.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-01
|
8KB
|
312 lines
/* -*-C-*-
$Id: uxsock.c,v 1.28 2001/06/02 01:21:58 cph Exp $
Copyright (c) 1990-2001 Massachusetts Institute of Technology
This program 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 2 of the License, or (at
your option) any later version.
This program 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
*/
#include "ux.h"
#include "osio.h"
#ifdef HAVE_SOCKETS
#include "uxsock.h"
#include "uxio.h"
#include "prims.h"
#include "limits.h"
static void do_connect (int, struct sockaddr *, socklen_t);
Tchannel
DEFUN (OS_open_tcp_stream_socket, (host, port),
PTR host AND
unsigned int port)
{
int s;
Tchannel channel;
transaction_begin ();
STD_UINT_SYSTEM_CALL
(syscall_socket, s, (UX_socket (AF_INET, SOCK_STREAM, 0)));
MAKE_CHANNEL (s, channel_type_tcp_stream_socket, channel =);
OS_channel_close_on_abort (channel);
{
struct sockaddr_in address;
(address . sin_family) = AF_INET;
memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
(address . sin_port) = port;
do_connect (s, ((struct sockaddr *) (&address)), (sizeof (address)));
}
transaction_commit ();
return (channel);
}
static void
do_connect (int s, struct sockaddr * address, socklen_t addr_len)
{
if ((UX_connect (s, address, addr_len)) < 0)
{
if (errno != EINTR)
error_system_call (errno, syscall_connect);
while (1)
{
deliver_pending_interrupts ();
/* Yuk; lots of hair because connect can't be restarted.
Instead, we must wait for the connection to finish, then
examine the SO_ERROR socket option. */
#ifdef HAVE_POLL
{
struct pollfd fds;
int nfds;
(fds . fd) = s;
(fds . events) = (POLLIN | POLLOUT);
nfds = (poll ((&fds), 1, 0));
if ((nfds > 0) && (((fds . revents) & (POLLIN | POLLOUT)) != 0))
break;
if ((nfds < 0) && (errno != EINTR))
error_system_call (errno, syscall_select);
}
#else /* not HAVE_POLL */
#ifdef HAVE_SELECT
{
fd_set readers;
fd_set writers;
int result;
FD_ZERO (&readers);
FD_SET (s, (&readers));
writers = readers;
result = (UX_select ((s + 1), (&readers), (&writers), 0, 0));
if ((result > 0)
&& ((FD_ISSET (s, (&readers))) || (FD_ISSET (s, (&writers)))))
break;
if ((result < 0) && (errno != EINTR))
error_system_call (errno, syscall_select);
}
#else /* not HAVE_SELECT */
error_system_call (errno, syscall_connect);
break;
#endif /* not HAVE_SELECT */
#endif /* not HAVE_POLL */
}
{
int error;
socklen_t len = (sizeof (error));
if (((getsockopt (s, SOL_SOCKET, SO_ERROR, (&error), (&len))) < 0)
|| (error != 0))
error_system_call (error, syscall_connect);
}
}
}
int
DEFUN (OS_get_service_by_name, (service_name, protocol_name),
CONST char * service_name AND
CONST char * protocol_name)
{
struct servent * entry = (UX_getservbyname (service_name, protocol_name));
return ((entry == 0) ? (-1) : (entry -> s_port));
}
unsigned long
DEFUN (OS_get_service_by_number, (port_number),
CONST unsigned long port_number)
{
return ((unsigned long) (htons ((unsigned short) port_number)));
}
unsigned int
DEFUN_VOID (OS_host_address_length)
{
return (sizeof (struct in_addr));
}
char **
DEFUN (OS_get_host_by_name, (host_name), CONST char * host_name)
{
struct hostent * entry = (UX_gethostbyname (host_name));
if (entry == 0)
return (0);
#ifdef HAVE_HOSTENT_H_ADDR_LIST
return (entry -> h_addr_list);
#else
{
static char * addresses [2];
(addresses[0]) = (entry -> h_addr);
(addresses[1]) = 0;
return (addresses);
}
#endif
}
#define HOSTNAMESIZE 1024
CONST char *
DEFUN_VOID (OS_get_host_name)
{
char host_name [HOSTNAMESIZE];
STD_VOID_SYSTEM_CALL
(syscall_gethostname, (UX_gethostname (host_name, HOSTNAMESIZE)));
{
char * result = (OS_malloc ((strlen (host_name)) + 1));
strcpy (result, host_name);
return (result);
}
}
CONST char *
DEFUN (OS_canonical_host_name, (host_name), CONST char * host_name)
{
struct hostent * entry = (gethostbyname (host_name));
if (entry == 0)
return (0);
{
char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
strcpy (result, (entry -> h_name));
return (result);
}
}
CONST char *
DEFUN (OS_get_host_by_address, (host_addr), CONST char * host_addr)
{
struct hostent * entry
= (gethostbyaddr (host_addr, (OS_host_address_length ()), AF_INET));
if (entry == 0)
return (0);
{
char * result = (OS_malloc ((strlen (entry -> h_name)) + 1));
strcpy (result, (entry -> h_name));
return (result);
}
}
void
DEFUN (OS_host_address_any, (addr), PTR addr)
{
(((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_ANY));
}
void
DEFUN (OS_host_address_loopback, (addr), PTR addr)
{
(((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_LOOPBACK));
}
#ifdef HAVE_UNIX_SOCKETS
Tchannel
DEFUN (OS_open_unix_stream_socket, (filename), CONST char * filename)
{
int s;
Tchannel channel;
transaction_begin ();
STD_UINT_SYSTEM_CALL
(syscall_socket, s, (UX_socket (AF_UNIX, SOCK_STREAM, 0)));
MAKE_CHANNEL (s, channel_type_unix_stream_socket, channel =);
OS_channel_close_on_abort (channel);
{
struct sockaddr_un address;
(address . sun_family) = AF_UNIX;
strncpy ((address . sun_path), filename, (sizeof (address . sun_path)));
do_connect (s, ((struct sockaddr *) (&address)), (sizeof (address)));
}
transaction_commit ();
return (channel);
}
#endif /* HAVE_UNIX_SOCKETS */
Tchannel
DEFUN_VOID (OS_create_tcp_server_socket)
{
int s;
STD_UINT_SYSTEM_CALL
(syscall_socket, s, (UX_socket (AF_INET, SOCK_STREAM, 0)));
MAKE_CHANNEL (s, channel_type_tcp_server_socket, return);
}
void
DEFUN (OS_bind_tcp_server_socket, (channel, host, port),
Tchannel channel AND
PTR host AND
unsigned int port)
{
struct sockaddr_in address;
(address . sin_family) = AF_INET;
memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
(address . sin_port) = port;
STD_VOID_SYSTEM_CALL
(syscall_bind, (UX_bind ((CHANNEL_DESCRIPTOR (channel)),
((struct sockaddr *) (&address)),
(sizeof (struct sockaddr_in)))));
}
#ifndef SOCKET_LISTEN_BACKLOG
#define SOCKET_LISTEN_BACKLOG 1024
#endif
void
DEFUN (OS_listen_tcp_server_socket, (channel), Tchannel channel)
{
STD_VOID_SYSTEM_CALL
(syscall_listen,
(UX_listen ((CHANNEL_DESCRIPTOR (channel)), SOCKET_LISTEN_BACKLOG)));
}
Tchannel
DEFUN (OS_server_connection_accept, (channel, peer_host, peer_port),
Tchannel channel AND
PTR peer_host AND
unsigned int * peer_port)
{
static struct sockaddr_in address;
int address_length = (sizeof (struct sockaddr_in));
int s;
while (1)
{
s = (UX_accept ((CHANNEL_DESCRIPTOR (channel)),
((struct sockaddr *) (&address)),
(&address_length)));
if (s >= 0)
break;
if (errno != EINTR)
{
#ifdef EAGAIN
if (errno == EAGAIN)
return (NO_CHANNEL);
#endif
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK)
return (NO_CHANNEL);
#endif
error_system_call (errno, syscall_accept);
}
deliver_pending_interrupts ();
}
if (peer_host != 0)
memcpy (peer_host,
(& (address . sin_addr)),
(sizeof (address . sin_addr)));
if (peer_port != 0)
(*peer_port) = (address . sin_port);
MAKE_CHANNEL (s, channel_type_tcp_stream_socket, return);
}
#endif /* not HAVE_SOCKETS */