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
/
os2sock.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-07-18
|
9KB
|
342 lines
/* -*-C-*-
$Id: os2sock.c,v 1.18 2001/07/19 01:45:36 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.
*/
/* This conditional encompasses the entire file. */
#ifndef DISABLE_SOCKET_SUPPORT
/* This definition is necessary for compilation with newer versions of
the Developer's Toolkit for OS/2. The newer version default to
using TCP/IP 4.1, but this code was designed for TCP/IP 4.0. */
#define TCPV40HDRS
#include "scheme.h"
#include "prims.h"
#include "osscheme.h"
#include "os2.h"
#include "uxsock.h"
#include <types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/un.h>
#include <sys/socket.h>
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBACK 0x7F000001
#endif
static Tchannel initialize_stream_socket (int, enum channel_type);
static msg_t * stream_socket_reader (LHANDLE, qid_t, msg_t *, int *);
static void stream_socket_operator
(Tchannel, chop_t, choparg_t, choparg_t, choparg_t);
#define VOID_SOCKET_CALL(proc, args) \
{ \
while ((proc args) < 0) \
{ \
if ((sock_errno ()) != SOCEINTR) \
OS2_error_system_call ((sock_errno ()), syscall_ ## proc); \
deliver_pending_interrupts (); \
} \
}
#define VALUE_SOCKET_CALL(proc, args, var) \
{ \
while (1) \
{ \
int rc = (proc args); \
if (rc >= 0) \
{ \
var = rc; \
break; \
} \
if ((sock_errno ()) != SOCEINTR) \
OS2_error_system_call ((sock_errno ()), syscall_ ## proc); \
deliver_pending_interrupts (); \
} \
}
static void
socket_close_on_abort_1 (void * sp)
{
(void) soclose (* ((int *) sp));
}
static void
socket_close_on_abort (int s)
{
int * sp = (dstack_alloc (sizeof (int)));
(*sp) = s;
transaction_record_action (tat_abort, socket_close_on_abort_1, sp);
}
Tchannel
OS_open_tcp_stream_socket (void * host, unsigned int port)
{
int s;
struct sockaddr_in address;
transaction_begin ();
VALUE_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
socket_close_on_abort (s);
memset ((&address), 0, (sizeof (address)));
(address . sin_family) = AF_INET;
memcpy ((& (address . sin_addr)), host, (sizeof (struct in_addr)));
(address . sin_port) = port;
VOID_SOCKET_CALL
(connect, (s,
((struct sockaddr *) (&address)),
(sizeof (address))));
return (initialize_stream_socket (s, channel_type_tcp_stream_socket));
}
Tchannel
OS_open_unix_stream_socket (const char * filename)
{
int s;
struct sockaddr_un address;
transaction_begin ();
VALUE_SOCKET_CALL (socket, (PF_OS2, SOCK_STREAM, 0), s);
socket_close_on_abort (s);
memset ((&address), 0, (sizeof (address)));
(address . sun_family) = AF_OS2;
strncpy ((address . sun_path), filename, (sizeof (address . sun_path)));
VOID_SOCKET_CALL
(connect, (s,
((struct sockaddr *) (&address)),
(sizeof (address))));
return (initialize_stream_socket (s, channel_type_unix_stream_socket));
}
int
OS_get_service_by_name (const char * service_name, const char * protocol_name)
{
struct servent * entry
= (getservbyname (((char *) service_name),
((char *) protocol_name)));
return ((entry == 0) ? (-1) : (entry -> s_port));
}
unsigned long
OS_get_service_by_number (const unsigned long port_number)
{
return ((unsigned long) (htons ((unsigned short) port_number)));
}
unsigned int
OS_host_address_length (void)
{
return (sizeof (struct in_addr));
}
char **
OS_get_host_by_name (const char * host_name)
{
struct hostent * entry = (gethostbyname ((char *) host_name));
return ((entry == 0) ? 0 : (entry -> h_addr_list));
}
#define HOSTNAMESIZE 1024
const char *
OS_get_host_name (void)
{
char host_name [HOSTNAMESIZE];
if (gethostname (host_name, HOSTNAMESIZE))
OS2_error_anonymous ();
{
char * result = (OS_malloc ((strlen (host_name)) + 1));
strcpy (result, host_name);
return (result);
}
}
const char *
OS_canonical_host_name (const char * host_name)
{
struct hostent * entry = (gethostbyname ((char *) 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 *
OS_get_host_by_address (const char * host_addr)
{
struct hostent * entry
= (gethostbyaddr (((char *) 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
OS_host_address_any (void * addr)
{
(((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_ANY));
}
void
OS_host_address_loopback (void * addr)
{
(((struct in_addr *) addr) -> s_addr) = (htonl (INADDR_LOOPBACK));
}
Tchannel
OS_create_tcp_server_socket (void)
{
int s;
VALUE_SOCKET_CALL (socket, (PF_INET, SOCK_STREAM, 0), s);
return (initialize_stream_socket (s, channel_type_tcp_server_socket));
}
void
OS_bind_tcp_server_socket (Tchannel channel, void * host, unsigned int port)
{
struct sockaddr_in address;
memset ((&address), 0, (sizeof (address)));
(address . sin_family) = AF_INET;
memcpy ((& (address . sin_addr)), host, (sizeof (address . sin_addr)));
(address . sin_port) = port;
VOID_SOCKET_CALL
(bind, (((int) (CHANNEL_HANDLE (channel))),
((struct sockaddr *) (&address)),
(sizeof (struct sockaddr_in))));
}
#ifndef SOCKET_LISTEN_BACKLOG
#define SOCKET_LISTEN_BACKLOG 5
#endif
void
OS_listen_tcp_server_socket (Tchannel channel)
{
VOID_SOCKET_CALL
(listen, (((int) (CHANNEL_HANDLE (channel))), SOCKET_LISTEN_BACKLOG));
}
Tchannel
OS_server_connection_accept (Tchannel channel,
void * peer_host, unsigned int * peer_port)
{
static struct sockaddr_in address;
int s;
transaction_begin ();
while (1)
{
int address_length = (sizeof (struct sockaddr_in));
s = (accept (((int) (CHANNEL_HANDLE (channel))),
((struct sockaddr *) (&address)),
(&address_length)));
if (s >= 0)
break;
if ((sock_errno ()) == SOCEWOULDBLOCK)
return (NO_CHANNEL);
if ((sock_errno ()) != SOCEINTR)
OS2_error_system_call ((sock_errno ()), syscall_accept);
deliver_pending_interrupts ();
}
socket_close_on_abort (s);
if (peer_host != 0)
memcpy (peer_host, (& (address . sin_addr)), (sizeof (struct in_addr)));
if (peer_port != 0)
(*peer_port) = (address . sin_port);
return (initialize_stream_socket (s, channel_type_tcp_stream_socket));
}
static Tchannel
initialize_stream_socket (int s, enum channel_type type)
{
Tchannel channel = (OS2_allocate_channel ());
OS2_initialize_channel (channel, s, (CHANNEL_READ | CHANNEL_WRITE), type);
OS2_start_channel_thread (channel,
stream_socket_reader,
stream_socket_operator);
transaction_commit ();
return (channel);
}
static msg_t *
stream_socket_reader (LHANDLE handle, qid_t qid, msg_t * message, int * eofp)
{
int nread;
do
nread = (recv (((int) handle),
(SM_READAHEAD_DATA (message)),
(sizeof (SM_READAHEAD_DATA (message))),
0));
while ((nread < 0) && ((sock_errno ()) == SOCEINTR));
if (nread >= 0)
{
(SM_READAHEAD_SIZE (message)) = nread;
(*eofp) = (nread == 0);
return (message);
}
OS2_destroy_message (message);
if ((sock_errno ()) == SOCENOTSOCK)
/* Socket was closed on us -- no need to do anything else. */
return (0);
(*eofp) = 0;
return (OS2_make_syscall_error ((sock_errno ()), syscall_recv));
}
static void
stream_socket_operator (Tchannel channel, chop_t operation,
choparg_t arg1, choparg_t arg2, choparg_t arg3)
{
switch (operation)
{
case chop_read:
OS2_channel_thread_read_op (channel, arg1, arg2, arg3);
break;
case chop_write:
VALUE_SOCKET_CALL
(send, (((int) (CHANNEL_HANDLE (channel))),
((char *) arg1),
((size_t) arg2),
0),
(* ((long *) arg3)));
break;
case chop_close:
OS2_channel_thread_close (channel);
VOID_SOCKET_CALL (soclose, ((int) (CHANNEL_HANDLE (channel))));
break;
default:
OS2_logic_error ("Unknown operation for stream socket.");
break;
}
}
#endif /* not DISABLE_SOCKET_SUPPORT */