socket.c revision 6d4314d6b6bd36696f8c1970aa4601b820ab2b00
/*
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#define WANT_SYS_IOCTL_H
#include <slirp.h>
#include "ip_icmp.h"
#include "main.h"
#ifdef __sun__
#endif
#if defined(VBOX_WITH_SLIRP_ICMP) && defined (RT_OS_WINDOWS)
#include <icmpapi.h>
#endif
#ifdef VBOX_WITH_SLIRP_ICMP
static void send_icmp_to_guest(PNATState, char *, size_t, struct socket *, const struct sockaddr_in *);
#endif
void
so_init()
{
}
struct socket *
{
{
return so;
}
}
/*
* Create a new socket, initialise the fields
* It is the responsibility of the caller to
* insque() it into the correct linked-list
*/
struct socket *
socreate()
{
if(so)
{
so->s = -1;
}
return so;
}
/*
* remque and free a socket, clobber cache
*/
void
{
if (so == tcp_last_so)
tcp_last_so = &tcb;
else if (so == udp_last_so)
udp_last_so = &udb;
}
/*
* Read from so's socket into sb_snd, updating all relevant sbuf fields
* NOTE: This will only be called if it is select()ed for reading, so
* a read() of 0 (or less) means it's disconnected
*/
int
{
DEBUG_CALL("soread");
/*
* No need to check if there's enough room to read.
* soread wouldn't have been called if there weren't
*/
{
/* Should never succeed, but... */
n = 1;
}
else
{
/* Should never succeed, but... */
if (len)
{
{
{
n = 2;
}
else
{
n = 1;
}
}
else
n = 2;
}
else
{
n = 1;
}
}
#ifdef HAVE_READV
#else
#endif
if (nn <= 0)
{
#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
/*
* Special case for WSAEnumNetworkEvents: If we receive 0 bytes that
* _could_ mean that the connection is closed. But we will receive an
* FD_CLOSE event later if the connection was _really_ closed. With
* www.youtube.com I see this very often. Closing the socket too early
* would be dangerous.
*/
if (nn == 0)
return 0;
#endif
return 0;
else
{
/* nn == 0 means peer has performed an orderly shutdown */
return -1;
}
}
#ifndef HAVE_READV
/*
* If there was no error, try and read the second time round
* We read again if n = 2 (ie, there's another part of the buffer)
* and we read as much as we could in the first read
* We don't test for <= 0 this time, because there legitimately
* might not be any more data (since the socket is non-blocking),
* a close will be detected on next iteration.
* A return of -1 wont (shouldn't) happen, since it didn't happen above
*/
{
int ret;
if (ret > 0)
}
#endif
/* Update fields */
return nn;
}
/*
* Get urgent data
*
* When the socket is created, we set it SO_OOBINLINE,
* so when OOB data arrives, we soread() it and everything
* in the send buffer is sent as urgent data
*/
void
{
DEBUG_CALL("sorecvoob");
/*
* We take a guess at how much urgent data has arrived.
* In most situations, when urgent data arrives, the next
* read() should get all the urgent data. This guess will
* be wrong however if more data arrives just after the
* urgent data, or the read() doesn't return all the
* urgent data.
*/
}
/*
* Send urgent data
* There's a lot duplicated code here, but...
*/
int
{
int n, len;
DEBUG_CALL("sosendoob");
{
/* We can send it directly */
}
else
{
/*
* Since there's no sendv or sendtov like writev,
* we must copy all data to a linear buffer then
* send it all
*/
{
len += n;
}
#ifdef DEBUG
if (n != len)
#endif
}
return n;
}
/*
* Write data from so_rcv to so's socket,
* updating all sbuf field as necessary
*/
int
{
int n,nn;
DEBUG_CALL("sowrite");
{
return 0;
}
/*
* No need to check if there's something to write,
* sowrite wouldn't have been called otherwise
*/
{
/* Should never succeed, but... */
n = 1;
}
else
{
if (len)
{
n = 2;
}
else
n = 1;
}
/* Check if there's urgent data to send, and if so, send it */
#ifdef HAVE_READV
#else
#endif
/* This should never happen, but people tell me it does *shrug* */
return 0;
{
return -1;
}
#ifndef HAVE_READV
{
int ret;
if (ret > 0)
}
#endif
/* Update sbuf */
/*
* If in DRAIN mode, and there's no more data, set
* it CANTSENDMORE
*/
return nn;
}
/*
* recvfrom() a UDP socket
*/
void
{
struct sockaddr_in addr;
DEBUG_CALL("sorecvfrom");
#endif
#if defined(VBOX_WITH_SLIRP_ICMP) && !defined(RT_OS_WINDOWS)
#endif
} else { /* A "normal" UDP packet */
struct mbuf *m;
int len, n;
return;
m->m_data += if_maxlinkhdr;
/*
* XXX Shouldn't FIONREAD packets destined for port 53,
* but I don't know the max packet size for DNS lookups
*/
len = M_FREEROOM(m);
/* if (so->so_fport != htons(53)) */
{
if (n > len)
{
m_inc(m, n);
len = M_FREEROOM(m);
}
}
if(m->m_len < 0)
{
if (errno == EHOSTUNREACH)
else if(errno == ENETUNREACH)
}
else
{
/*
* Hack: domain name lookup will be used the most for UDP,
* and since they'll only be used once there's no need
* for the 4 minute (or whatever) timeout... So we time them
* out much quicker (10 seconds for now...)
*/
{
else
}
#if 0
{
m->m_len = 0;
}
#endif
/*
* If this packet was destined for CTL_ADDR,
* make it look like that's where it came from, done by udp_output
*/
} /* rx error */
} /* if ping packet */
}
/*
* sendto() a socket
*/
int
{
int ret;
struct sockaddr_in addr;
#if 0
struct sockaddr_in host_addr;
#endif
DEBUG_CALL("sosendto");
DEBUG_ARG("m = %lx", (long)m);
{
/* It's an alias */
switch(last_byte)
{
#if 0
/* handle this case at 'default:' */
case CTL_BROADCAST:
/* Send the packet to host to fully emulate broadcast */
/** @todo r=klaus: on Linux host this causes the host to receive
* the packet twice for some reason. And I cannot find any place
* in the man pages which states that sending a broadcast does not
* reach the host itself. */
break;
#endif
case CTL_DNS:
else
break;
case CTL_ALIAS:
default:
else
break;
}
}
else
/* Don't care what port we get */
if (ret < 0)
return -1;
/*
* Kill the socket if there's no reply in 4 minutes,
* but only if it's an expirable socket
*/
return 0;
}
/*
* XXX This should really be tcp_listen
*/
struct socket *
{
struct sockaddr_in addr;
int s, opt = 1;
DEBUG_CALL("solisten");
{
/* free(so); Not sofree() ??? free(NULL) == NOP */
return NULL;
}
/* Don't tcp_attach... we don't need so_snd nor so_rcv */
{
return NULL;
}
/*
* SS_FACCEPTONCE sockets must time out.
*/
if (flags & SS_FACCEPTONCE)
|| (listen(s,1) < 0))
{
#ifdef RT_OS_WINDOWS
closesocket(s);
/* Restore the real errno */
#else
close(s);
/* Restore the real errno */
#endif
return NULL;
}
else
so->s = s;
return so;
}
/*
* Data is available in so_rcv
* Just write() the data to the socket
* XXX not yet...
*/
void
{
#if 0
#endif
}
/*
* Data has been freed in so_snd
* We have room for a read() if we want to
* For now, don't read, it'll be done in the main loop
*/
void
{
}
/*
* Various session state calls
* XXX Should be #define's
* The socket state stuff needs work, these often get call 2 or 3
* times each when only 1 was needed
*/
void
{
}
void
{
}
void
{
{
}
/* XXX close() here as well? */
else
}
void
{
else
}
void
{
#if 0
/*
* XXX Do nothing ... ?
*/
#endif
}
/*
* Set write drain mode
* Set CANTSENDMORE once all data has been write()n
*/
void
{
else
}
#ifdef VBOX_WITH_SLIRP_ICMP
static void
send_icmp_to_guest(PNATState pData, char *buff, size_t len, struct socket *so, const struct sockaddr_in *addr)
{
char ip_copy[256];
int old_ip_len;
struct mbuf *m;
}
LogRel(("Can't find the corresponding packet for the received ICMP\n"));
return;
}
/* Now ip is pointing on header we've sent from guest */
}
/* source address from original IP packet*/
/* overide ther tail of old packet */
/* according RFC 793 error messages required copy of initial IP header + 64 bit */
}
/* the low level expects fields to be in host format so let's convert them*/
icmp_reflect(pData, m);
/* Don't call m_free here*/
}
static void
{
int len;
int i;
if (len <= 0) {
return;
}
for (i = 0; i < len; ++i) {
case IP_DEST_HOST_UNREACHABLE:
case IP_DEST_NET_UNREACHABLE:
case IP_DEST_PROT_UNREACHABLE:
/* UNREACH error inject here */
case IP_DEST_PORT_UNREACHABLE:
break;
}
}
}
#endif
{
struct sockaddr_in addr;
char buff[1500];
int len;
/* XXX Check if reply is "correct"? */
{
if (errno == EHOSTUNREACH)
else if(errno == ENETUNREACH)
}
else
{
#ifdef VBOX_WITH_SLIRP_ICMP
#else
#endif
}
}