amiga-libnix3/socket/socketpair.c

210 lines
4.3 KiB
C

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
// #define TEST
#ifndef AF_UNIX
# define AF_UNIX AF_INET
#endif
#ifndef AF_LOCAL
# define AF_LOCAL AF_UNIX
#endif
#ifndef PF_LOCAL
# define PF_LOCAL AF_LOCAL
#endif
static int invalid_socket (int socket)
{
#ifdef WIN32
return (socket == INVALID_SOCKET);
#else
return (socket < 0);
#endif /* WIN32 */
}
#if !defined (WIN32) && !defined (closesocket)
# define closesocket close
#endif /* !WIN32 */
#if defined(AMIGA) && !defined(__ixemul__)
# define close CloseSocket
# include <proto/socket.h>
#endif
#ifdef DEBUG
# include <stdio.h>
# define GIFT_TRACE( msg ) perror msg
#else
# define GIFT_TRACE( msg ) ((void)0)
#endif
int socketpair (int family, int type, int protocol, int sv[2])
{
long insock, outsock, newsock;
struct sockaddr_in sock_in, sock_out;
long len;
/* windowz only has AF_INET (we use that for AF_LOCAL too) */
if (family != AF_LOCAL && family != AF_INET)
return -1;
/* STRAM and DGRAM sockets only */
if (type != SOCK_STREAM && type != SOCK_DGRAM)
return -1;
/* yes, we all love windoze */
if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL)
|| (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET))
return -1;
/* create the first socket */
newsock = socket (AF_INET, type, 0);
if (invalid_socket (newsock))
{
GIFT_TRACE (("first socket call failed"));
return -1;
}
/* bind the socket to any unused port */
sock_in.sin_family = AF_INET;
sock_in.sin_port = 0;
sock_in.sin_addr.s_addr = INADDR_ANY;
if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
{
GIFT_TRACE (("bind failed"));
closesocket (newsock);
return -1;
}
len = sizeof (sock_in);
if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0)
{
GIFT_TRACE (("getsockname error"));
closesocket (newsock);
return -1;
}
/* For stream sockets, create a listener */
if (type == SOCK_STREAM)
listen (newsock, 2);
/* create a connecting socket */
outsock = socket (AF_INET, type, 0);
if (invalid_socket (outsock))
{
GIFT_TRACE (("second socket call failed"));
closesocket (newsock);
return -1;
}
/* For datagram sockets, bind the 2nd socket to an unused address, too */
if (type == SOCK_DGRAM)
{
sock_out.sin_family = AF_INET;
sock_out.sin_port = 0;
sock_out.sin_addr.s_addr = INADDR_ANY;
if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0)
{
GIFT_TRACE (("bind failed"));
closesocket (newsock);
closesocket (outsock);
return -1;
}
len = sizeof (sock_out);
if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0)
{
GIFT_TRACE (("getsockname error"));
closesocket (newsock);
closesocket (outsock);
return -1;
}
}
/* Force IP address to loopback */
sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
if (type == SOCK_DGRAM)
sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* Do a connect */
if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
{
GIFT_TRACE (("connect error"));
closesocket (newsock);
closesocket (outsock);
return -1;
}
if (type == SOCK_STREAM)
{
/* For stream sockets, accept the connection and close the listener */
len = sizeof (sock_in);
insock = accept (newsock, (struct sockaddr *) &sock_in, &len);
if (invalid_socket (insock))
{
GIFT_TRACE (("accept error"));
closesocket (newsock);
closesocket (outsock);
return -1;
}
closesocket (newsock);
}
else
{
/* For datagram sockets, connect the 2nd socket */
if (connect (newsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0)
{
GIFT_TRACE (("connect error"));
closesocket (newsock);
closesocket (outsock);
return -1;
}
insock = newsock;
}
/* set the descriptors */
sv[0] = insock;
sv[1] = outsock;
/* we've done it */
return 0;
}
#ifdef TEST
#include <stdlib.h>
#include <proto/exec.h>
struct Library *SocketBase = NULL;
int main( void )
{
int pfd[2];
if((SocketBase = OpenLibrary("bsdsocket.library",4)))
{
if(socketpair(AF_LOCAL, SOCK_STREAM, 0, pfd) != -1)
{
printf("socketpair() succedeed\n");
printf("1: %ld, 2: %ld\n", pfd[0], pfd[1]);
Wait( SIGBREAKF_CTRL_C );
closesocket(pfd[0]);
closesocket(pfd[1]);
}
CloseLibrary(SocketBase);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
#endif /* TEST */