1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413 |
|
module tango.net.device.Berkeley;
private import tango.sys.Common;
private import tango.core.Exception;
import consts=tango.sys.consts.socket;
private import tango.stdc.string : strlen;
private import tango.stdc.stringz;
/*******************************************************************************
*******************************************************************************/
enum {SOCKET_ERROR = consts.SOCKET_ERROR}
/*******************************************************************************
*******************************************************************************/
enum SocketOption
{
DEBUG = consts.SO_DEBUG , /* turn on debugging info recording */
BROADCAST = consts.SO_BROADCAST , /* permit sending of broadcast msgs */
REUSEADDR = consts.SO_REUSEADDR , /* allow local address reuse */
LINGER = consts.SO_LINGER , /* linger on close if data present */
DONTLINGER = ~(consts.SO_LINGER),
OOBINLINE = consts.SO_OOBINLINE , /* leave received OOB data in line */
ACCEPTCONN = consts.SO_ACCEPTCONN, /* socket has had listen() */
KEEPALIVE = consts.SO_KEEPALIVE , /* keep connections alive */
DONTROUTE = consts.SO_DONTROUTE , /* just use interface addresses */
TYPE = consts.SO_TYPE , /* get socket type */
/*
* Additional options, not kept in so_options.
*/
SNDBUF = consts.SO_SNDBUF, /* send buffer size */
RCVBUF = consts.SO_RCVBUF, /* receive buffer size */
ERROR = consts.SO_ERROR , /* get error status and clear */
// OptionLevel.IP settings
MULTICAST_TTL = consts.IP_MULTICAST_TTL ,
MULTICAST_LOOP = consts.IP_MULTICAST_LOOP ,
ADD_MEMBERSHIP = consts.IP_ADD_MEMBERSHIP ,
DROP_MEMBERSHIP = consts.IP_DROP_MEMBERSHIP,
// OptionLevel.TCP settings
TCP_NODELAY = consts.TCP_NODELAY ,
// Windows specifics
WIN_UPDATE_ACCEPT_CONTEXT = 0x700B,
WIN_CONNECT_TIME = 0x700C,
WIN_UPDATE_CONNECT_CONTEXT = 0x7010,
}
/*******************************************************************************
*******************************************************************************/
enum SocketOptionLevel
{
SOCKET = consts.SOL_SOCKET ,
IP = consts.IPPROTO_IP ,
TCP = consts.IPPROTO_TCP ,
UDP = consts.IPPROTO_UDP ,
}
/*******************************************************************************
*******************************************************************************/
enum SocketType
{
STREAM = consts.SOCK_STREAM , /++ sequential, reliable +/
DGRAM = consts.SOCK_DGRAM , /++ connectionless unreliable, max length +/
SEQPACKET = consts.SOCK_SEQPACKET, /++ sequential, reliable, max length +/
}
/*******************************************************************************
*******************************************************************************/
enum ProtocolType
{
IP = consts.IPPROTO_IP , /// default internet protocol (probably 4 for compatibility)
IPV4 = consts.IPPROTO_IP , /// internet protocol version 4
IPV6 = consts.IPPROTO_IPV6 , /// internet protocol version 6
ICMP = consts.IPPROTO_ICMP , /// internet control message protocol
IGMP = consts.IPPROTO_IGMP , /// internet group management protocol
TCP = consts.IPPROTO_TCP , /// transmission control protocol
PUP = consts.IPPROTO_PUP , /// PARC universal packet protocol
UDP = consts.IPPROTO_UDP , /// user datagram protocol
IDP = consts.IPPROTO_IDP , /// Xerox NS protocol
}
/*******************************************************************************
*******************************************************************************/
enum AddressFamily
{
UNSPEC = consts.AF_UNSPEC ,
UNIX = consts.AF_UNIX ,
INET = consts.AF_INET ,
IPX = consts.AF_IPX ,
APPLETALK = consts.AF_APPLETALK,
INET6 = consts.AF_INET6 ,
}
/*******************************************************************************
*******************************************************************************/
enum SocketShutdown
{
RECEIVE = consts.SHUT_RD,
SEND = consts.SHUT_WR,
BOTH = consts.SHUT_RDWR,
}
/*******************************************************************************
*******************************************************************************/
enum SocketFlags
{
NONE = 0,
OOB = consts.MSG_OOB, /// out of band
PEEK = consts.MSG_PEEK, /// only for receiving
DONTROUTE = consts.MSG_DONTROUTE, /// only for sending
NOSIGNAL = 0x4000, /// inhibit signals
}
enum AIFlags: int
{
PASSIVE = consts.AI_PASSIVE, /// get address to use bind()
CANONNAME = consts.AI_CANONNAME, /// fill ai_canonname
NUMERICHOST = consts.AI_NUMERICHOST, /// prevent host name resolution
NUMERICSERV = consts.AI_NUMERICSERV, /// prevent service name resolution valid
/// flags for addrinfo (not a standard def,
/// apps should not use it)
ALL = consts.AI_ALL, /// IPv6 and IPv4-mapped (with AI_V4MAPPED)
ADDRCONFIG = consts.AI_ADDRCONFIG, /// only if any address is assigned
V4MAPPED = consts.AI_V4MAPPED, /// accept IPv4-mapped IPv6 address special
/// recommended flags for getipnodebyname
MASK = consts.AI_MASK,
DEFAULT = consts.AI_DEFAULT,
}
enum AIError
{
BADFLAGS = consts.EAI_BADFLAGS, /// Invalid value for `ai_flags' field.
NONAME = consts.EAI_NONAME, /// NAME or SERVICE is unknown.
AGAIN = consts.EAI_AGAIN, /// Temporary failure in name resolution.
FAIL = consts.EAI_FAIL, /// Non-recoverable failure in name res.
NODATA = consts.EAI_NODATA, /// No address associated with NAME.
FAMILY = consts.EAI_FAMILY, /// `ai_family' not supported.
SOCKTYPE = consts.EAI_SOCKTYPE, /// `ai_socktype' not supported.
SERVICE = consts.EAI_SERVICE, /// SERVICE not supported for `ai_socktype'.
MEMORY = consts.EAI_MEMORY, /// Memory allocation failure.
}
enum NIFlags: int
{
MAXHOST = consts.NI_MAXHOST,
MAXSERV = consts.NI_MAXSERV,
NUMERICHOST = consts.NI_NUMERICHOST, /// Don't try to look up hostname.
NUMERICSERV = consts.NI_NUMERICSERV, /// Don't convert port number to name.
NOFQDN = consts.NI_NOFQDN, /// Only return nodename portion.
NAMEREQD = consts.NI_NAMEREQD, /// Don't return numeric addresses.
DGRAM = consts.NI_DGRAM, /// Look up UDP service rather than TCP.
}
/*******************************************************************************
conversions for network byte-order
*******************************************************************************/
version(BigEndian)
{
private ushort htons (ushort x)
{
return x;
}
private uint htonl (uint x)
{
return x;
}
}
else
{
private import tango.core.BitManip;
private ushort htons (ushort x)
{
return cast(ushort) ((x >> 8) | (x << 8));
}
private uint htonl (uint x)
{
return bswap(x);
}
}
/*******************************************************************************
*******************************************************************************/
version (Win32)
{
pragma (lib, "ws2_32.lib");
private import tango.sys.win32.WsaSock;
private enum socket_t: int
{
init = ~0
}
package extern (Windows)
{
alias closesocket close;
socket_t socket(int af, int type, int protocol);
int ioctlsocket(socket_t s, int cmd, uint* argp);
uint inet_addr(const(char)* cp);
int bind(socket_t s, Address.sockaddr* name, int namelen);
int connect(socket_t s, Address.sockaddr* name, int namelen);
int listen(socket_t s, int backlog);
socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
int closesocket(socket_t s);
int shutdown(socket_t s, int how);
int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
int send(socket_t s, const(void)* buf, int len, int flags);
int sendto(socket_t s, const(void)* buf, int len, int flags, Address.sockaddr* to, int tolen);
int recv(socket_t s, void* buf, int len, int flags);
int recvfrom(socket_t s, void* buf, int len, int flags, Address.sockaddr* from, int* fromlen);
int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
int gethostname(void* namebuffer, int buflen);
char* inet_ntoa(uint ina);
NetHost.hostent* gethostbyname(const(char)* name);
NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
/**
The gai_strerror function translates error codes of getaddrinfo,
freeaddrinfo and getnameinfo to a human readable string, suitable
for error reporting. (C) MAN
*/
//char* gai_strerror(int errcode);
/**
Given node and service, which identify an Internet host and a service,
getaddrinfo() returns one or more addrinfo structures, each of which
contains an Internet address that can be specified in a call to bind
or connect. The getaddrinfo() function combines the functionality
provided by the getservbyname and getservbyport functions into a single
interface, but unlike the latter functions, getaddrinfo() is reentrant
and allows programs to eliminate IPv4-versus-IPv6 dependencies.(C) MAN
*/
int function(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res) getaddrinfo;
/**
The freeaddrinfo() function frees the memory that was allocated for the
dynamically allocated linked list res. (C) MAN
*/
void function(Address.addrinfo *res) freeaddrinfo;
/**
The getnameinfo() function is the inverse of getaddrinfo: it converts
a socket address to a corresponding host and service, in a protocol-
independent manner. It combines the functionality of gethostbyaddr and
getservbyport, but unlike those functions, getaddrinfo is reentrant and
allows programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
*/
int function(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags) getnameinfo;
bool function (socket_t, uint, void*, DWORD, DWORD, DWORD, DWORD*, OVERLAPPED*) AcceptEx;
bool function (socket_t, HANDLE, DWORD, DWORD, OVERLAPPED*, void*, DWORD) TransmitFile;
bool function (socket_t, void*, int, void*, DWORD, DWORD*, OVERLAPPED*) ConnectEx;
//char* inet_ntop(int af, void *src, char *dst, int len);
}
private __gshared HMODULE lib;
shared static this()
{
lib = LoadLibraryA ("Ws2_32.dll");
getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
if (!getnameinfo)
{
FreeLibrary (lib);
lib = LoadLibraryA ("Wship6.dll");
}
getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
getaddrinfo = cast(typeof(getaddrinfo)) GetProcAddress(lib, "getaddrinfo");
freeaddrinfo = cast(typeof(freeaddrinfo)) GetProcAddress(lib, "freeaddrinfo");
if (!getnameinfo)
{
FreeLibrary (lib);
lib = null;
}
WSADATA wd = void;
if (WSAStartup (0x0202, &wd))
throw new SocketException("version of socket library is too old");
DWORD result;
Guid acceptG = {0xb5367df1, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
Guid connectG = {0x25a207b9, 0xddf3, 0x4660, [0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e]};
Guid transmitG = {0xb5367df0, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
auto s = cast(HANDLE) socket (AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
assert (s != cast(HANDLE) -1);
WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
&connectG, connectG.sizeof, &ConnectEx,
ConnectEx.sizeof, &result, null, null);
WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
&acceptG, acceptG.sizeof, &AcceptEx,
AcceptEx.sizeof, &result, null, null);
WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
&transmitG, transmitG.sizeof, &TransmitFile,
TransmitFile.sizeof, &result, null, null);
closesocket (cast(socket_t)(cast(int)s));
}
shared static ~this()
{
if (lib)
FreeLibrary (lib);
WSACleanup();
}
}
else
{
private import tango.stdc.errno;
//private alias int socket_t = -1;
private enum socket_t: int
{
init = -1
}
package extern (C)
{
socket_t socket(int af, int type, int protocol);
int fcntl(socket_t s, int f, ...);
uint inet_addr(const(char)* cp);
int bind(socket_t s, const(Address.sockaddr)* name, int namelen);
int connect(socket_t s, const(Address.sockaddr)* name, int namelen);
int listen(socket_t s, int backlog);
socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
int close(socket_t s);
int shutdown(socket_t s, int how);
int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
int send(socket_t s, const(void)* buf, size_t len, int flags);
int sendto(socket_t s, const(void)* buf, size_t len, int flags, Address.sockaddr* to, int tolen);
int recv(socket_t s, void* buf, size_t len, int flags);
int recvfrom(socket_t s, void* buf, size_t len, int flags, Address.sockaddr* from, int* fromlen);
int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
int gethostname(void* namebuffer, int buflen);
char* inet_ntoa(uint ina);
NetHost.hostent* gethostbyname(const(char)* name);
NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
/**
Given node and service, which identify an Internet host and a service,
getaddrinfo() returns one or more addrinfo structures, each of which
contains an Internet address that can be specified in a call to bind or
connect. The getaddrinfo() function combines the functionality provided
by the getservbyname and getservbyport functions into a single interface,
but unlike the latter functions, getaddrinfo() is reentrant and allows
programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
*/
int getaddrinfo(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res);
/**
The freeaddrinfo() function frees the memory that was allocated for the
dynamically allocated linked list res. (C) MAN
*/
void freeaddrinfo(Address.addrinfo *res);
/**
The getnameinfo() function is the inverse of getaddrinfo: it converts a socket
address to a corresponding host and service, in a protocol-independent manner.
It combines the functionality of gethostbyaddr and getservbyport, but unlike
those functions, getaddrinfo is reentrant and allows programs to eliminate
IPv4-versus-IPv6 dependencies. (C) MAN
*/
int getnameinfo(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags);
/**
The gai_strerror function translates error codes of getaddrinfo, freeaddrinfo
and getnameinfo to a human readable string, suitable for error reporting. (C) MAN
*/
const(char)* gai_strerror(int errcode);
const(char)* inet_ntop(int af, const(void) *src, char *dst, int len);
}
}
/*******************************************************************************
*******************************************************************************/
public struct Berkeley
{
socket_t sock;
SocketType type;
AddressFamily family;
ProtocolType protocol;
version (Windows)
bool synchronous;
enum INVALID_SOCKET = socket_t.init;
enum
{
Error = -1
}
alias Error ERROR; // backward compatibility
alias noDelay setNoDelay; // backward compatibility
alias addressReuse setAddressReuse; // backward compatibility
/***********************************************************************
Configure this instance
***********************************************************************/
void open (AddressFamily family, SocketType type, ProtocolType protocol, bool create=true)
{
this.type = type;
this.family = family;
this.protocol = protocol;
if (create)
reopen();
}
/***********************************************************************
Open/reopen a native socket for this instance
***********************************************************************/
void reopen (socket_t sock = sock.init)
{
if (this.sock != sock.init)
this.detach();
if (sock is sock.init)
{
sock = cast(socket_t) socket (family, type, protocol);
if (sock is sock.init)
exception ("Unable to create socket: ");
}
this.sock = sock;
}
/***********************************************************************
calling shutdown() before this is recommended for connection-
oriented sockets
***********************************************************************/
void detach ()
{
if (sock != sock.init)
.close (sock);
sock = sock.init;
}
/***********************************************************************
Return the underlying OS handle of this Conduit
***********************************************************************/
@property const socket_t handle ()
{
return sock;
}
/***********************************************************************
Return socket error status
***********************************************************************/
@property const int error ()
{
int errcode;
getOption (SocketOptionLevel.SOCKET, SocketOption.ERROR, (&errcode)[0..1]);
return errcode;
}
/***********************************************************************
Return the last error
***********************************************************************/
@property static int lastError ()
{
version (Win32)
return WSAGetLastError();
else
return errno;
}
/***********************************************************************
Is this socket still alive? A closed socket is considered to
be dead, but a shutdown socket is still alive.
***********************************************************************/
@property const bool isAlive ()
{
int type, typesize = type.sizeof;
return getsockopt (sock, SocketOptionLevel.SOCKET,
SocketOption.TYPE, cast(char*) &type,
&typesize) != Error;
}
/***********************************************************************
***********************************************************************/
@property AddressFamily addressFamily ()
{
return family;
}
/***********************************************************************
***********************************************************************/
Berkeley* bind (Address addr)
{
if(Error == .bind (sock, addr.name, addr.nameLen))
exception ("Unable to bind socket: ");
return &this;
}
/***********************************************************************
***********************************************************************/
Berkeley* connect (Address to)
{
if (Error == .connect (sock, to.name, to.nameLen))
{
if (! blocking)
{
auto err = lastError;
version (Windows)
{
if (err is WSAEWOULDBLOCK)
return &this;
}
else
{
if (err is EINPROGRESS)
return &this;
}
}
exception ("Unable to connect socket: ");
}
return &this;
}
/***********************************************************************
need to bind() first
***********************************************************************/
Berkeley* listen (int backlog)
{
if (Error == .listen (sock, backlog))
exception ("Unable to listen on socket: ");
return &this;
}
/***********************************************************************
need to bind() first
***********************************************************************/
void accept (ref Berkeley target)
{
auto newsock = .accept (sock, null, null);
if (socket_t.init is newsock)
exception ("Unable to accept socket connection: ");
target.reopen (newsock);
target.protocol = protocol; //same protocol
target.family = family; //same family
target.type = type; //same type
}
/***********************************************************************
The shutdown function shuts down the connection of the socket.
Depending on the argument value, it will:
- stop receiving data for this socket. If further data
arrives, it is rejected.
- stop trying to transmit data from this socket. Also
discards any data waiting to be sent. Stop looking for
acknowledgement of data already sent; don't retransmit
if any data is lost.
***********************************************************************/
Berkeley* shutdown (SocketShutdown how)
{
.shutdown (sock, how);
return &this;
}
/***********************************************************************
set linger timeout
***********************************************************************/
@property Berkeley* linger (int period)
{
version (Win32)
alias ushort attr;
else
alias uint attr;
union linger
{
struct {
attr l_onoff; // option on/off
attr l_linger; // linger time
};
attr[2] array; // combined
}
linger l;
l.l_onoff = 1; // option on/off
l.l_linger = cast(ushort) period; // linger time
return setOption (SocketOptionLevel.SOCKET, SocketOption.LINGER, l.array);
}
/***********************************************************************
enable/disable address reuse
***********************************************************************/
@property Berkeley* addressReuse (bool enabled)
{
int[1] x = enabled;
return setOption (SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, x);
}
/***********************************************************************
enable/disable noDelay option (nagle)
***********************************************************************/
@property Berkeley* noDelay (bool enabled)
{
int[1] x = enabled;
return setOption (SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, x);
}
/***********************************************************************
Helper function to handle the adding and dropping of group
membership.
***********************************************************************/
void joinGroup (IPv4Address address, bool onOff)
{
assert (address, "Socket.joinGroup :: invalid null address");
struct ip_mreq
{
uint imr_multiaddr; /* IP multicast address of group */
uint imr_interface; /* local IP address of interface */
}
ip_mreq mrq;
auto option = (onOff) ? SocketOption.ADD_MEMBERSHIP : SocketOption.DROP_MEMBERSHIP;
mrq.imr_interface = 0;
mrq.imr_multiaddr = address.sin.sin_addr;
if (.setsockopt(sock, SocketOptionLevel.IP, option, &mrq, mrq.sizeof) == Error)
exception ("Unable to perform multicast join: ");
}
/***********************************************************************
***********************************************************************/
const Address newFamilyObject ()
{
if (family is AddressFamily.INET)
return new IPv4Address;
if (family is AddressFamily.INET6)
return new IPv6Address;
return new UnknownAddress;
}
/***********************************************************************
return the hostname
***********************************************************************/
@property static char[] hostName ()
{
char[64] name;
if(Error == .gethostname (name.ptr, name.length))
exception ("Unable to obtain host name: ");
return name [0 .. strlen(name.ptr)].dup;
}
/***********************************************************************
return the default host address (IPv4)
***********************************************************************/
@property static uint hostAddress ()
{
auto ih = new NetHost;
ih.getHostByName (hostName);
assert (ih.addrList.length);
return ih.addrList[0];
}
/***********************************************************************
return the remote address of the current connection (IPv4)
***********************************************************************/
@property const Address remoteAddress ()
{
auto addr = newFamilyObject();
auto nameLen = addr.nameLen;
if(Error == .getpeername (sock, addr.name, &nameLen))
exception ("Unable to obtain remote socket address: ");
assert (addr.addressFamily is family);
return addr;
}
/***********************************************************************
return the local address of the current connection (IPv4)
***********************************************************************/
@property const Address localAddress ()
{
auto addr = newFamilyObject();
auto nameLen = addr.nameLen;
if(Error == .getsockname (sock, addr.name, &nameLen))
exception ("Unable to obtain local socket address: ");
assert (addr.addressFamily is family);
return addr;
}
/***********************************************************************
Send data on the connection. Returns the number of bytes
actually sent, or ERROR on failure. If the socket is blocking
and there is no buffer space left, send waits.
Returns number of bytes actually sent, or -1 on error
***********************************************************************/
const int send (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
{
if (buf.length is 0)
return 0;
version (Posix)
{
auto ret = .send (sock, buf.ptr, buf.length,
SocketFlags.NOSIGNAL + cast(int) flags);
if (errno is EPIPE)
ret = -1;
return ret;
}
else
return .send (sock, buf.ptr, buf.length, cast(int) flags);
}
/***********************************************************************
Send data to a specific destination Address. If the
destination address is not specified, a connection
must have been made and that address is used. If the
socket is blocking and there is no buffer space left,
sendTo waits.
***********************************************************************/
const int sendTo (const(void)[] buf, SocketFlags flags, Address to)
{
return sendTo (buf, cast(int) flags, to.name, to.nameLen);
}
/***********************************************************************
ditto
***********************************************************************/
const int sendTo (const(void)[] buf, Address to)
{
return sendTo (buf, SocketFlags.NONE, to);
}
/***********************************************************************
ditto - assumes you connect()ed
***********************************************************************/
const int sendTo (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
{
return sendTo (buf, cast(int) flags, null, 0);
}
/***********************************************************************
Send data to a specific destination Address. If the
destination address is not specified, a connection
must have been made and that address is used. If the
socket is blocking and there is no buffer space left,
sendTo waits.
***********************************************************************/
private const int sendTo (const(void)[] buf, int flags, Address.sockaddr* to, int len)
{
if (buf.length is 0)
return 0;
version (Posix)
{
auto ret = .sendto (sock, buf.ptr, buf.length,
flags | SocketFlags.NOSIGNAL, to, len);
if (errno is EPIPE)
ret = -1;
return ret;
}
else
return .sendto (sock, buf.ptr, buf.length, flags, to, len);
}
/***********************************************************************
Receive data on the connection. Returns the number of
bytes actually received, 0 if the remote side has closed
the connection, or ERROR on failure. If the socket is blocking,
receive waits until there is data to be received.
Returns number of bytes actually received, 0 on connection
closure, or -1 on error
***********************************************************************/
const int receive (void[] buf, SocketFlags flags=SocketFlags.NONE)
{
if (!buf.length)
badArg ("Socket.receive :: target buffer has 0 length");
return .recv(sock, buf.ptr, buf.length, cast(int)flags);
}
/***********************************************************************
Receive data and get the remote endpoint Address. Returns
the number of bytes actually received, 0 if the remote side
has closed the connection, or ERROR on failure. If the socket
is blocking, receiveFrom waits until there is data to be
received.
***********************************************************************/
const int receiveFrom (void[] buf, SocketFlags flags, Address from)
{
if (!buf.length)
badArg ("Socket.receiveFrom :: target buffer has 0 length");
assert(from.addressFamily() == family);
int nameLen = from.nameLen();
return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
}
/***********************************************************************
ditto
***********************************************************************/
const int receiveFrom (void[] buf, Address from)
{
return receiveFrom(buf, SocketFlags.NONE, from);
}
/***********************************************************************
ditto - assumes you connect()ed
***********************************************************************/
const int receiveFrom (void[] buf, SocketFlags flags = SocketFlags.NONE)
{
if (!buf.length)
badArg ("Socket.receiveFrom :: target buffer has 0 length");
return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
}
/***********************************************************************
returns the length, in bytes, of the actual result - very
different from getsockopt()
***********************************************************************/
const int getOption (SocketOptionLevel level, SocketOption option, void[] result)
{
int len = cast(int) result.length;
if(Error == .getsockopt (sock, cast(int)level, cast(int)option, result.ptr, &len))
exception ("Unable to get socket option: ");
return len;
}
/***********************************************************************
***********************************************************************/
Berkeley* setOption (SocketOptionLevel level, SocketOption option, const(void)[] value)
{
if(Error == .setsockopt (sock, cast(int)level, cast(int)option, value.ptr, cast(int) value.length))
exception ("Unable to set socket option: ");
return &this;
}
/***********************************************************************
getter
***********************************************************************/
@property const bool blocking()
{
version (Windows)
return synchronous;
else
return !(fcntl(sock, F_GETFL, 0) & O_NONBLOCK);
}
/***********************************************************************
setter
***********************************************************************/
@property void blocking(bool yes)
{
version (Windows)
{
uint num = !yes;
if(ioctlsocket(sock, consts.FIONBIO, &num) is ERROR)
exception("Unable to set socket blocking: ");
synchronous = yes;
}
else
{
int x = fcntl(sock, F_GETFL, 0);
if(yes)
x &= ~O_NONBLOCK;
else
x |= O_NONBLOCK;
if(fcntl(sock, F_SETFL, x) is ERROR)
exception("Unable to set socket blocking: ");
}
return;
}
/***********************************************************************
***********************************************************************/
static void exception (immutable(char)[] msg)
{
throw new SocketException (msg ~ SysError.lookup(lastError).idup);
}
/***********************************************************************
***********************************************************************/
protected static void badArg (immutable(char)[] msg)
{
throw new IllegalArgumentException (msg);
}
}
/*******************************************************************************
*******************************************************************************/
public abstract class Address
{
public struct sockaddr
{
ushort sa_family;
char[14] sa_data = 0;
}
struct addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
uint ai_addrlen;
version (FreeBSD)
{
char* ai_canonname;
sockaddr* ai_addr;
}
else
{
sockaddr* ai_addr;
char* ai_canonname;
}
addrinfo* ai_next;
}
@property abstract sockaddr* name();
@property abstract const int nameLen();
/***********************************************************************
Internal usage
***********************************************************************/
private static ushort ntohs (ushort x)
{
return htons(x);
}
/***********************************************************************
Internal usage
***********************************************************************/
private static uint ntohl (uint x)
{
return htonl(x);
}
/***********************************************************************
Internal usage
***********************************************************************/
private static char[] fromInt (char[] tmp, int i)
{
size_t j = tmp.length;
do {
tmp[--j] = cast(char)(i % 10 + '0');
} while (i /= 10);
return tmp [j .. $];
}
/***********************************************************************
Internal usage
***********************************************************************/
private static int toInt (const(char)[] s)
{
uint value;
foreach (c; s)
if (c >= '0' && c <= '9')
value = value * 10 + (c - '0');
else
break;
return value;
}
/***********************************************************************
Tango: added this common function
***********************************************************************/
static void exception (immutable(char)[] msg)
{
throw new SocketException (msg);
}
/***********************************************************************
Address factory
***********************************************************************/
static Address create (sockaddr* sa)
{
switch (sa.sa_family)
{
case AddressFamily.INET:
return new IPv4Address(sa);
case AddressFamily.INET6:
return new IPv6Address(sa);
default:
return null;
}
}
/***********************************************************************
***********************************************************************/
static Address resolve (const(char)[] host, const(char)[] service = null,
AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
return resolveAll (host, service, af, flags)[0];
}
/***********************************************************************
***********************************************************************/
static Address resolve (const(char)[] host, ushort port,
AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
return resolveAll (host, port, af, flags)[0];
}
/***********************************************************************
***********************************************************************/
static Address[] resolveAll (const(char)[] host, const(char)[] service = null,
AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
Address[] retVal;
version (Win32)
{
if (!getaddrinfo)
{ // *old* windows, let's fall back to NetHost
uint port = toInt(service);
if (flags & AIFlags.PASSIVE && host is null)
return [new IPv4Address(0, cast(ushort)port)];
auto nh = new NetHost;
if (!nh.getHostByName(host))
throw new AddressException("couldn't resolve " ~ host.idup);
retVal.length = nh.addrList.length;
foreach (i, addr; nh.addrList)
retVal[i] = new IPv4Address(addr, cast(ushort)port);
return retVal;
}
}
addrinfo* info;
addrinfo hints;
hints.ai_flags = flags;
hints.ai_family = (flags & AIFlags.PASSIVE && af == AddressFamily.UNSPEC) ? AddressFamily.INET6 : af;
hints.ai_socktype = SocketType.STREAM;
int error = getaddrinfo(toStringz(host), service.length == 0 ? null : toStringz(service), &hints, &info);
if (error != 0)
throw new AddressException("couldn't resolve " ~ host.idup);
retVal.length = 16;
retVal.length = 0;
while (info)
{
if (auto addr = create(info.ai_addr))
retVal ~= addr;
info = info.ai_next;
}
freeaddrinfo (info);
return retVal;
}
/***********************************************************************
***********************************************************************/
static Address[] resolveAll (const(char) host[], ushort port,
AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
char[16] buf;
return resolveAll (host, fromInt(buf, port), af, flags);
}
/***********************************************************************
***********************************************************************/
static Address passive (const(char)[] service,
AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
return resolve (null, service, af, flags | AIFlags.PASSIVE);
}
/***********************************************************************
***********************************************************************/
static Address passive (ushort port, AddressFamily af = AddressFamily.UNSPEC,
AIFlags flags = cast(AIFlags)0)
{
return resolve (null, port, af, flags | AIFlags.PASSIVE);
}
/***********************************************************************
***********************************************************************/
@property char[] toAddrString()
{
char[1025] host = void;
// Getting name info. Don't look up hostname, returns
// numeric name. (NIFlags.NUMERICHOST)
getnameinfo (name, nameLen, host.ptr, host.length, null, 0, NIFlags.NUMERICHOST);
return fromStringz (host.ptr).dup;
}
/***********************************************************************
***********************************************************************/
@property char[] toPortString()
{
char[32] service = void;
// Getting name info. Returns port number, not
// service name. (NIFlags.NUMERICSERV)
getnameinfo (name, nameLen, null, 0, service.ptr, service.length, NIFlags.NUMERICSERV);
foreach (i, c; service)
if (c == '\0')
return service[0..i].dup;
return null;
}
/***********************************************************************
***********************************************************************/
override string toString()
{
return toAddrString.idup ~ ":" ~ toPortString.idup;
}
/***********************************************************************
***********************************************************************/
@property AddressFamily addressFamily()
{
return cast(AddressFamily)name.sa_family;
}
}
/*******************************************************************************
*******************************************************************************/
public class UnknownAddress : Address
{
sockaddr sa;
/***********************************************************************
***********************************************************************/
@property override sockaddr* name()
{
return &sa;
}
/***********************************************************************
***********************************************************************/
@property override const int nameLen()
{
return sa.sizeof;
}
/***********************************************************************
***********************************************************************/
@property override AddressFamily addressFamily()
{
return cast(AddressFamily) sa.sa_family;
}
/***********************************************************************
***********************************************************************/
override string toString()
{
return "Unknown";
}
}
/*******************************************************************************
*******************************************************************************/
public class IPv4Address : Address
{
/***********************************************************************
***********************************************************************/
enum
{
ADDR_ANY = 0,
ADDR_NONE = cast(uint)-1,
PORT_ANY = 0
}
/***********************************************************************
***********************************************************************/
struct sockaddr_in
{
version (FreeBSD)
{
ubyte sin_len;
ubyte sinfamily = AddressFamily.INET;
}
else
{
ushort sinfamily = AddressFamily.INET;
}
ushort sin_port;
uint sin_addr; //in_addr
char[8] sin_zero = 0;
}
static assert(sockaddr_in.sizeof is 16);
private sockaddr_in sin;
/***********************************************************************
***********************************************************************/
protected this ()
{
}
/***********************************************************************
***********************************************************************/
this (ushort port)
{
sin.sin_addr = 0; //any, "0.0.0.0"
sin.sin_port = htons(port);
}
/***********************************************************************
***********************************************************************/
this (uint addr, ushort port)
{
sin.sin_addr = htonl(addr);
sin.sin_port = htons(port);
}
/***********************************************************************
-port- can be PORT_ANY
-addr- is an IP address or host name
***********************************************************************/
this (const(char)[] addr, ushort port = PORT_ANY)
{
uint uiaddr = parse(addr);
if (ADDR_NONE == uiaddr)
{
auto ih = new NetHost;
if (!ih.getHostByName(addr))
{
char[16] tmp = void;
exception ("Unable to resolve "~addr.idup~":"~fromInt(tmp, port).idup);
}
uiaddr = ih.addrList[0];
}
sin.sin_addr = htonl(uiaddr);
sin.sin_port = htons(port);
}
/***********************************************************************
***********************************************************************/
this (sockaddr* addr)
{
sin = *(cast(sockaddr_in*)addr);
}
/***********************************************************************
***********************************************************************/
@property override sockaddr* name()
{
return cast(sockaddr*)&sin;
}
/***********************************************************************
***********************************************************************/
@property override const int nameLen()
{
return cast(int)sin.sizeof;
}
/***********************************************************************
***********************************************************************/
@property override AddressFamily addressFamily()
{
return AddressFamily.INET;
}
/***********************************************************************
***********************************************************************/
@property const ushort port()
{
return ntohs(sin.sin_port);
}
/***********************************************************************
***********************************************************************/
@property const uint addr()
{
return ntohl(sin.sin_addr);
}
/***********************************************************************
***********************************************************************/
@property override const char[] toAddrString()
{
char[16] buff = 0;
version (Windows)
return fromStringz(inet_ntoa(sin.sin_addr)).dup;
else
return fromStringz(inet_ntop(AddressFamily.INET, &sin.sin_addr, buff.ptr, 16)).dup;
}
/***********************************************************************
***********************************************************************/
@property override const char[] toPortString()
{
char[8] _port;
return fromInt (_port, port()).dup;
}
/***********************************************************************
***********************************************************************/
override string toString()
{
return toAddrString().idup ~ ":" ~ toPortString().idup;
}
/***********************************************************************
-addr- is an IP address in the format "a.b.c.d"
returns ADDR_NONE on failure
***********************************************************************/
static uint parse(const(char)[] addr)
{
char[64] tmp;
synchronized (IPv4Address.classinfo)
return ntohl(inet_addr(toStringz(addr, tmp)));
}
}
/*******************************************************************************
*******************************************************************************/
debug(UnitTest)
{
unittest
{
IPv4Address ia = new IPv4Address("63.105.9.61", 80);
assert(ia.toString() == "63.105.9.61:80");
}
}
/*******************************************************************************
IPv6 is the next-generation Internet Protocol version
designated as the successor to IPv4, the first
implementation used in the Internet that is still in
dominant use currently.
More information: http://ipv6.com/
IPv6 supports 128-bit address space as opposed to 32-bit
address space of IPv4.
IPv6 is written as 8 blocks of 4 octal digits (16 bit)
separated by a colon (":"). Zero block can be replaced by "::".
For example:
---
0000:0000:0000:0000:0000:0000:0000:0001
is equal
::0001
is equal
::1
is analogue IPv4 127.0.0.1
0000:0000:0000:0000:0000:0000:0000:0000
is equal
::
is analogue IPv4 0.0.0.0
2001:cdba:0000:0000:0000:0000:3257:9652
is equal
2001:cdba::3257:9652
IPv4 address can be submitted through IPv6 as ::ffff:xx.xx.xx.xx,
where xx.xx.xx.xx 32-bit IPv4 addresses.
::ffff:51b0:ec6d
is equal
::ffff:81.176.236.109
is analogue IPv4 81.176.236.109
The URL for the IPv6 address will be of the form:
http://[2001:cdba:0000:0000:0000:0000:3257:9652]/
If needed to specify a port, it will be listed after the
closing square bracket followed by a colon.
http://[2001:cdba:0000:0000:0000:0000:3257:9652]:8080/
address: "2001:cdba:0000:0000:0000:0000:3257:9652"
port: 8080
IPv6Address can be used as well as IPv4Address.
scope addr = new IPv6Address(8080);
address: "::"
port: 8080
scope addr_2 = new IPv6Address("::1", 8081);
address: "::1"
port: 8081
scope addr_3 = new IPv6Address("::1");
address: "::1"
port: PORT_ANY
Also in the IPv6Address constructor can specify the service name
or port as string
scope addr_3 = new IPv6Address("::", "ssh");
address: "::"
port: 22 (ssh service port)
scope addr_4 = new IPv6Address("::", "8080");
address: "::"
port: 8080
---
*******************************************************************************/
class IPv6Address : Address
{
protected:
/***********************************************************************
***********************************************************************/
struct sockaddr_in6
{
ushort sin_family;
ushort sin_port;
uint sin6_flowinfo;
ubyte[16] sin6_addr;
uint sin6_scope_id;
}
sockaddr_in6 sin;
/***********************************************************************
***********************************************************************/
this ()
{
}
/***********************************************************************
***********************************************************************/
this (sockaddr* sa)
{
sin = *cast(sockaddr_in6*)sa;
}
/***********************************************************************
***********************************************************************/
@property override sockaddr* name()
{
return cast(sockaddr*)&sin;
}
/***********************************************************************
***********************************************************************/
@property override const int nameLen()
{
return cast(int)sin.sizeof;
}
public:
/***********************************************************************
***********************************************************************/
@property override AddressFamily addressFamily()
{
return AddressFamily.INET6;
}
enum ushort PORT_ANY = 0;
/***********************************************************************
***********************************************************************/
@property const ushort port()
{
return ntohs(sin.sin_port);
}
/***********************************************************************
Create IPv6Address with zero address
***********************************************************************/
this (int port)
{
this ("::", port);
}
/***********************************************************************
-port- can be PORT_ANY
-addr- is an IP address or host name
***********************************************************************/
this (const(char)[] addr, int port = PORT_ANY)
{
version (Win32)
{
if (!getaddrinfo)
exception ("This platform does not support IPv6.");
}
addrinfo* info;
addrinfo hints;
hints.ai_family = AddressFamily.INET6;
int error = getaddrinfo((addr ~ '\0').ptr, null, &hints, &info);
if (error != 0)
exception("failed to create IPv6Address: ");
sin = *cast(sockaddr_in6*)(info.ai_addr);
sin.sin_port = htons(cast(ushort) port);
}
/***********************************************************************
-service- can be a port number or service name
-addr- is an IP address or host name
***********************************************************************/
this (const(char)[] addr, const(char)[] service)
{
version (Win32)
{
if(! getaddrinfo)
exception ("This platform does not support IPv6.");
}
addrinfo* info;
addrinfo hints;
hints.ai_family = AddressFamily.INET6;
int error = getaddrinfo((addr ~ '\0').ptr, (service ~ '\0').ptr, &hints, &info);
if (error != 0)
exception ("failed to create IPv6Address: ");
sin = *cast(sockaddr_in6*)(info.ai_addr);
}
/***********************************************************************
***********************************************************************/
@property ubyte[] addr()
{
return sin.sin6_addr;
}
/***********************************************************************
***********************************************************************/
version (Posix)
@property override const char[] toAddrString()
{
char[100] buff = 0;
return fromStringz(inet_ntop(AddressFamily.INET6, &sin.sin6_addr, buff.ptr, 100)).dup;
}
/***********************************************************************
***********************************************************************/
@property override const char[] toPortString()
{
char[8] _port;
return fromInt (_port, port()).dup;
}
/***********************************************************************
***********************************************************************/
override string toString()
{
return "[" ~ toAddrString.idup ~ "]:" ~ toPortString.idup;
}
}
/*******************************************************************************
*******************************************************************************/
debug(UnitTest)
{
unittest
{
IPv6Address ia = new IPv6Address("7628:0d18:11a3:09d7:1f34:8a2e:07a0:765d", 8080);
assert(ia.toString() == "[7628:d18:11a3:9d7:1f34:8a2e:7a0:765d]:8080");
//assert(ia.toString() == "[7628:0d18:11a3:09d7:1f34:8a2e:07a0:765d]:8080");
}
}
/*******************************************************************************
*******************************************************************************/
public class NetHost
{
const(char)[] name;
const(char)[][] aliases;
uint[] addrList;
/***********************************************************************
***********************************************************************/
struct hostent
{
const(char)* h_name;
const(char)** h_aliases;
version (Win32)
{
short h_addrtype;
short h_length;
}
else
{
int h_addrtype;
int h_length;
}
const(char)** h_addr_list;
const(char)* h_addr()
{
return h_addr_list[0];
}
}
/***********************************************************************
***********************************************************************/
protected void validHostent(hostent* he)
{
if (he.h_addrtype != AddressFamily.INET || he.h_length != 4)
throw new SocketException("Address family mismatch.");
}
/***********************************************************************
***********************************************************************/
void populate (hostent* he)
{
int i;
const(char)* p;
name = fromStringz(he.h_name);
for (i = 0;; i++)
{
p = he.h_aliases[i];
if(!p)
break;
}
if (i)
{
aliases = new const(char)[][i];
for (i = 0; i != aliases.length; i++)
aliases[i] = fromStringz(he.h_aliases[i]);
}
else
aliases = null;
for (i = 0;; i++)
{
p = he.h_addr_list[i];
if(!p)
break;
}
if (i)
{
addrList = new uint[i];
for (i = 0; i != addrList.length; i++)
addrList[i] = Address.ntohl(*(cast(uint*)he.h_addr_list[i]));
}
else
addrList = null;
}
/***********************************************************************
***********************************************************************/
bool getHostByName(const(char)[] name)
{
char[1024] tmp;
synchronized (NetHost.classinfo)
{
auto he = gethostbyname(toStringz(name, tmp));
if(!he)
return false;
validHostent(he);
populate(he);
}
return true;
}
/***********************************************************************
***********************************************************************/
bool getHostByAddr(uint addr)
{
uint x = htonl(addr);
synchronized (NetHost.classinfo)
{
auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
if(!he)
return false;
validHostent(he);
populate(he);
}
return true;
}
/***********************************************************************
***********************************************************************/
//shortcut
bool getHostByAddr(const(char)[] addr)
{
char[64] tmp;
synchronized (NetHost.classinfo)
{
uint x = inet_addr(toStringz(addr, tmp));
auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
if(!he)
return false;
validHostent(he);
populate(he);
}
return true;
}
}
/*******************************************************************************
*******************************************************************************/
debug (UnitTest)
{
import tango.io.Stdout;
unittest
{
NetHost ih = new NetHost;
ih.getHostByName(Berkeley.hostName());
assert(ih.addrList.length > 0);
IPv4Address ia = new IPv4Address(ih.addrList[0], IPv4Address.PORT_ANY);
Stdout.formatln("addrses: {} {}\n", ia.toAddrString, ih.name);
Stdout.formatln("IP address = {}\nname = {}\n", ia.toAddrString(), ih.name);
foreach(int i, const(char)[] s; ih.aliases)
{
Stdout.formatln("aliases[%d] = {}\n", i, s);
}
Stdout("---\n");
assert(ih.getHostByAddr(ih.addrList[0]));
Stdout.formatln("name = {}\n", ih.name);
foreach(int i, const(char)[] s; ih.aliases)
{
Stdout.formatln("aliases[{}] = {}\n", i, s);
}
}
}
/*******************************************************************************
a set of sockets for Berkeley.select()
*******************************************************************************/
public class SocketSet
{
import tango.stdc.config;
struct timeval
{
c_long seconds, microseconds;
}
private size_t nbytes; //Win32: excludes uint.size "count"
private byte* buf;
struct fd {}
version(Windows)
{
@property uint count()
{
return *(cast(uint*)buf);
}
@property void count(int setter)
{
*(cast(uint*)buf) = setter;
}
@property socket_t* first()
{
return cast(socket_t*)(buf + uint.sizeof);
}
}
else version (Posix)
{
import tango.core.BitManip;
size_t nfdbits;
socket_t _maxfd = cast(socket_t)0;
const uint fdelt(socket_t s)
{
return cast(uint)(s / nfdbits);
}
const uint fdmask(socket_t s)
{
return 1 << cast(uint)(s % nfdbits);
}
@property uint* first()
{
return cast(uint*)buf;
}
@property public socket_t maxfd()
{
return _maxfd;
}
}
public:
this (uint max)
{
version(Win32)
{
nbytes = max * socket_t.sizeof;
buf = (new byte[nbytes + uint.sizeof]).ptr;
count = 0;
}
else version (Posix)
{
if (max <= 32)
nbytes = 32 * uint.sizeof;
else
nbytes = max * uint.sizeof;
buf = (new byte[nbytes]).ptr;
nfdbits = nbytes * 8;
//clear(); //new initializes to 0
}
else
{
static assert(0);
}
}
this (SocketSet o)
{
nbytes = o.nbytes;
auto size = nbytes;
version (Win32)
size += uint.sizeof;
version (Posix)
{
nfdbits = o.nfdbits;
_maxfd = o._maxfd;
}
auto b = new byte[size];
b[] = o.buf[0..size];
buf = b.ptr;
}
this()
{
version(Win32)
{
this(64);
}
else version (Posix)
{
this(32);
}
else
{
static assert(0);
}
}
SocketSet dup()
{
return new SocketSet (this);
}
SocketSet reset()
{
version(Win32)
{
count = 0;
}
else version (Posix)
{
buf[0 .. nbytes] = 0;
_maxfd = cast(socket_t)0;
}
else
{
static assert(0);
}
return this;
}
void add(socket_t s)
in
{
version(Win32)
{
assert(count < max); //added too many sockets; specify a higher max in the constructor
}
}
body
{
version(Win32)
{
uint c = count;
first[c] = s;
count = c + 1;
}
else version (Posix)
{
if (s > _maxfd)
_maxfd = s;
bts(cast(size_t*)&first[fdelt(s)], cast(size_t)s % nfdbits);
}
else
{
static assert(0);
}
}
void add(Berkeley* s)
{
add(s.handle);
}
void remove(socket_t s)
{
version(Win32)
{
uint c = count;
socket_t* start = first;
socket_t* stop = start + c;
for(; start != stop; start++)
{
if(*start == s)
goto found;
}
return; //not found
found:
for(++start; start != stop; start++)
{
*(start - 1) = *start;
}
count = c - 1;
}
else version (Posix)
{
btr(cast(size_t*)&first[fdelt(s)], cast(size_t)s % nfdbits);
// If we're removing the biggest file descriptor we've
// entered so far we need to recalculate this value
// for the socket set.
if (s == _maxfd)
{
while (--_maxfd >= 0)
{
if (isSet(_maxfd))
{
break;
}
}
}
}
else
{
static assert(0);
}
}
void remove(Berkeley* s)
{
remove(s.handle);
}
int isSet(socket_t s)
{
version(Win32)
{
socket_t* start = first;
socket_t* stop = start + count;
for(; start != stop; start++)
{
if(*start == s)
return true;
}
return false;
}
else version (Posix)
{
//return bt(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
int index = cast(uint)s % nfdbits;
return (cast(uint*)&first[fdelt(s)])[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)));
}
else
{
static assert(0);
}
}
int isSet(Berkeley* s)
{
return isSet(s.handle);
}
@property const size_t max()
{
return nbytes / socket_t.sizeof;
}
fd* toFd_set()
{
return cast(fd*)buf;
}
/***********************************************************************
SocketSet's are updated to include only those sockets which an
event occured.
Returns the number of events, 0 on timeout, or -1 on error
for a connect()ing socket, writeability means connected
for a listen()ing socket, readability means listening
Winsock: possibly internally limited to 64 sockets per set
***********************************************************************/
static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv)
{
fd* fr, fw, fe;
//make sure none of the SocketSet's are the same object
if (checkRead)
{
assert(checkRead !is checkWrite);
assert(checkRead !is checkError);
}
if (checkWrite)
assert(checkWrite !is checkError);
version(Win32)
{
//Windows has a problem with empty fd_set's that aren't null
fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
}
else
{
fr = checkRead ? checkRead.toFd_set() : null;
fw = checkWrite ? checkWrite.toFd_set() : null;
fe = checkError ? checkError.toFd_set() : null;
}
int result;
version(Win32)
{
while ((result = .select (socket_t.max - 1, fr, fw, fe, tv)) == -1)
{
if(WSAGetLastError() != WSAEINTR)
break;
}
}
else version (Posix)
{
socket_t maxfd = cast(socket_t)0;
if (checkRead)
maxfd = checkRead.maxfd;
if (checkWrite && checkWrite.maxfd > maxfd)
maxfd = checkWrite.maxfd;
if (checkError && checkError.maxfd > maxfd)
maxfd = checkError.maxfd;
while ((result = .select (maxfd + 1, fr, fw, fe, tv)) == -1)
{
if(errno() != EINTR)
break;
}
}
else
{
static assert(0);
}
return result;
}
/***********************************************************************
select with specified timeout
***********************************************************************/
static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, long microseconds)
{
timeval tv = {
cast(typeof(timeval.seconds)) (microseconds / 1000000),
cast(typeof(timeval.microseconds)) (microseconds % 1000000)
};
return select (checkRead, checkWrite, checkError, &tv);
}
/***********************************************************************
select with maximum timeout
***********************************************************************/
static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
{
return select (checkRead, checkWrite, checkError, null);
}
}
|