Files
libsst/libsst-net/SST_NetAddress.c
2026-04-03 00:22:39 -05:00

292 lines
6.6 KiB
C

/*
SST_NetAddress.h
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 8/7/2012
Purpose:
Address storage manipulation
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "PlatformPrivate.h"
#include <SST/SST_NetAddress.h>
#include <string.h>
/*************************************************************************/
SST_NetResult SST_Net_InitAddress(SST_NetAddress* addr, SST_NetAddressFamily family, unsigned short port)
{
unsigned short nboPort; /* Port in network byte order */
size_t addrSize;
uint8_t* asBytes = (uint8_t*)addr;
nboPort = htons(port);
/* Avoid strict aliasing violations by setting up a temporary structure and memcpy()ing. */
switch(family)
{
case SSTNETADDRFAM_IPV4:
{
struct sockaddr_in addr4;
addr4.sin_family = AF_INET;
addr4.sin_port = nboPort;
addr4.sin_addr.s_addr = INADDR_ANY;
memset(&addr4.sin_zero, 0, sizeof(addr4.sin_zero));
addrSize = sizeof(struct sockaddr_in);
memcpy(addr, &addr4, addrSize);
break;
}
case SSTNETADDRFAM_IPV6:
{
struct sockaddr_in6 addr6;
addr6.sin6_family = AF_INET;
addr6.sin6_port = nboPort;
addr6.sin6_flowinfo = 0;
addr6.sin6_addr = in6addr_any;
addr6.sin6_scope_id = 0;
addrSize = sizeof(struct sockaddr_in6);
memcpy(addr, &addr6, addrSize);
break;
}
/* Default: return error */
default:
return SSTNETRESULT_ADDRFAMNOTSUPPORTED;
}
/* memset() the rest of the address storage to all-bits-zero. */
memset(asBytes + addrSize, 0, sizeof(SST_NetAddress) - addrSize);
return SSTNETRESULT_SUCCESS;
}
/*************************************************************************/
SST_NetAddressFamily SST_Net_GetAddressFamily(const SST_NetAddress* addr)
{
switch(addr->ss_family)
{
case AF_INET: return SSTNETADDRFAM_IPV4;
case AF_INET6: return SSTNETADDRFAM_IPV6;
default: return SSTNETADDRFAM_UNKNOWN;
}
}
/*************************************************************************/
unsigned short SST_Net_GetAddressPort(const SST_NetAddress* addr)
{
switch(addr->ss_family)
{
case AF_INET:
{
const struct sockaddr_in* addr4 = (const struct sockaddr_in*)addr;
return ntohs(addr4->sin_port);
}
case AF_INET6:
{
const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)addr;
return ntohs(addr6->sin6_port);
}
default: return UINT16_MAX;
}
}
/*************************************************************************/
int SST_Net_AddressCompare(const SST_NetAddress* addr1, const SST_NetAddress* addr2)
{
if(addr1->ss_family != addr2->ss_family)
return (addr1->ss_family < addr2->ss_family ? -1 : 1);
switch(addr1->ss_family)
{
case AF_INET:
{
const struct sockaddr_in* A = (const struct sockaddr_in*)addr1;
const struct sockaddr_in* B = (const struct sockaddr_in*)addr2;
/* Are the addresses different? */
if(A->sin_addr.s_addr != B->sin_addr.s_addr)
return (A->sin_addr.s_addr < B->sin_addr.s_addr ? -1 : 1);
/* Are the ports different? */
if(A->sin_port != B->sin_port)
return (A->sin_port < B->sin_port ? -1 : 1);
/* Address/port are the same, so OK */
return 0;
}
case AF_INET6:
{
const struct sockaddr_in6* A = (const struct sockaddr_in6*)addr1;
const struct sockaddr_in6* B = (const struct sockaddr_in6*)addr2;
int result;
result = memcmp(&A->sin6_addr, &B->sin6_addr, sizeof(struct in6_addr));
/* Are the addresses different? */
if(result != 0)
return result;
/* Are the ports different? */
if(A->sin6_port != B->sin6_port)
return (A->sin6_port < B->sin6_port ? -1 : 1);
/* Address/port are the same, so OK */
return 0;
}
}
/* Undefined structure -> useless result */
return -1;
}
/*************************************************************************/
int SST_Net_AddressIsLocalhost(const SST_NetAddress* addr)
{
int retval = 0;
switch(addr->ss_family)
{
case AF_INET:
{
struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
uint32_t localhost = (uint32_t)inet_addr("127.0.0.1");
uint32_t myaddr = (uint32_t)addr4->sin_addr.s_addr;
/* Compare address to loopback */
retval = (myaddr == localhost);
}
case AF_INET6:
{
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr;
/* Compare address to loopback */
retval = (memcmp(&addr6->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)) == 0);
}
default: retval = -1; /* Error code*/
}
return retval;
}
/*************************************************************************/
void SST_Net_AddressSetToLocalhost(SST_NetAddress* addr)
{
switch(addr->ss_family)
{
case AF_INET:
{
struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
addr4->sin_addr.s_addr = inet_addr("127.0.0.1");
}
case AF_INET6:
{
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr;
addr6->sin6_addr = in6addr_loopback;
}
}
}
/*************************************************************************/
SST_NetResult SST_Net_SetAddressFromAddress(SST_NetAddress* dst, const SST_NetAddress* src)
{
switch(src->ss_family)
{
case AF_INET:
{
struct sockaddr_in* dstAddr = (struct sockaddr_in*)dst;
const struct sockaddr_in* srcAddr = (const struct sockaddr_in*)src;
memcpy(&dstAddr->sin_addr, &srcAddr->sin_addr, sizeof(struct in_addr));
break;
}
case AF_INET6:
{
struct sockaddr_in6* dstAddr = (struct sockaddr_in6*)dst;
const struct sockaddr_in6* srcAddr = (const struct sockaddr_in6*)src;
memcpy(&dstAddr->sin6_addr, &srcAddr->sin6_addr, sizeof(struct in6_addr));
break;
}
/* Default: return error */
default:
return SSTNETRESULT_ADDRFAMNOTSUPPORTED;
}
return SSTNETRESULT_SUCCESS;
}
/*************************************************************************/
SST_NetResult SST_Net_SetAddressFromString(SST_NetAddress* addr, const char* addrString)
{
int result;
char buf[sizeof(SST_NetAddress)];
result = inet_pton(addr->ss_family, addrString, buf);
if(result > 0)
{
switch(addr->ss_family)
{
case AF_INET:
{
struct sockaddr_in* dst = (struct sockaddr_in*)addr;
memcpy(&dst->sin_addr, buf, sizeof(dst->sin_addr));
break;
}
case AF_INET6:
{
struct sockaddr_in6* dst = (struct sockaddr_in6*)addr;
memcpy(&dst->sin6_addr, buf, sizeof(dst->sin6_addr));
break;
}
}
return SSTNETRESULT_SUCCESS;
}
else if(result == 0)
return SSTNETRESULT_BADADDRESSSTRING;
//Other error
return NativeDecodeError();
}