📄 socket.cxx
字号:
char auxdata[50];
readData.msg_control = auxdata;
readData.msg_controllen = sizeof(auxdata);
// read a packet
int r = ::recvmsg(os_handle, &readData, 0);
if (!ConvertOSError(r, LastReadError))
return PFalse;
lastReadCount = r;
if (r >= 0) {
struct cmsghdr * cmsg;
for (cmsg = CMSG_FIRSTHDR(&readData); cmsg != NULL; cmsg = CMSG_NXTHDR(&readData,cmsg)) {
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
in_pktinfo * info = (in_pktinfo *)CMSG_DATA(cmsg);
SetLastReceiveAddr(&info->ipi_spec_dst, sizeof(in_addr));
break;
}
}
}
return lastReadCount > 0;
}
#else
PBoolean PSocket::os_recvfrom(
void * buf, // Data to be written as URGENT TCP data.
PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
int flags,
sockaddr * addr, // Address from which the datagram was received.
PINDEX * addrlen)
{
lastReadCount = 0;
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return PFalse;
// attempt to read non-out of band data
int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
if (!ConvertOSError(r, LastReadError))
return PFalse;
lastReadCount = r;
return lastReadCount > 0;
}
#endif
PBoolean PSocket::os_sendto(
const void * buf, // Data to be written as URGENT TCP data.
PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
int flags,
sockaddr * addr, // Address to which the datagram is sent.
PINDEX addrlen)
{
lastWriteCount = 0;
if (!IsOpen())
return SetErrorValues(NotOpen, EBADF, LastWriteError);
// attempt to read data
int result;
for (;;) {
if (addr != NULL)
result = ::sendto(os_handle, (char *)buf, len, flags, (sockaddr *)addr, addrlen);
else
result = ::send(os_handle, (char *)buf, len, flags);
if (result > 0)
break;
if (errno != EWOULDBLOCK)
return ConvertOSError(-1, LastWriteError);
if (!PXSetIOBlock(PXWriteBlock, writeTimeout))
return PFalse;
}
#if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
PThread::Yield(); // Starvation prevention
#endif
lastWriteCount = result;
return ConvertOSError(0, LastWriteError);
}
PBoolean PSocket::Read(void * buf, PINDEX len)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF, LastReadError);
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return PFalse;
if (ConvertOSError(lastReadCount = ::recv(os_handle, (char *)buf, len, 0)))
return lastReadCount > 0;
lastReadCount = 0;
return PFalse;
}
//////////////////////////////////////////////////////////////////
//
// PEthSocket
//
PEthSocket::PEthSocket(PINDEX, PINDEX, PINDEX)
{
medium = MediumUnknown;
filterMask = FilterDirected|FilterBroadcast;
filterType = TypeAll;
fakeMacHeader = PFalse;
ipppInterface = PFalse;
}
PEthSocket::~PEthSocket()
{
Close();
}
PBoolean PEthSocket::Connect(const PString & interfaceName)
{
Close();
fakeMacHeader = PFalse;
ipppInterface = PFalse;
if (strncmp("eth", interfaceName, 3) == 0)
medium = Medium802_3;
else if (strncmp("lo", interfaceName, 2) == 0)
medium = MediumLoop;
else if (strncmp("sl", interfaceName, 2) == 0) {
medium = MediumWan;
fakeMacHeader = PTrue;
}
else if (strncmp("ppp", interfaceName, 3) == 0) {
medium = MediumWan;
fakeMacHeader = PTrue;
}
else if (strncmp("ippp", interfaceName, 4) == 0) {
medium = MediumWan;
ipppInterface = PTrue;
}
#ifdef P_RTEMS
else if (strncmp(RTEMS_BSP_NETWORK_DRIVER_NAME, interfaceName, 3) == 0)
medium = Medium802_3;
#endif
else
return SetErrorValues(NotFound, ENOENT);
#if defined(SIO_Get_MAC_Address)
PUDPSocket ifsock;
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_INET;
strcpy(ifr.ifr_name, interfaceName);
if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIO_Get_MAC_Address, &ifr)))
return PFalse;
memcpy(&macAddress, ifr.ifr_macaddr, sizeof(macAddress));
#endif
channelName = interfaceName;
return OpenSocket();
}
PBoolean PEthSocket::OpenSocket()
{
#ifdef SOCK_PACKET
if (!ConvertOSError(os_handle = os_socket(AF_INET, SOCK_PACKET, htons(filterType))))
return PFalse;
struct sockaddr addr;
memset(&addr, 0, sizeof(addr));
addr.sa_family = AF_INET;
strcpy(addr.sa_data, channelName);
if (!ConvertOSError(bind(os_handle, &addr, sizeof(addr)))) {
os_close();
os_handle = -1;
return PFalse;
}
#endif
return PTrue;
}
PBoolean PEthSocket::Close()
{
SetFilter(FilterDirected, filterType); // Turn off promiscuous mode
return PSocket::Close();
}
PBoolean PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
{
PUDPSocket ifsock;
ifreq ifreqs[20]; // Maximum of 20 interfaces
struct ifconf ifc;
ifc.ifc_len = sizeof(ifreqs);
ifc.ifc_buf = (caddr_t)ifreqs;
if (!ConvertOSError(ioctl(ifsock.GetHandle(), SIOCGIFCONF, &ifc)))
return PFalse;
int ifcount = ifc.ifc_len/sizeof(ifreq);
int ifidx;
for (ifidx = 0; ifidx < ifcount; ifidx++) {
if (strchr(ifreqs[ifidx].ifr_name, ':') == NULL) {
ifreq ifr;
strcpy(ifr.ifr_name, ifreqs[ifidx].ifr_name);
if (ioctl(ifsock.GetHandle(), SIOCGIFFLAGS, &ifr) == 0 &&
(ifr.ifr_flags & IFF_UP) != 0 &&
idx-- == 0) {
name = ifreqs[ifidx].ifr_name;
return PTrue;
}
}
}
return PFalse;
}
PBoolean PEthSocket::GetAddress(Address & addr)
{
if (!IsOpen())
return PFalse;
addr = macAddress;
return PTrue;
}
PBoolean PEthSocket::EnumIpAddress(PINDEX idx,
PIPSocket::Address & addr,
PIPSocket::Address & net_mask)
{
if (!IsOpen())
return PFalse;
PUDPSocket ifsock;
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_INET;
if (idx == 0)
strcpy(ifr.ifr_name, channelName);
else
sprintf(ifr.ifr_name, "%s:%u", (const char *)channelName, (int)(idx-1));
if (!ConvertOSError(ioctl(os_handle, SIOCGIFADDR, &ifr)))
return PFalse;
sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
addr = sin->sin_addr;
if (!ConvertOSError(ioctl(os_handle, SIOCGIFNETMASK, &ifr)))
return PFalse;
net_mask = sin->sin_addr;
return PTrue;
}
PBoolean PEthSocket::GetFilter(unsigned & mask, WORD & type)
{
if (!IsOpen())
return PFalse;
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, channelName);
if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
return PFalse;
if ((ifr.ifr_flags&IFF_PROMISC) != 0)
filterMask |= FilterPromiscuous;
else
filterMask &= ~FilterPromiscuous;
mask = filterMask;
type = filterType;
return PTrue;
}
PBoolean PEthSocket::SetFilter(unsigned filter, WORD type)
{
if (!IsOpen())
return PFalse;
if (filterType != type) {
os_close();
filterType = type;
if (!OpenSocket())
return PFalse;
}
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, channelName);
if (!ConvertOSError(ioctl(os_handle, SIOCGIFFLAGS, &ifr)))
return PFalse;
if ((filter&FilterPromiscuous) != 0)
ifr.ifr_flags |= IFF_PROMISC;
else
ifr.ifr_flags &= ~IFF_PROMISC;
if (!ConvertOSError(ioctl(os_handle, SIOCSIFFLAGS, &ifr)))
return PFalse;
filterMask = filter;
return PTrue;
}
PEthSocket::MediumTypes PEthSocket::GetMedium()
{
return medium;
}
PBoolean PEthSocket::ResetAdaptor()
{
// No implementation
return PTrue;
}
PBoolean PEthSocket::Read(void * buf, PINDEX len)
{
static const BYTE macHeader[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 8, 0 };
BYTE * bufptr = (BYTE *)buf;
if (fakeMacHeader) {
if (len <= (PINDEX)sizeof(macHeader)) {
memcpy(bufptr, macHeader, len);
lastReadCount = len;
return PTrue;
}
memcpy(bufptr, macHeader, sizeof(macHeader));
bufptr += sizeof(macHeader);
len -= sizeof(macHeader);
}
for (;;) {
sockaddr from;
PINDEX fromlen = sizeof(from);
if (!os_recvfrom(bufptr, len, 0, &from, &fromlen))
return PFalse;
if (channelName != from.sa_data)
continue;
if (ipppInterface) {
if (lastReadCount <= 10)
return PFalse;
if (memcmp(bufptr+6, "\xff\x03\x00\x21", 4) != 0) {
memmove(bufptr+sizeof(macHeader), bufptr, lastReadCount);
lastReadCount += sizeof(macHeader);
}
else {
memmove(bufptr+sizeof(macHeader), bufptr+10, lastReadCount);
lastReadCount += sizeof(macHeader)-10;
}
memcpy(bufptr, macHeader, sizeof(macHeader));
break;
}
if (fakeMacHeader) {
lastReadCount += sizeof(macHeader);
break;
}
if ((filterMask&FilterPromiscuous) != 0)
break;
if ((filterMask&FilterDirected) != 0 && macAddress == bufptr)
break;
static const Address broadcast;
if ((filterMask&FilterBroadcast) != 0 && broadcast == bufptr)
break;
}
return lastReadCount > 0;
}
PBoolean PEthSocket::Write(const void * buf, PINDEX len)
{
sockaddr to;
strcpy((char *)to.sa_data, channelName);
return os_sendto(buf, len, 0, &to, sizeof(to)) && lastWriteCount >= len;
}
///////////////////////////////////////////////////////////////////////////////
PBoolean PIPSocket::GetGatewayAddress(Address & addr)
{
RouteTable table;
if (GetRouteTable(table)) {
for (PINDEX i = 0; i < table.GetSize(); i++) {
if (table[i].GetNetwork() == 0) {
addr = table[i].GetDestination();
return PTrue;
}
}
}
return PFalse;
}
PString PIPSocket::GetGatewayInterface()
{
RouteTable table;
if (GetRouteTable(table)) {
for (PINDEX i = 0; i < table.GetSize(); i++) {
if (table[i].GetNetwork() == 0)
return table[i].GetInterface();
}
}
return PString();
}
#if defined(P_LINUX) || defined (P_AIX)
PBoolean PIPSocket::GetRouteTable(RouteTable & table)
{
PTextFile procfile;
if (!procfile.Open("/proc/net/route", PFile::ReadOnly))
return PFalse;
for (;;) {
// Ignore heading line or remainder of route line
procfile.ignore(1000, '\n');
if (procfile.eof())
return PTrue;
char iface[20];
unsigned long net_addr, dest_addr, net_mask;
int flags, refcnt, use, metric;
procfile >> iface >> ::hex >> net_addr >> dest_addr >> flags
>> ::dec >> refcnt >> use >> metric
>> ::hex >> net_mask;
if (procfile.bad())
return PFalse;
RouteEntry * entry = new RouteEntry(net_addr);
entry->net_mask = net_mask;
entry->destination = dest_addr;
entry->interfaceName = iface;
entry->metric = metric;
table.Append(entry);
}
}
#elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_QNX)
PBoolean process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric);
PBoolean get_ifname(int index, char *name);
PBoolean PIPSocket::GetRouteTable(RouteTable & table)
{
int mib[6];
size_t space_needed;
char *limit, *buf, *ptr;
struct rt_msghdr *rtm;
InterfaceTable if_table;
// Read the Routing Table
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &space_needed, NULL, 0) < 0) {
printf("sysctl: net.route.0.0.dump estimate");
return PFalse;
}
if ((buf = (char *)malloc(space_needed)) == NULL) {
printf("malloc(%lu)", (unsigned long)space_needed);
return PFalse;
}
// read the routing table data
if (sysctl(mib, 6, buf, &space_needed, NULL, 0) < 0) {
printf("sysctl: net.route.0.0.dump");
free(buf);
return PFalse;
}
// Read the interface table
if (!GetInterfaceTable(if_table)) {
printf("Interface Table Invalid\n");
return PFalse;
}
// Process the Routing Table data
limit = buf + space_needed;
for (ptr = buf; ptr < limit; ptr += rtm->rtm_msglen) {
unsigned long net_addr, dest_addr, net_mask;
int metric;
char name[16];
rtm = (struct rt_msghdr *)ptr;
if ( process_rtentry(rtm,ptr, &net_addr, &net_mask, &dest_addr, &metric) ){
RouteEntry * entry = new RouteEntry(net_addr);
entry->net_mask = net_mask;
entry->destination = dest_addr;
if ( get_ifname(rtm->rtm_index,name) )
entry->interfaceName = name;
entry->metric = metric;
table.Append(entry);
} // end if
} // end for loop
free(buf);
return PTrue;
}
PBoolean process_rtentry(struct rt_msghdr *rtm, char *ptr, unsigned long *p_net_addr,
unsigned long *p_net_mask, unsigned long *p_dest_addr, int *p_metric) {
struct sockaddr_in *sa_in;
unsigned long net_addr, dest_addr, net_mask;
int metric;
sa_in = (struct sockaddr_in *)(rtm + 1);
// Check for zero length entry
if (rtm->rtm_msglen == 0) {
printf("zero length message\n");
return PFalse;
}
if ((~rtm->rtm_flags&RTF_LLINFO)
#if defined(P_NETBSD) || defined(P_QNX)
&& (~rtm->rtm_flags&RTF_CLONED) // Net BSD has flag one way
#elif !defined(P_OPENBSD)
&& (~rtm->rtm_flags&RTF_WASCLONED) // Free BSD/MAC has it another
#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -