mirror of
https://github.com/izzy2lost/cpython.git
synced 2026-03-10 11:29:24 -07:00
2375 lines
68 KiB
C++
2375 lines
68 KiB
C++
/* Socket module */
|
|
|
|
/*
|
|
|
|
This module provides an interface to Berkeley socket IPC.
|
|
|
|
Limitations:
|
|
|
|
- Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
|
|
portable manner, though AF_PACKET, AF_NETLINK and AF_TIPC are supported
|
|
under Linux.
|
|
- No read/write operations (use sendall/recv or makefile instead).
|
|
- Additional restrictions apply on some non-Unix platforms (compensated
|
|
for by socket.py).
|
|
|
|
Module interface:
|
|
|
|
- socket.error: exception raised for socket specific errors
|
|
- socket.gaierror: exception raised for getaddrinfo/getnameinfo errors,
|
|
a subclass of socket.error
|
|
- socket.herror: exception raised for gethostby* errors,
|
|
a subclass of socket.error
|
|
- socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd')
|
|
- socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
|
|
- socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com')
|
|
- socket.getprotobyname(protocolname) --> protocol number
|
|
- socket.getservbyname(servicename[, protocolname]) --> port number
|
|
- socket.getservbyport(portnumber[, protocolname]) --> service name
|
|
- socket.socket([family[, type [, proto, fileno]]]) --> new socket object
|
|
(fileno specifies a pre-existing socket file descriptor)
|
|
- socket.socketpair([family[, type [, proto]]]) --> (socket, socket)
|
|
- socket.ntohs(16 bit value) --> new int object
|
|
- socket.ntohl(32 bit value) --> new int object
|
|
- socket.htons(16 bit value) --> new int object
|
|
- socket.htonl(32 bit value) --> new int object
|
|
- socket.getaddrinfo(host, port [, family, socktype, proto, flags])
|
|
--> List of (family, socktype, proto, canonname, sockaddr)
|
|
- socket.getnameinfo(sockaddr, flags) --> (host, port)
|
|
- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
|
|
- socket.has_ipv6: boolean value indicating if IPv6 is supported
|
|
- socket.inet_aton(IP address) -> 32-bit packed IP representation
|
|
- socket.inet_ntoa(packed IP) -> IP address string
|
|
- socket.getdefaulttimeout() -> None | float
|
|
- socket.setdefaulttimeout(None | float)
|
|
- socket.if_nameindex() -> list of tuples (if_index, if_name)
|
|
- socket.if_nametoindex(name) -> corresponding interface index
|
|
- socket.if_indextoname(index) -> corresponding interface name
|
|
- an Internet socket address is a pair (hostname, port)
|
|
where hostname can be anything recognized by gethostbyname()
|
|
(including the dd.dd.dd.dd notation) and port is in host byte order
|
|
- where a hostname is returned, the dd.dd.dd.dd notation is used
|
|
- a UNIX domain socket address is a string specifying the pathname
|
|
- an AF_PACKET socket address is a tuple containing a string
|
|
specifying the ethernet interface and an integer specifying
|
|
the Ethernet protocol number to be received. For example:
|
|
("eth0",0x1234). Optional 3rd,4th,5th elements in the tuple
|
|
specify packet-type and ha-type/addr.
|
|
- an AF_TIPC socket address is expressed as
|
|
(addr_type, v1, v2, v3 [, scope]); where addr_type can be one of:
|
|
TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, and TIPC_ADDR_ID;
|
|
and scope can be one of:
|
|
TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and TIPC_NODE_SCOPE.
|
|
The meaning of v1, v2 and v3 depends on the value of addr_type:
|
|
if addr_type is TIPC_ADDR_NAME:
|
|
v1 is the server type
|
|
v2 is the port identifier
|
|
v3 is ignored
|
|
if addr_type is TIPC_ADDR_NAMESEQ:
|
|
v1 is the server type
|
|
v2 is the lower port number
|
|
v3 is the upper port number
|
|
if addr_type is TIPC_ADDR_ID:
|
|
v1 is the node
|
|
v2 is the ref
|
|
v3 is ignored
|
|
|
|
|
|
Local naming conventions:
|
|
|
|
- names starting with sock_ are socket object methods
|
|
- names starting with socket_ are module-level functions
|
|
- names starting with PySocket are exported through socketmodule.h
|
|
|
|
*/
|
|
|
|
#include <ppltasks.h>
|
|
#include "Python.h"
|
|
#include "structmember.h"
|
|
|
|
using namespace Windows::Foundation;
|
|
using namespace Windows::Networking;
|
|
using namespace Windows::Networking::Sockets;
|
|
using namespace Windows::Storage::Streams;
|
|
using namespace Platform;
|
|
using namespace Concurrency;
|
|
/* Constants from winsock */
|
|
#define AF_INET 2
|
|
#define AF_INET6 23
|
|
#define SOCK_STREAM 1
|
|
#define SOCK_DGRAM 2
|
|
|
|
struct sock_addr_t {
|
|
HostName ^host;
|
|
String ^service;
|
|
};
|
|
|
|
/* Global variable holding the exception type for errors detected
|
|
by this module (but not argument type or memory errors, etc.). */
|
|
static PyObject *socket_herror;
|
|
static PyObject *socket_gaierror;
|
|
static PyObject *socket_timeout;
|
|
|
|
namespace{
|
|
extern PyTypeObject sock_type;
|
|
}
|
|
|
|
#undef MAX
|
|
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
|
|
|
/* The object holding a socket. It holds some extra information,
|
|
like the address family, which is used to decode socket address
|
|
arguments properly. */
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
Platform::Object^ sock_fd; /* Socket file descriptor */
|
|
DataWriter ^writer;
|
|
DataReader ^reader;
|
|
int sock_family; /* Address family, e.g., AF_INET */
|
|
int sock_type; /* Socket type, e.g., SOCK_STREAM */
|
|
int sock_proto; /* Protocol type, usually 0 */
|
|
PyObject *(*errorhandler)(void); /* Error handler; checks
|
|
errno, returns NULL and
|
|
sets a Python exception */
|
|
double sock_timeout; /* Operation timeout in seconds;
|
|
0.0 means non-blocking */
|
|
} PySocketSockObject;
|
|
|
|
/* Socket object documentation */
|
|
PyDoc_STRVAR(sock_doc,
|
|
"socket([family[, type[, proto]]]) -> socket object\n\
|
|
\n\
|
|
Open a socket of the given type. The family argument specifies the\n\
|
|
address family; it defaults to AF_INET. The type argument specifies\n\
|
|
whether this is a stream (SOCK_STREAM, this is the default)\n\
|
|
or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\
|
|
specifying the default protocol. Keyword arguments are accepted.\n\
|
|
\n\
|
|
A socket object represents one endpoint of a network connection.\n\
|
|
\n\
|
|
Methods of socket objects (keyword arguments not allowed):\n\
|
|
\n\
|
|
_accept() -- accept connection, returning new socket fd and client address\n\
|
|
bind(addr) -- bind the socket to a local address\n\
|
|
close() -- close the socket\n\
|
|
connect(addr) -- connect the socket to a remote address\n\
|
|
connect_ex(addr) -- connect, return an error code instead of an exception\n\
|
|
_dup() -- return a new socket fd duplicated from fileno()\n\
|
|
fileno() -- return underlying file descriptor\n\
|
|
getpeername() -- return remote address [*]\n\
|
|
getsockname() -- return local address\n\
|
|
getsockopt(level, optname[, buflen]) -- get socket options\n\
|
|
gettimeout() -- return timeout or None\n\
|
|
listen(n) -- start listening for incoming connections\n\
|
|
recv(buflen[, flags]) -- receive data\n\
|
|
recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\
|
|
recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\
|
|
recvfrom_into(buffer[, nbytes, [, flags])\n\
|
|
-- receive data and sender\'s address (into a buffer)\n\
|
|
sendall(data[, flags]) -- send all data\n\
|
|
send(data[, flags]) -- send data, may not send all of it\n\
|
|
sendto(data[, flags], addr) -- send data to a given address\n\
|
|
setblocking(0 | 1) -- set or clear the blocking I/O flag\n\
|
|
setsockopt(level, optname, value) -- set socket options\n\
|
|
settimeout(None | float) -- set or clear the timeout\n\
|
|
shutdown(how) -- shut down traffic in one or both directions\n\
|
|
if_nameindex() -- return all network interface indices and names\n\
|
|
if_nametoindex(name) -- return the corresponding interface index\n\
|
|
if_indextoname(index) -- return the corresponding interface name\n\
|
|
\n\
|
|
[*] not available on all platforms!");
|
|
|
|
static PyObject*
|
|
select_error(void)
|
|
{
|
|
PyErr_SetString(PyExc_OSError, "unable to select on socket");
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef MS_WINDOWS
|
|
#ifndef WSAEAGAIN
|
|
#define WSAEAGAIN WSAEWOULDBLOCK
|
|
#endif
|
|
#define CHECK_ERRNO(expected) \
|
|
(WSAGetLastError() == WSA ## expected)
|
|
#else
|
|
#define CHECK_ERRNO(expected) \
|
|
(errno == expected)
|
|
#endif
|
|
|
|
/* Convenience function to raise an error according to errno
|
|
and return a NULL pointer from a function. */
|
|
|
|
static PyObject *
|
|
set_error(void)
|
|
{
|
|
/* XXX */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
set_herror(int h_error)
|
|
{
|
|
/* XXX */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
set_gaierror(int error)
|
|
{
|
|
/* XXX */
|
|
return NULL;
|
|
}
|
|
|
|
/* Function to perform the setting of socket blocking mode
|
|
internally. block = (1 | 0). */
|
|
static int
|
|
internal_setblocking(PySocketSockObject *s, int block)
|
|
{
|
|
/* XXX later */
|
|
return 1;
|
|
}
|
|
|
|
/* Do a select()/poll() on the socket, if necessary (sock_timeout > 0).
|
|
The argument writing indicates the direction.
|
|
This does not raise an exception; we'll let our caller do that
|
|
after they've reacquired the interpreter lock.
|
|
Returns 1 on timeout, -1 on error, 0 otherwise. */
|
|
static int
|
|
internal_select_ex(PySocketSockObject *s, int writing, double interval)
|
|
{
|
|
/* Nothing to do unless we're in timeout mode (not non-blocking) */
|
|
if (s->sock_timeout <= 0.0)
|
|
return 0;
|
|
|
|
/* Guard against closed socket */
|
|
if (s->sock_fd == nullptr)
|
|
return 0;
|
|
|
|
/* Handling this condition here simplifies the select loops */
|
|
if (interval < 0.0)
|
|
return 1;
|
|
|
|
/* XXX not supported in winrt? */
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
internal_select(PySocketSockObject *s, int writing)
|
|
{
|
|
return internal_select_ex(s, writing, s->sock_timeout);
|
|
}
|
|
|
|
/*
|
|
Two macros for automatic retry of select() in case of false positives
|
|
(for example, select() could indicate a socket is ready for reading
|
|
but the data then discarded by the OS because of a wrong checksum).
|
|
Here is an example of use:
|
|
|
|
BEGIN_SELECT_LOOP(s)
|
|
Py_BEGIN_ALLOW_THREADS
|
|
timeout = internal_select_ex(s, 0, interval);
|
|
if (!timeout)
|
|
outlen = recv(s->sock_fd, cbuf, len, flags);
|
|
Py_END_ALLOW_THREADS
|
|
if (timeout == 1) {
|
|
PyErr_SetString(socket_timeout, "timed out");
|
|
return -1;
|
|
}
|
|
END_SELECT_LOOP(s)
|
|
*/
|
|
|
|
#define BEGIN_SELECT_LOOP(s) \
|
|
{ \
|
|
_PyTime_timeval now, deadline = {0, 0}; \
|
|
double interval = s->sock_timeout; \
|
|
int has_timeout = s->sock_timeout > 0.0; \
|
|
if (has_timeout) { \
|
|
_PyTime_gettimeofday(&now); \
|
|
deadline = now; \
|
|
_PyTime_ADD_SECONDS(deadline, s->sock_timeout); \
|
|
} \
|
|
while (1) { \
|
|
errno = 0; \
|
|
|
|
#define END_SELECT_LOOP(s) \
|
|
if (!has_timeout || \
|
|
(!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \
|
|
break; \
|
|
_PyTime_gettimeofday(&now); \
|
|
interval = _PyTime_INTERVAL(now, deadline); \
|
|
} \
|
|
} \
|
|
|
|
/* Initialize a new socket object. */
|
|
|
|
static double defaulttimeout = -1.0; /* Default timeout for new sockets */
|
|
|
|
static void
|
|
init_sockobject(PySocketSockObject *s,
|
|
Platform::Object^ fd, int family, int type, int proto)
|
|
{
|
|
s->sock_fd = fd;
|
|
s->sock_family = family;
|
|
s->sock_type = type;
|
|
s->sock_proto = proto;
|
|
|
|
s->errorhandler = &set_error;
|
|
#ifdef SOCK_NONBLOCK
|
|
if (type & SOCK_NONBLOCK)
|
|
s->sock_timeout = 0.0;
|
|
else
|
|
#endif
|
|
{
|
|
s->sock_timeout = defaulttimeout;
|
|
if (defaulttimeout >= 0.0)
|
|
internal_setblocking(s, 0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Create a new socket object.
|
|
This just creates the object and initializes it.
|
|
If the creation fails, return NULL and set an exception (implicit
|
|
in NEWOBJ()). */
|
|
|
|
static PySocketSockObject *
|
|
new_sockobject(Platform::Object^ fd, int family, int type, int proto)
|
|
{
|
|
PySocketSockObject *s;
|
|
s = (PySocketSockObject *)
|
|
PyType_GenericNew(&sock_type, NULL, NULL);
|
|
if (s != NULL)
|
|
init_sockobject(s, fd, family, type, proto);
|
|
return s;
|
|
}
|
|
|
|
|
|
/* Lock to allow python interpreter to continue, but only allow one
|
|
thread to be in gethostbyname or getaddrinfo */
|
|
#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
|
|
PyThread_type_lock netdb_lock;
|
|
#endif
|
|
|
|
|
|
/* Convert a string specifying a host name or one of a few symbolic
|
|
names to a numeric IP address. This usually calls gethostbyname()
|
|
to do the work; the names "" and "<broadcast>" are special.
|
|
Return the length (IPv4 should be 4 bytes), or negative if
|
|
an error occurred; then an exception is raised. */
|
|
|
|
static int
|
|
setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
|
|
{
|
|
/* XXX later */
|
|
PyErr_SetString(PyExc_OSError, "unknown address family");
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* Create a string object representing an IP address.
|
|
This is always a string of the form 'dd.dd.dd.dd' (with variable
|
|
size numbers). */
|
|
|
|
static PyObject *
|
|
makeipaddr(struct sockaddr *addr, int addrlen)
|
|
{
|
|
/* XXX later */
|
|
PyErr_SetString(PyExc_NotImplementedError, "makeipaddr");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Create an object representing the given socket address,
|
|
suitable for passing it back to bind(), connect() etc.
|
|
The family field of the sockaddr structure is inspected
|
|
to determine what kind of address it really is. */
|
|
|
|
static PyObject *
|
|
makesockaddr(Platform::Object^ sockfd, struct sockaddr *addr, size_t addrlen, int proto)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "makesockaddr");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Parse a socket address argument according to the socket object's
|
|
address family. Return 1 if the address was in the proper format,
|
|
0 of not. The address is returned through addr_ret, its length
|
|
through len_ret. */
|
|
|
|
static int
|
|
getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
|
struct sock_addr_t *addr_ret)
|
|
{
|
|
Py_UNICODE *host;
|
|
int port;
|
|
PyObject *strport;
|
|
if (!PyTuple_Check(args)) {
|
|
PyErr_Format(
|
|
PyExc_TypeError,
|
|
"getsockaddrarg: "
|
|
"address must be tuple, not %.500s",
|
|
Py_TYPE(args)->tp_name);
|
|
return 0;
|
|
}
|
|
if (!PyArg_ParseTuple(args, "ui", &host, &port))
|
|
return 0;
|
|
strport = PyUnicode_FromFormat("%i", port);
|
|
if (!strport)
|
|
return 1;
|
|
|
|
addr_ret->host = ref new HostName(ref new String(host));
|
|
addr_ret->service = ref new String(PyUnicode_AsUnicode(strport));
|
|
Py_DECREF(strport);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* s._accept() -> (fd, address) */
|
|
|
|
static PyObject *
|
|
sock_accept(PySocketSockObject *s)
|
|
{
|
|
StreamSocketListener ^fd;
|
|
|
|
try {
|
|
fd = safe_cast<StreamSocketListener^>(s->sock_fd);
|
|
} catch(...) {
|
|
return select_error();
|
|
}
|
|
|
|
/* XXX ConnectionReceived */
|
|
PyErr_SetString(PyExc_NotImplementedError, "accept");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(accept_doc,
|
|
"_accept() -> (socket, address info)\n\
|
|
\n\
|
|
Wait for an incoming connection. Return a new socket file descriptor\n\
|
|
representing the connection, and the address of the client.\n\
|
|
For IP sockets, the address info is a pair (hostaddr, port).");
|
|
|
|
/* s.setblocking(flag) method. Argument:
|
|
False -- non-blocking mode; same as settimeout(0)
|
|
True -- blocking mode; same as settimeout(None)
|
|
*/
|
|
|
|
static PyObject *
|
|
sock_setblocking(PySocketSockObject *s, PyObject *arg)
|
|
{
|
|
int block;
|
|
|
|
block = PyLong_AsLong(arg);
|
|
if (block == -1 && PyErr_Occurred())
|
|
return NULL;
|
|
|
|
s->sock_timeout = block ? -1.0 : 0.0;
|
|
internal_setblocking(s, block);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(setblocking_doc,
|
|
"setblocking(flag)\n\
|
|
\n\
|
|
Set the socket to blocking (flag is true) or non-blocking (false).\n\
|
|
setblocking(True) is equivalent to settimeout(None);\n\
|
|
setblocking(False) is equivalent to settimeout(0.0).");
|
|
|
|
/* s.settimeout(timeout) method. Argument:
|
|
None -- no timeout, blocking mode; same as setblocking(True)
|
|
0.0 -- non-blocking mode; same as setblocking(False)
|
|
> 0 -- timeout mode; operations time out after timeout seconds
|
|
< 0 -- illegal; raises an exception
|
|
*/
|
|
static PyObject *
|
|
sock_settimeout(PySocketSockObject *s, PyObject *arg)
|
|
{
|
|
double timeout;
|
|
|
|
if (arg == Py_None)
|
|
timeout = -1.0;
|
|
else {
|
|
timeout = PyFloat_AsDouble(arg);
|
|
if (timeout < 0.0) {
|
|
if (!PyErr_Occurred())
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Timeout value out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
s->sock_timeout = timeout;
|
|
internal_setblocking(s, timeout < 0.0);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(settimeout_doc,
|
|
"settimeout(timeout)\n\
|
|
\n\
|
|
Set a timeout on socket operations. 'timeout' can be a float,\n\
|
|
giving in seconds, or None. Setting a timeout of None disables\n\
|
|
the timeout feature and is equivalent to setblocking(1).\n\
|
|
Setting a timeout of zero is the same as setblocking(0).");
|
|
|
|
/* s.gettimeout() method.
|
|
Returns the timeout associated with a socket. */
|
|
static PyObject *
|
|
sock_gettimeout(PySocketSockObject *s)
|
|
{
|
|
if (s->sock_timeout < 0.0) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
else
|
|
return PyFloat_FromDouble(s->sock_timeout);
|
|
}
|
|
|
|
PyDoc_STRVAR(gettimeout_doc,
|
|
"gettimeout() -> timeout\n\
|
|
\n\
|
|
Returns the timeout in seconds (float) associated with socket \n\
|
|
operations. A timeout of None indicates that timeouts on socket \n\
|
|
operations are disabled.");
|
|
|
|
/* s.setsockopt() method.
|
|
With an integer third argument, sets an integer option.
|
|
With a string third argument, sets an option from a buffer;
|
|
use optional built-in module 'struct' to encode the string. */
|
|
|
|
static PyObject *
|
|
sock_setsockopt(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
int level;
|
|
int optname;
|
|
int res;
|
|
char *buf;
|
|
int buflen;
|
|
int flag;
|
|
|
|
if (PyArg_ParseTuple(args, "iii:setsockopt",
|
|
&level, &optname, &flag)) {
|
|
buf = (char *) &flag;
|
|
buflen = sizeof flag;
|
|
}
|
|
else {
|
|
PyErr_Clear();
|
|
if (!PyArg_ParseTuple(args, "iiy#:setsockopt",
|
|
&level, &optname, &buf, &buflen))
|
|
return NULL;
|
|
}
|
|
/* XXX implement */
|
|
res = -1;
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(setsockopt_doc,
|
|
"setsockopt(level, option, value)\n\
|
|
\n\
|
|
Set a socket option. See the Unix manual for level and option.\n\
|
|
The value argument can either be an integer or a string.");
|
|
|
|
|
|
#if 0
|
|
/* s.getsockopt() method.
|
|
With two arguments, retrieves an integer option.
|
|
With a third integer argument, retrieves a string buffer of that size;
|
|
use optional built-in module 'struct' to decode the string. */
|
|
|
|
static PyObject *
|
|
sock_getsockopt(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
int level;
|
|
int optname;
|
|
int res;
|
|
PyObject *buf;
|
|
socklen_t buflen = 0;
|
|
|
|
if (!PyArg_ParseTuple(args, "ii|i:getsockopt",
|
|
&level, &optname, &buflen))
|
|
return NULL;
|
|
|
|
if (buflen == 0) {
|
|
int flag = 0;
|
|
socklen_t flagsize = sizeof flag;
|
|
res = getsockopt(s->sock_fd, level, optname,
|
|
(void *)&flag, &flagsize);
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
return PyLong_FromLong(flag);
|
|
}
|
|
if (buflen <= 0 || buflen > 1024) {
|
|
PyErr_SetString(PyExc_OSError,
|
|
"getsockopt buflen out of range");
|
|
return NULL;
|
|
}
|
|
buf = PyBytes_FromStringAndSize((char *)NULL, buflen);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
/* XXX implement */
|
|
res = -1;
|
|
if (res < 0) {
|
|
Py_DECREF(buf);
|
|
return s->errorhandler();
|
|
}
|
|
_PyBytes_Resize(&buf, buflen);
|
|
return buf;
|
|
}
|
|
#endif
|
|
|
|
PyDoc_STRVAR(getsockopt_doc,
|
|
"getsockopt(level, option[, buffersize]) -> value\n\
|
|
\n\
|
|
Get a socket option. See the Unix manual for level and option.\n\
|
|
If a nonzero buffersize argument is given, the return value is a\n\
|
|
string of that length; otherwise it is an integer.");
|
|
|
|
|
|
/* s.bind(sockaddr) method */
|
|
|
|
static PyObject *
|
|
sock_bind(PySocketSockObject *s, PyObject *addro)
|
|
{
|
|
PyErr_SetString(PyExc_NotADirectoryError, "bind");
|
|
return NULL;
|
|
#if 0
|
|
sock_addr_t addrbuf;
|
|
int addrlen;
|
|
int res;
|
|
|
|
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
|
|
return NULL;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen);
|
|
Py_END_ALLOW_THREADS
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(bind_doc,
|
|
"bind(address)\n\
|
|
\n\
|
|
Bind the socket to a local address. For IP sockets, the address is a\n\
|
|
pair (host, port); the host must refer to the local host. For raw packet\n\
|
|
sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])");
|
|
|
|
|
|
/* s.close() method.
|
|
Set the file descriptor to -1 so operations tried subsequently
|
|
will surely fail. */
|
|
|
|
static PyObject *
|
|
sock_close(PySocketSockObject *s)
|
|
{
|
|
Platform::IDisposable^ fd;
|
|
|
|
if ((fd = (Platform::IDisposable^)s->sock_fd) != nullptr) {
|
|
//XXX compiler rejects the call to dispose
|
|
//fd->Dispose();
|
|
s->sock_fd = nullptr;
|
|
}
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(close_doc,
|
|
"close()\n\
|
|
\n\
|
|
Close the socket. It cannot be used after this call.");
|
|
|
|
static PyObject *
|
|
sock_detach(PySocketSockObject *s)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "detach");
|
|
return NULL;
|
|
#if 0
|
|
Platform::Object^ fd = s->sock_fd;
|
|
s->sock_fd = -1;
|
|
return PyLong_FromSocket_t(fd);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(detach_doc,
|
|
"detach()\n\
|
|
\n\
|
|
Close the socket object without closing the underlying file descriptor.\
|
|
The object cannot be used after this call, but the file descriptor\
|
|
can be reused for other purposes. The file descriptor is returned.");
|
|
|
|
/* s.connect(sockaddr) method */
|
|
|
|
static PyObject *
|
|
sock_connect(PySocketSockObject *s, PyObject *addro)
|
|
{
|
|
sock_addr_t addrbuf;
|
|
int res = 0;
|
|
int timeout = 0;
|
|
HostName ^host;
|
|
String ^error = nullptr;
|
|
|
|
StreamSocket ^sock = (StreamSocket^)(s->sock_fd);
|
|
|
|
if (!getsockaddrarg(s, addro, &addrbuf))
|
|
return NULL;
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
auto t = create_task(sock->ConnectAsync(addrbuf.host, addrbuf.service, SocketProtectionLevel::PlainSocket));
|
|
try{
|
|
t.get();
|
|
}catch(Exception ^e){
|
|
error = e->ToString();
|
|
}
|
|
Py_END_ALLOW_THREADS
|
|
|
|
if (timeout == 1) {
|
|
//PyErr_SetString(socket_timeout, "timed out");
|
|
return NULL;
|
|
}
|
|
if (error != nullptr) {
|
|
PyObject *msg = PyUnicode_FromUnicode(error->Data(), error->Length());
|
|
/* XXX error check */
|
|
PyErr_SetObject(PyExc_OSError, msg);
|
|
Py_DECREF(msg);
|
|
return NULL;
|
|
}
|
|
else {
|
|
s->writer = ref new DataWriter(sock->OutputStream);
|
|
s->reader = ref new DataReader(sock->InputStream);
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(connect_doc,
|
|
"connect(address)\n\
|
|
\n\
|
|
Connect the socket to a remote address. For IP sockets, the address\n\
|
|
is a pair (host, port).");
|
|
|
|
|
|
/* s.connect_ex(sockaddr) method */
|
|
|
|
static PyObject *
|
|
sock_connect_ex(PySocketSockObject *s, PyObject *addro)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "connect_ex");
|
|
return NULL;
|
|
#if 0
|
|
sock_addr_t addrbuf;
|
|
int addrlen;
|
|
int res;
|
|
int timeout;
|
|
|
|
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
|
|
return NULL;
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
/* Signals are not errors (though they may raise exceptions). Adapted
|
|
from PyErr_SetFromErrnoWithFilenameObject(). */
|
|
#ifdef EINTR
|
|
if (res == EINTR && PyErr_CheckSignals())
|
|
return NULL;
|
|
#endif
|
|
|
|
return PyLong_FromLong((long) res);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(connect_ex_doc,
|
|
"connect_ex(address) -> errno\n\
|
|
\n\
|
|
This is like connect(address), but returns an error code (the errno value)\n\
|
|
instead of raising an exception when an error occurs.");
|
|
|
|
|
|
/* s.fileno() method */
|
|
|
|
static PyObject *
|
|
sock_fileno(PySocketSockObject *s)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "fileno");
|
|
return NULL;
|
|
// return PyLong_FromSocket_t(s->sock_fd);
|
|
}
|
|
|
|
PyDoc_STRVAR(fileno_doc,
|
|
"fileno() -> integer\n\
|
|
\n\
|
|
Return the integer file descriptor of the socket.");
|
|
|
|
|
|
/* s.getsockname() method */
|
|
|
|
static PyObject *
|
|
sock_getsockname(PySocketSockObject *s)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getsockname");
|
|
return NULL;
|
|
#if 0
|
|
sock_addr_t addrbuf;
|
|
int res;
|
|
socklen_t addrlen;
|
|
|
|
if (!getsockaddrlen(s, &addrlen))
|
|
return NULL;
|
|
memset(&addrbuf, 0, addrlen);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
|
Py_END_ALLOW_THREADS
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
|
|
s->sock_proto);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(getsockname_doc,
|
|
"getsockname() -> address info\n\
|
|
\n\
|
|
Return the address of the local endpoint. For IP sockets, the address\n\
|
|
info is a pair (hostaddr, port).");
|
|
|
|
|
|
/* s.getpeername() method */
|
|
|
|
static PyObject *
|
|
sock_getpeername(PySocketSockObject *s)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getpeername");
|
|
return NULL;
|
|
#if 0
|
|
sock_addr_t addrbuf;
|
|
int res;
|
|
socklen_t addrlen;
|
|
|
|
if (!getsockaddrlen(s, &addrlen))
|
|
return NULL;
|
|
memset(&addrbuf, 0, addrlen);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
|
Py_END_ALLOW_THREADS
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
|
|
s->sock_proto);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(getpeername_doc,
|
|
"getpeername() -> address info\n\
|
|
\n\
|
|
Return the address of the remote endpoint. For IP sockets, the address\n\
|
|
info is a pair (hostaddr, port).");
|
|
|
|
|
|
|
|
/* s.listen(n) method */
|
|
|
|
static PyObject *
|
|
sock_listen(PySocketSockObject *s, PyObject *arg)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "listen");
|
|
return NULL;
|
|
#if 0
|
|
int backlog;
|
|
int res;
|
|
|
|
backlog = PyLong_AsLong(arg);
|
|
if (backlog == -1 && PyErr_Occurred())
|
|
return NULL;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
/* To avoid problems on systems that don't allow a negative backlog
|
|
* (which doesn't make sense anyway) we force a minimum value of 0. */
|
|
if (backlog < 0)
|
|
backlog = 0;
|
|
res = listen(s->sock_fd, backlog);
|
|
Py_END_ALLOW_THREADS
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(listen_doc,
|
|
"listen(backlog)\n\
|
|
\n\
|
|
Enable a server to accept connections. The backlog argument must be at\n\
|
|
least 0 (if it is lower, it is set to 0); it specifies the number of\n\
|
|
unaccepted connections that the system will allow before refusing new\n\
|
|
connections.");
|
|
|
|
|
|
/* s.recv(nbytes [,flags]) method */
|
|
|
|
static PyObject *
|
|
sock_recv(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
Py_ssize_t recvlen;
|
|
int flags = 0;
|
|
|
|
if (!PyArg_ParseTuple(args, "n|i:recv", &recvlen, &flags))
|
|
return NULL;
|
|
|
|
if (recvlen < 0) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"negative buffersize in recv");
|
|
return NULL;
|
|
}
|
|
|
|
size_t bytesread;
|
|
auto t = create_task(s->reader->LoadAsync(recvlen));
|
|
try {
|
|
bytesread = t.get();
|
|
} catch(Exception ^e) {
|
|
String ^error = e->ToString();
|
|
PyObject *msg = PyUnicode_FromUnicode(error->Data(), error->Length());
|
|
if (!msg)
|
|
return NULL;
|
|
PyErr_SetObject(PyExc_OSError, msg);
|
|
Py_DECREF(msg);
|
|
return NULL;
|
|
}
|
|
|
|
auto buf = ref new Array<unsigned char>(bytesread);
|
|
s->reader->ReadBytes(buf);
|
|
return PyBytes_FromStringAndSize((char*)buf->Data, buf->Length);
|
|
}
|
|
|
|
PyDoc_STRVAR(recv_doc,
|
|
"recv(buffersize[, flags]) -> data\n\
|
|
\n\
|
|
Receive up to buffersize bytes from the socket. For the optional flags\n\
|
|
argument, see the Unix manual. When no data is available, block until\n\
|
|
at least one byte is available or until the remote end is closed. When\n\
|
|
the remote end is closed and all data is read, return the empty string.");
|
|
|
|
|
|
/* s.recv_into(buffer, [nbytes [,flags]]) method */
|
|
|
|
static PyObject*
|
|
sock_recv_into(PySocketSockObject *s, PyObject *args, PyObject *kwds)
|
|
{
|
|
static char *kwlist[] = {"buffer", "nbytes", "flags", 0};
|
|
|
|
int flags = 0;
|
|
Py_buffer pbuf;
|
|
Py_ssize_t readlen, recvlen = 0;
|
|
|
|
/* Get the buffer's memory */
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "w*|ni:recv_into", kwlist,
|
|
&pbuf, &recvlen, &flags))
|
|
|
|
if (recvlen < 0) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"negative buffersize in recv");
|
|
return NULL;
|
|
}
|
|
|
|
if (recvlen == 0) {
|
|
/* If nbytes was not specified, use the buffer's length */
|
|
recvlen = pbuf.len;
|
|
}
|
|
|
|
/* Check if the buffer is large enough */
|
|
if (pbuf.len < recvlen) {
|
|
PyBuffer_Release(&pbuf);
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"buffer too small for requested bytes");
|
|
return NULL;
|
|
}
|
|
|
|
size_t bytesread;
|
|
auto t = create_task(s->reader->LoadAsync(recvlen));
|
|
try {
|
|
bytesread = t.get();
|
|
} catch(Exception ^e) {
|
|
String ^error = e->ToString();
|
|
PyObject *msg = PyUnicode_FromUnicode(error->Data(), error->Length());
|
|
if (!msg)
|
|
return NULL;
|
|
PyErr_SetObject(PyExc_OSError, msg);
|
|
Py_DECREF(msg);
|
|
return NULL;
|
|
}
|
|
|
|
auto buf = ref new Array<unsigned char>(bytesread);
|
|
s->reader->ReadBytes(buf);
|
|
memcpy(pbuf.buf, buf->Data, bytesread);
|
|
PyBuffer_Release(&pbuf);
|
|
return PyLong_FromSize_t(bytesread);
|
|
}
|
|
|
|
PyDoc_STRVAR(recv_into_doc,
|
|
"recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\
|
|
\n\
|
|
A version of recv() that stores its data into a buffer rather than creating \n\
|
|
a new string. Receive up to buffersize bytes from the socket. If buffersize \n\
|
|
is not specified (or 0), receive up to the size available in the given buffer.\n\
|
|
\n\
|
|
See recv() for documentation about the flags.");
|
|
|
|
|
|
/* s.recvfrom(nbytes [,flags]) method */
|
|
|
|
static PyObject *
|
|
sock_recvfrom(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "recvfrom");
|
|
return NULL;
|
|
#if 0
|
|
PyObject *buf = NULL;
|
|
PyObject *addr = NULL;
|
|
PyObject *ret = NULL;
|
|
int flags = 0;
|
|
Py_ssize_t recvlen, outlen;
|
|
|
|
if (!PyArg_ParseTuple(args, "n|i:recvfrom", &recvlen, &flags))
|
|
return NULL;
|
|
|
|
if (recvlen < 0) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"negative buffersize in recvfrom");
|
|
return NULL;
|
|
}
|
|
|
|
buf = PyBytes_FromStringAndSize((char *) 0, recvlen);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
|
|
outlen = sock_recvfrom_guts(s, PyBytes_AS_STRING(buf),
|
|
recvlen, flags, &addr);
|
|
if (outlen < 0) {
|
|
goto finally;
|
|
}
|
|
|
|
if (outlen != recvlen) {
|
|
/* We did not read as many bytes as we anticipated, resize the
|
|
string if possible and be successful. */
|
|
if (_PyBytes_Resize(&buf, outlen) < 0)
|
|
/* Oopsy, not so successful after all. */
|
|
goto finally;
|
|
}
|
|
|
|
ret = PyTuple_Pack(2, buf, addr);
|
|
|
|
finally:
|
|
Py_XDECREF(buf);
|
|
Py_XDECREF(addr);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(recvfrom_doc,
|
|
"recvfrom(buffersize[, flags]) -> (data, address info)\n\
|
|
\n\
|
|
Like recv(buffersize, flags) but also return the sender's address info.");
|
|
|
|
|
|
/* s.recvfrom_into(buffer[, nbytes [,flags]]) method */
|
|
|
|
static PyObject *
|
|
sock_recvfrom_into(PySocketSockObject *s, PyObject *args, PyObject* kwds)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "recvfrom_into");
|
|
return NULL;
|
|
#if 0
|
|
static char *kwlist[] = {"buffer", "nbytes", "flags", 0};
|
|
|
|
int flags = 0;
|
|
Py_buffer pbuf;
|
|
char *buf;
|
|
Py_ssize_t readlen, buflen, recvlen = 0;
|
|
|
|
PyObject *addr = NULL;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "w*|ni:recvfrom_into",
|
|
kwlist, &pbuf,
|
|
&recvlen, &flags))
|
|
return NULL;
|
|
buf = pbuf.buf;
|
|
buflen = pbuf.len;
|
|
assert(buf != 0 && buflen > 0);
|
|
|
|
if (recvlen < 0) {
|
|
PyBuffer_Release(&pbuf);
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"negative buffersize in recvfrom_into");
|
|
return NULL;
|
|
}
|
|
if (recvlen == 0) {
|
|
/* If nbytes was not specified, use the buffer's length */
|
|
recvlen = buflen;
|
|
}
|
|
|
|
readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr);
|
|
if (readlen < 0) {
|
|
PyBuffer_Release(&pbuf);
|
|
/* Return an error */
|
|
Py_XDECREF(addr);
|
|
return NULL;
|
|
}
|
|
|
|
PyBuffer_Release(&pbuf);
|
|
/* Return the number of bytes read and the address. Note that we do
|
|
not do anything special here in the case that readlen < recvlen. */
|
|
return Py_BuildValue("nN", readlen, addr);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(recvfrom_into_doc,
|
|
"recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\
|
|
\n\
|
|
Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.");
|
|
|
|
|
|
/* s.send(data [,flags]) method */
|
|
|
|
static PyObject *
|
|
sock_send(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
StreamSocket ^fd = (StreamSocket^)s->sock_fd;
|
|
DataWriter ^writer = s->writer;
|
|
int flags = 0, timeout = 0;
|
|
size_t n;
|
|
Py_buffer pbuf;
|
|
|
|
if (!PyArg_ParseTuple(args, "y*|i:send", &pbuf, &flags))
|
|
return NULL;
|
|
|
|
auto rtbuf = ref new Array<unsigned char, 1U>((unsigned char*)pbuf.buf, pbuf.len);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
s->writer->WriteBytes(rtbuf);
|
|
n = create_task(s->writer->StoreAsync()).get();
|
|
Py_END_ALLOW_THREADS
|
|
|
|
/*
|
|
if (timeout == 1) {
|
|
PyBuffer_Release(&pbuf);
|
|
//PyErr_SetString(socket_timeout, "timed out");
|
|
return NULL;
|
|
}
|
|
*/
|
|
|
|
PyBuffer_Release(&pbuf);
|
|
/*
|
|
if (n < 0)
|
|
return s->errorhandler();
|
|
*/
|
|
return PyLong_FromSsize_t(n);
|
|
}
|
|
|
|
PyDoc_STRVAR(send_doc,
|
|
"send(data[, flags]) -> count\n\
|
|
\n\
|
|
Send a data string to the socket. For the optional flags\n\
|
|
argument, see the Unix manual. Return the number of bytes\n\
|
|
sent; this may be less than len(data) if the network is busy.");
|
|
|
|
|
|
/* s.sendall(data [,flags]) method */
|
|
|
|
static PyObject *
|
|
sock_sendall(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
Py_ssize_t len, n = -1;
|
|
int flags = 0, timeout /* XXX implement timeout */;
|
|
Py_buffer pbuf;
|
|
if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
|
|
return NULL;
|
|
if (flags != 0) {
|
|
PyBuffer_Release(&pbuf);
|
|
PyErr_SetString(PyExc_ValueError, "non-zero flags are not supported");
|
|
return NULL;
|
|
}
|
|
len = pbuf.len;
|
|
auto rtbuf = ref new Array<unsigned char, 1U>((unsigned char*)pbuf.buf, pbuf.len);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
s->writer->WriteBytes(rtbuf);
|
|
n = create_task(s->writer->StoreAsync()).get();
|
|
Py_END_ALLOW_THREADS
|
|
PyBuffer_Release(&pbuf);
|
|
if (n != len) {
|
|
PyErr_SetString(PyExc_OSError, "Could not send all data");
|
|
return NULL;
|
|
}
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(sendall_doc,
|
|
"sendall(data[, flags])\n\
|
|
\n\
|
|
Send a data string to the socket. For the optional flags\n\
|
|
argument, see the Unix manual. This calls send() repeatedly\n\
|
|
until all data is sent. If an error occurs, it's impossible\n\
|
|
to tell how much data has been sent.");
|
|
|
|
|
|
/* s.sendto(data, [flags,] sockaddr) method */
|
|
|
|
static PyObject *
|
|
sock_sendto(PySocketSockObject *s, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "sendto");
|
|
return NULL;
|
|
#if 0
|
|
Py_buffer pbuf;
|
|
PyObject *addro;
|
|
char *buf;
|
|
Py_ssize_t len, arglen;
|
|
sock_addr_t addrbuf;
|
|
int addrlen, n = -1, flags, timeout;
|
|
|
|
flags = 0;
|
|
arglen = PyTuple_Size(args);
|
|
switch (arglen) {
|
|
case 2:
|
|
PyArg_ParseTuple(args, "y*O:sendto", &pbuf, &addro);
|
|
break;
|
|
case 3:
|
|
PyArg_ParseTuple(args, "y*iO:sendto",
|
|
&pbuf, &flags, &addro);
|
|
break;
|
|
default:
|
|
PyErr_Format(PyExc_TypeError,
|
|
"sendto() takes 2 or 3 arguments (%d given)",
|
|
arglen);
|
|
return NULL;
|
|
}
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
buf = pbuf.buf;
|
|
len = pbuf.len;
|
|
|
|
if (!IS_SELECTABLE(s)) {
|
|
PyBuffer_Release(&pbuf);
|
|
return select_error();
|
|
}
|
|
|
|
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) {
|
|
PyBuffer_Release(&pbuf);
|
|
return NULL;
|
|
}
|
|
|
|
BEGIN_SELECT_LOOP(s)
|
|
Py_BEGIN_ALLOW_THREADS
|
|
timeout = internal_select_ex(s, 1, interval);
|
|
if (!timeout)
|
|
n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
if (timeout == 1) {
|
|
PyBuffer_Release(&pbuf);
|
|
PyErr_SetString(socket_timeout, "timed out");
|
|
return NULL;
|
|
}
|
|
END_SELECT_LOOP(s)
|
|
PyBuffer_Release(&pbuf);
|
|
if (n < 0)
|
|
return s->errorhandler();
|
|
return PyLong_FromSsize_t(n);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(sendto_doc,
|
|
"sendto(data[, flags], address) -> count\n\
|
|
\n\
|
|
Like send(data, flags) but allows specifying the destination address.\n\
|
|
For IP sockets, the address is a pair (hostaddr, port).");
|
|
|
|
|
|
/* s.shutdown(how) method */
|
|
|
|
static PyObject *
|
|
sock_shutdown(PySocketSockObject *s, PyObject *arg)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "shutdown");
|
|
return NULL;
|
|
#if 0
|
|
int how;
|
|
int res;
|
|
|
|
how = PyLong_AsLong(arg);
|
|
if (how == -1 && PyErr_Occurred())
|
|
return NULL;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
res = shutdown(s->sock_fd, how);
|
|
Py_END_ALLOW_THREADS
|
|
if (res < 0)
|
|
return s->errorhandler();
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(shutdown_doc,
|
|
"shutdown(flag)\n\
|
|
\n\
|
|
Shut down the reading side of the socket (flag == SHUT_RD), the writing side\n\
|
|
of the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR).");
|
|
|
|
/* List of methods for socket objects */
|
|
|
|
static PyMethodDef sock_methods[] = {
|
|
{"_accept", (PyCFunction)sock_accept, METH_NOARGS,
|
|
accept_doc},
|
|
{"bind", (PyCFunction)sock_bind, METH_O,
|
|
bind_doc},
|
|
{"close", (PyCFunction)sock_close, METH_NOARGS,
|
|
close_doc},
|
|
{"connect", (PyCFunction)sock_connect, METH_O,
|
|
connect_doc},
|
|
{"connect_ex", (PyCFunction)sock_connect_ex, METH_O,
|
|
connect_ex_doc},
|
|
{"detach", (PyCFunction)sock_detach, METH_NOARGS,
|
|
detach_doc},
|
|
{"fileno", (PyCFunction)sock_fileno, METH_NOARGS,
|
|
fileno_doc},
|
|
#ifdef HAVE_GETPEERNAME
|
|
{"getpeername", (PyCFunction)sock_getpeername,
|
|
METH_NOARGS, getpeername_doc},
|
|
#endif
|
|
{"getsockname", (PyCFunction)sock_getsockname,
|
|
METH_NOARGS, getsockname_doc},
|
|
#if 0
|
|
{"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS,
|
|
getsockopt_doc},
|
|
#endif
|
|
{"listen", (PyCFunction)sock_listen, METH_O,
|
|
listen_doc},
|
|
{"recv", (PyCFunction)sock_recv, METH_VARARGS,
|
|
recv_doc},
|
|
{"recv_into", (PyCFunction)sock_recv_into, METH_VARARGS | METH_KEYWORDS,
|
|
recv_into_doc},
|
|
{"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS,
|
|
recvfrom_doc},
|
|
{"recvfrom_into", (PyCFunction)sock_recvfrom_into, METH_VARARGS | METH_KEYWORDS,
|
|
recvfrom_into_doc},
|
|
{"send", (PyCFunction)sock_send, METH_VARARGS,
|
|
send_doc},
|
|
{"sendall", (PyCFunction)sock_sendall, METH_VARARGS,
|
|
sendall_doc},
|
|
{"sendto", (PyCFunction)sock_sendto, METH_VARARGS,
|
|
sendto_doc},
|
|
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
|
|
setblocking_doc},
|
|
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
|
|
settimeout_doc},
|
|
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
|
|
gettimeout_doc},
|
|
{"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS,
|
|
setsockopt_doc},
|
|
{"shutdown", (PyCFunction)sock_shutdown, METH_O,
|
|
shutdown_doc},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
/* SockObject members */
|
|
static PyMemberDef sock_memberlist[] = {
|
|
{"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"},
|
|
{"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"},
|
|
{"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"},
|
|
{"timeout", T_DOUBLE, offsetof(PySocketSockObject, sock_timeout), READONLY, "the socket timeout"},
|
|
{0},
|
|
};
|
|
|
|
/* Deallocate a socket object in response to the last Py_DECREF().
|
|
First close the file description. */
|
|
|
|
static void
|
|
sock_dealloc(PySocketSockObject *s)
|
|
{
|
|
if (s->sock_fd != nullptr) {
|
|
PyObject *exc, *val, *tb;
|
|
Py_ssize_t old_refcount = Py_REFCNT(s);
|
|
++Py_REFCNT(s);
|
|
PyErr_Fetch(&exc, &val, &tb);
|
|
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
|
|
"unclosed %R", s))
|
|
/* Spurious errors can appear at shutdown */
|
|
if (PyErr_ExceptionMatches(PyExc_Warning))
|
|
PyErr_WriteUnraisable((PyObject *) s);
|
|
PyErr_Restore(exc, val, tb);
|
|
// XXX compiler rejects the call to dispose
|
|
//((Platform::IDisposable^)s->sock_fd)->Dispose();
|
|
s->sock_fd = nullptr;
|
|
Py_REFCNT(s) = old_refcount;
|
|
}
|
|
Py_TYPE(s)->tp_free((PyObject *)s);
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
sock_repr(PySocketSockObject *s)
|
|
{
|
|
return PyUnicode_FromFormat(
|
|
"<socket object, fd=%ld, family=%d, type=%d, proto=%d>",
|
|
/* XXX sockfd */
|
|
(long)-1, s->sock_family,
|
|
s->sock_type,
|
|
s->sock_proto);
|
|
}
|
|
|
|
|
|
/* Create a new, uninitialized socket object. */
|
|
|
|
static PyObject *
|
|
sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *snew;
|
|
|
|
snew = type->tp_alloc(type, 0);
|
|
if (snew != NULL) {
|
|
((PySocketSockObject *)snew)->sock_fd = nullptr;
|
|
((PySocketSockObject *)snew)->sock_timeout = -1.0;
|
|
((PySocketSockObject *)snew)->errorhandler = &set_error;
|
|
}
|
|
return snew;
|
|
}
|
|
|
|
|
|
/* Initialize a new socket object. */
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
PySocketSockObject *s = (PySocketSockObject *)self;
|
|
PyObject *fdobj = NULL;
|
|
Platform::Object^ fd = nullptr;
|
|
int family = AF_INET;
|
|
int type = SOCK_STREAM;
|
|
int proto = 0;
|
|
static char *keywords[] = {"family", "type", "proto", "fileno", 0};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
"|iiiO:socket", keywords,
|
|
&family, &type, &proto, &fdobj))
|
|
return -1;
|
|
|
|
if (fdobj != NULL && fdobj != Py_None) {
|
|
PyErr_SetString(PyExc_NotImplementedError, "socket creation from existing handle");
|
|
return -1;
|
|
}
|
|
else {
|
|
if (family != AF_INET) {
|
|
PyErr_SetString(PyExc_NotImplementedError, "unknown socket family");
|
|
return -1;
|
|
}
|
|
switch(type) {
|
|
case SOCK_STREAM:
|
|
fd = ref new StreamSocket();
|
|
break;
|
|
case SOCK_DGRAM:
|
|
fd = ref new DatagramSocket();
|
|
break;
|
|
default:
|
|
PyErr_SetString(PyExc_NotImplementedError, "unknown socket type");
|
|
return -1;
|
|
}
|
|
}
|
|
init_sockobject(s, fd, family, type, proto);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* Type object for socket objects. */
|
|
namespace {
|
|
PyTypeObject sock_type = {
|
|
PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */
|
|
"_socket.socket", /* tp_name */
|
|
sizeof(PySocketSockObject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)sock_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_reserved */
|
|
(reprfunc)sock_repr, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
sock_doc, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
sock_methods, /* tp_methods */
|
|
sock_memberlist, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
sock_initobj, /* tp_init */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
sock_new, /* tp_new */
|
|
PyObject_Del, /* tp_free */
|
|
};
|
|
}
|
|
|
|
|
|
/* Python interface to gethostname(). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_gethostname(PyObject *self, PyObject *unused)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "gethostname");
|
|
return NULL;
|
|
#if 0
|
|
/* Don't use winsock's gethostname, as this returns the ANSI
|
|
version of the hostname, whereas we need a Unicode string.
|
|
Otherwise, gethostname apparently also returns the DNS name. */
|
|
wchar_t buf[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD size = Py_ARRAY_LENGTH(buf);
|
|
wchar_t *name;
|
|
PyObject *result;
|
|
|
|
if (GetComputerNameExW(ComputerNamePhysicalDnsHostname, buf, &size))
|
|
return PyUnicode_FromWideChar(buf, size);
|
|
|
|
if (GetLastError() != ERROR_MORE_DATA)
|
|
return PyErr_SetFromWindowsErr(0);
|
|
|
|
if (size == 0)
|
|
return PyUnicode_New(0, 0);
|
|
|
|
/* MSDN says ERROR_MORE_DATA may occur because DNS allows longer
|
|
names */
|
|
name = PyMem_Malloc(size * sizeof(wchar_t));
|
|
if (!name)
|
|
return NULL;
|
|
if (!GetComputerNameExW(ComputerNamePhysicalDnsHostname,
|
|
name,
|
|
&size))
|
|
{
|
|
PyMem_Free(name);
|
|
return PyErr_SetFromWindowsErr(0);
|
|
}
|
|
|
|
result = PyUnicode_FromWideChar(name, size);
|
|
PyMem_Free(name);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(gethostname_doc,
|
|
"gethostname() -> string\n\
|
|
\n\
|
|
Return the current host name.");
|
|
|
|
/* Python interface to gethostbyname(name). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_gethostbyname(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "gethostbyname");
|
|
return NULL;
|
|
#if 0
|
|
char *name;
|
|
sock_addr_t addrbuf;
|
|
PyObject *ret = NULL;
|
|
|
|
if (!PyArg_ParseTuple(args, "et:gethostbyname", "idna", &name))
|
|
return NULL;
|
|
if (setipaddr(name, SAS2SA(&addrbuf), sizeof(addrbuf), AF_INET) < 0)
|
|
goto finally;
|
|
ret = makeipaddr(SAS2SA(&addrbuf), sizeof(struct sockaddr_in));
|
|
finally:
|
|
PyMem_Free(name);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(gethostbyname_doc,
|
|
"gethostbyname(host) -> address\n\
|
|
\n\
|
|
Return the IP address (a string of the form '255.255.255.255') for a host.");
|
|
|
|
|
|
/* Python interface to gethostbyname_ex(name). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_gethostbyname_ex(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "gethostbyname_ex");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(ghbn_ex_doc,
|
|
"gethostbyname_ex(host) -> (name, aliaslist, addresslist)\n\
|
|
\n\
|
|
Return the true host name, a list of aliases, and a list of IP addresses,\n\
|
|
for a host. The host argument is a string giving a host name or IP number.");
|
|
|
|
|
|
/* Python interface to gethostbyaddr(IP). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_gethostbyaddr(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "gethostbyaddr");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(gethostbyaddr_doc,
|
|
"gethostbyaddr(host) -> (name, aliaslist, addresslist)\n\
|
|
\n\
|
|
Return the true host name, a list of aliases, and a list of IP addresses,\n\
|
|
for a host. The host argument is a string giving a host name or IP number.");
|
|
|
|
|
|
/* Python interface to getservbyname(name).
|
|
This only returns the port number, since the other info is already
|
|
known or not useful (like the list of aliases). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_getservbyname(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getservbyname");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(getservbyname_doc,
|
|
"getservbyname(servicename[, protocolname]) -> integer\n\
|
|
\n\
|
|
Return a port number from a service name and protocol name.\n\
|
|
The optional protocol name, if given, should be 'tcp' or 'udp',\n\
|
|
otherwise any protocol will match.");
|
|
|
|
|
|
/* Python interface to getservbyport(port).
|
|
This only returns the service name, since the other info is already
|
|
known or not useful (like the list of aliases). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_getservbyport(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getservbyport");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(getservbyport_doc,
|
|
"getservbyport(port[, protocolname]) -> string\n\
|
|
\n\
|
|
Return the service name from a port number and protocol name.\n\
|
|
The optional protocol name, if given, should be 'tcp' or 'udp',\n\
|
|
otherwise any protocol will match.");
|
|
|
|
/* Python interface to getprotobyname(name).
|
|
This only returns the protocol number, since the other info is
|
|
already known or not useful (like the list of aliases). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_getprotobyname(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getprotobyname");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(getprotobyname_doc,
|
|
"getprotobyname(name) -> integer\n\
|
|
\n\
|
|
Return the protocol number for the named protocol. (Rarely used.)");
|
|
|
|
|
|
/* dup() function for socket fds */
|
|
|
|
static PyObject *
|
|
socket_dup(PyObject *self, PyObject *fdobj)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "dup");
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(dup_doc,
|
|
"dup(integer) -> integer\n\
|
|
\n\
|
|
Duplicate an integer socket file descriptor. This is like os.dup(), but for\n\
|
|
sockets; on some platforms os.dup() won't work for socket file descriptors.");
|
|
|
|
|
|
static PyObject *
|
|
socket_ntohs(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "ntohs");
|
|
return NULL;
|
|
#if 0
|
|
int x1, x2;
|
|
|
|
if (!PyArg_ParseTuple(args, "i:ntohs", &x1)) {
|
|
return NULL;
|
|
}
|
|
if (x1 < 0) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"can't convert negative number to unsigned long");
|
|
return NULL;
|
|
}
|
|
x2 = (unsigned int)ntohs((unsigned short)x1);
|
|
return PyLong_FromLong(x2);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(ntohs_doc,
|
|
"ntohs(integer) -> integer\n\
|
|
\n\
|
|
Convert a 16-bit integer from network to host byte order.");
|
|
|
|
|
|
static PyObject *
|
|
socket_ntohl(PyObject *self, PyObject *arg)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "ntohl");
|
|
return NULL;
|
|
#if 0
|
|
unsigned long x;
|
|
|
|
if (PyLong_Check(arg)) {
|
|
x = PyLong_AsUnsignedLong(arg);
|
|
if (x == (unsigned long) -1 && PyErr_Occurred())
|
|
return NULL;
|
|
#if SIZEOF_LONG > 4
|
|
{
|
|
unsigned long y;
|
|
/* only want the trailing 32 bits */
|
|
y = x & 0xFFFFFFFFUL;
|
|
if (y ^ x)
|
|
return PyErr_Format(PyExc_OverflowError,
|
|
"long int larger than 32 bits");
|
|
x = y;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
return PyErr_Format(PyExc_TypeError,
|
|
"expected int/long, %s found",
|
|
Py_TYPE(arg)->tp_name);
|
|
if (x == (unsigned long) -1 && PyErr_Occurred())
|
|
return NULL;
|
|
return PyLong_FromUnsignedLong(ntohl(x));
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(ntohl_doc,
|
|
"ntohl(integer) -> integer\n\
|
|
\n\
|
|
Convert a 32-bit integer from network to host byte order.");
|
|
|
|
|
|
static PyObject *
|
|
socket_htons(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "htons");
|
|
return NULL;
|
|
#if 0
|
|
int x1, x2;
|
|
|
|
if (!PyArg_ParseTuple(args, "i:htons", &x1)) {
|
|
return NULL;
|
|
}
|
|
if (x1 < 0) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"can't convert negative number to unsigned long");
|
|
return NULL;
|
|
}
|
|
x2 = (unsigned int)htons((unsigned short)x1);
|
|
return PyLong_FromLong(x2);
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(htons_doc,
|
|
"htons(integer) -> integer\n\
|
|
\n\
|
|
Convert a 16-bit integer from host to network byte order.");
|
|
|
|
|
|
static PyObject *
|
|
socket_htonl(PyObject *self, PyObject *arg)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "ntohl");
|
|
return NULL;
|
|
#if 0
|
|
unsigned long x;
|
|
|
|
if (PyLong_Check(arg)) {
|
|
x = PyLong_AsUnsignedLong(arg);
|
|
if (x == (unsigned long) -1 && PyErr_Occurred())
|
|
return NULL;
|
|
#if SIZEOF_LONG > 4
|
|
{
|
|
unsigned long y;
|
|
/* only want the trailing 32 bits */
|
|
y = x & 0xFFFFFFFFUL;
|
|
if (y ^ x)
|
|
return PyErr_Format(PyExc_OverflowError,
|
|
"long int larger than 32 bits");
|
|
x = y;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
return PyErr_Format(PyExc_TypeError,
|
|
"expected int/long, %s found",
|
|
Py_TYPE(arg)->tp_name);
|
|
return PyLong_FromUnsignedLong(htonl((unsigned long)x));
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(htonl_doc,
|
|
"htonl(integer) -> integer\n\
|
|
\n\
|
|
Convert a 32-bit integer from host to network byte order.");
|
|
|
|
/* socket.inet_aton() and socket.inet_ntoa() functions. */
|
|
|
|
PyDoc_STRVAR(inet_aton_doc,
|
|
"inet_aton(string) -> bytes giving packed 32-bit IP representation\n\
|
|
\n\
|
|
Convert an IP address in string format (123.45.67.89) to the 32-bit packed\n\
|
|
binary format used in low-level network functions.");
|
|
|
|
static PyObject*
|
|
socket_inet_aton(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "inet_aton");
|
|
return NULL;
|
|
#if 0
|
|
|
|
#ifndef INADDR_NONE
|
|
#define INADDR_NONE (-1)
|
|
#endif
|
|
#ifdef HAVE_INET_ATON
|
|
struct in_addr buf;
|
|
#endif
|
|
|
|
#if !defined(HAVE_INET_ATON) || defined(USE_INET_ATON_WEAKLINK)
|
|
#if (SIZEOF_INT != 4)
|
|
#error "Not sure if in_addr_t exists and int is not 32-bits."
|
|
#endif
|
|
/* Have to use inet_addr() instead */
|
|
unsigned int packed_addr;
|
|
#endif
|
|
char *ip_addr;
|
|
|
|
if (!PyArg_ParseTuple(args, "s:inet_aton", &ip_addr))
|
|
return NULL;
|
|
|
|
|
|
#ifdef HAVE_INET_ATON
|
|
|
|
#ifdef USE_INET_ATON_WEAKLINK
|
|
if (inet_aton != NULL) {
|
|
#endif
|
|
if (inet_aton(ip_addr, &buf))
|
|
return PyBytes_FromStringAndSize((char *)(&buf),
|
|
sizeof(buf));
|
|
|
|
PyErr_SetString(PyExc_OSError,
|
|
"illegal IP address string passed to inet_aton");
|
|
return NULL;
|
|
|
|
#ifdef USE_INET_ATON_WEAKLINK
|
|
} else {
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if !defined(HAVE_INET_ATON) || defined(USE_INET_ATON_WEAKLINK)
|
|
|
|
/* special-case this address as inet_addr might return INADDR_NONE
|
|
* for this */
|
|
if (strcmp(ip_addr, "255.255.255.255") == 0) {
|
|
packed_addr = 0xFFFFFFFF;
|
|
} else {
|
|
|
|
packed_addr = inet_addr(ip_addr);
|
|
|
|
if (packed_addr == INADDR_NONE) { /* invalid address */
|
|
PyErr_SetString(PyExc_OSError,
|
|
"illegal IP address string passed to inet_aton");
|
|
return NULL;
|
|
}
|
|
}
|
|
return PyBytes_FromStringAndSize((char *) &packed_addr,
|
|
sizeof(packed_addr));
|
|
|
|
#ifdef USE_INET_ATON_WEAKLINK
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(inet_ntoa_doc,
|
|
"inet_ntoa(packed_ip) -> ip_address_string\n\
|
|
\n\
|
|
Convert an IP address from 32-bit packed binary format to string format");
|
|
|
|
static PyObject*
|
|
socket_inet_ntoa(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "inet_ntoa");
|
|
return NULL;
|
|
#if 0
|
|
|
|
char *packed_str;
|
|
int addr_len;
|
|
struct in_addr packed_addr;
|
|
|
|
if (!PyArg_ParseTuple(args, "y#:inet_ntoa", &packed_str, &addr_len)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (addr_len != sizeof(packed_addr)) {
|
|
PyErr_SetString(PyExc_OSError,
|
|
"packed IP wrong length for inet_ntoa");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&packed_addr, packed_str, addr_len);
|
|
|
|
return PyUnicode_FromString(inet_ntoa(packed_addr));
|
|
#endif
|
|
}
|
|
|
|
/* Python interface to getaddrinfo(host, port). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getaddrinfo");
|
|
return NULL;
|
|
#if 0
|
|
|
|
static char* kwnames[] = {"host", "port", "family", "type", "proto",
|
|
"flags", 0};
|
|
struct addrinfo hints, *res;
|
|
struct addrinfo *res0 = NULL;
|
|
PyObject *hobj = NULL;
|
|
PyObject *pobj = (PyObject *)NULL;
|
|
char pbuf[30];
|
|
char *hptr, *pptr;
|
|
int family, socktype, protocol, flags;
|
|
int error;
|
|
PyObject *all = (PyObject *)NULL;
|
|
PyObject *idna = NULL;
|
|
|
|
family = socktype = protocol = flags = 0;
|
|
family = AF_UNSPEC;
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iiii:getaddrinfo",
|
|
kwnames, &hobj, &pobj, &family, &socktype,
|
|
&protocol, &flags)) {
|
|
return NULL;
|
|
}
|
|
if (hobj == Py_None) {
|
|
hptr = NULL;
|
|
} else if (PyUnicode_Check(hobj)) {
|
|
_Py_IDENTIFIER(encode);
|
|
|
|
idna = _PyObject_CallMethodId(hobj, &PyId_encode, "s", "idna");
|
|
if (!idna)
|
|
return NULL;
|
|
assert(PyBytes_Check(idna));
|
|
hptr = PyBytes_AS_STRING(idna);
|
|
} else if (PyBytes_Check(hobj)) {
|
|
hptr = PyBytes_AsString(hobj);
|
|
} else {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"getaddrinfo() argument 1 must be string or None");
|
|
return NULL;
|
|
}
|
|
if (PyLong_CheckExact(pobj)) {
|
|
long value = PyLong_AsLong(pobj);
|
|
if (value == -1 && PyErr_Occurred())
|
|
goto err;
|
|
PyOS_snprintf(pbuf, sizeof(pbuf), "%ld", value);
|
|
pptr = pbuf;
|
|
} else if (PyUnicode_Check(pobj)) {
|
|
pptr = _PyUnicode_AsString(pobj);
|
|
if (pptr == NULL)
|
|
goto err;
|
|
} else if (PyBytes_Check(pobj)) {
|
|
pptr = PyBytes_AS_STRING(pobj);
|
|
} else if (pobj == Py_None) {
|
|
pptr = (char *)NULL;
|
|
} else {
|
|
PyErr_SetString(PyExc_OSError, "Int or String expected");
|
|
goto err;
|
|
}
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = family;
|
|
hints.ai_socktype = socktype;
|
|
hints.ai_protocol = protocol;
|
|
hints.ai_flags = flags;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
ACQUIRE_GETADDRINFO_LOCK
|
|
error = getaddrinfo(hptr, pptr, &hints, &res0);
|
|
Py_END_ALLOW_THREADS
|
|
RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
|
|
if (error) {
|
|
set_gaierror(error);
|
|
goto err;
|
|
}
|
|
|
|
if ((all = PyList_New(0)) == NULL)
|
|
goto err;
|
|
for (res = res0; res; res = res->ai_next) {
|
|
PyObject *single;
|
|
PyObject *addr =
|
|
makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol);
|
|
if (addr == NULL)
|
|
goto err;
|
|
single = Py_BuildValue("iiisO", res->ai_family,
|
|
res->ai_socktype, res->ai_protocol,
|
|
res->ai_canonname ? res->ai_canonname : "",
|
|
addr);
|
|
Py_DECREF(addr);
|
|
if (single == NULL)
|
|
goto err;
|
|
|
|
if (PyList_Append(all, single))
|
|
goto err;
|
|
Py_XDECREF(single);
|
|
}
|
|
Py_XDECREF(idna);
|
|
if (res0)
|
|
freeaddrinfo(res0);
|
|
return all;
|
|
err:
|
|
Py_XDECREF(all);
|
|
Py_XDECREF(idna);
|
|
if (res0)
|
|
freeaddrinfo(res0);
|
|
return (PyObject *)NULL;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(getaddrinfo_doc,
|
|
"getaddrinfo(host, port [, family, socktype, proto, flags])\n\
|
|
-> list of (family, socktype, proto, canonname, sockaddr)\n\
|
|
\n\
|
|
Resolve host and port into addrinfo struct.");
|
|
|
|
/* Python interface to getnameinfo(sa, flags). */
|
|
|
|
/*ARGSUSED*/
|
|
static PyObject *
|
|
socket_getnameinfo(PyObject *self, PyObject *args)
|
|
{
|
|
PyErr_SetString(PyExc_NotImplementedError, "getnameinfo");
|
|
return NULL;
|
|
#if 0
|
|
PyObject *sa = (PyObject *)NULL;
|
|
int flags;
|
|
char *hostp;
|
|
int port;
|
|
unsigned int flowinfo, scope_id;
|
|
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
|
|
struct addrinfo hints, *res = NULL;
|
|
int error;
|
|
PyObject *ret = (PyObject *)NULL;
|
|
|
|
flags = flowinfo = scope_id = 0;
|
|
if (!PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags))
|
|
return NULL;
|
|
if (!PyTuple_Check(sa)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"getnameinfo() argument 1 must be a tuple");
|
|
return NULL;
|
|
}
|
|
if (!PyArg_ParseTuple(sa, "si|II",
|
|
&hostp, &port, &flowinfo, &scope_id))
|
|
return NULL;
|
|
if (flowinfo > 0xfffff) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"getsockaddrarg: flowinfo must be 0-1048575.");
|
|
return NULL;
|
|
}
|
|
PyOS_snprintf(pbuf, sizeof(pbuf), "%d", port);
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_UNSPEC;
|
|
hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */
|
|
hints.ai_flags = AI_NUMERICHOST; /* don't do any name resolution */
|
|
Py_BEGIN_ALLOW_THREADS
|
|
ACQUIRE_GETADDRINFO_LOCK
|
|
error = getaddrinfo(hostp, pbuf, &hints, &res);
|
|
Py_END_ALLOW_THREADS
|
|
RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
|
|
if (error) {
|
|
set_gaierror(error);
|
|
goto fail;
|
|
}
|
|
if (res->ai_next) {
|
|
PyErr_SetString(PyExc_OSError,
|
|
"sockaddr resolved to multiple addresses");
|
|
goto fail;
|
|
}
|
|
switch (res->ai_family) {
|
|
case AF_INET:
|
|
{
|
|
if (PyTuple_GET_SIZE(sa) != 2) {
|
|
PyErr_SetString(PyExc_OSError,
|
|
"IPv4 sockaddr must be 2 tuple");
|
|
goto fail;
|
|
}
|
|
break;
|
|
}
|
|
#ifdef ENABLE_IPV6
|
|
case AF_INET6:
|
|
{
|
|
struct sockaddr_in6 *sin6;
|
|
sin6 = (struct sockaddr_in6 *)res->ai_addr;
|
|
sin6->sin6_flowinfo = htonl(flowinfo);
|
|
sin6->sin6_scope_id = scope_id;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen,
|
|
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
|
|
if (error) {
|
|
set_gaierror(error);
|
|
goto fail;
|
|
}
|
|
ret = Py_BuildValue("ss", hbuf, pbuf);
|
|
|
|
fail:
|
|
if (res)
|
|
freeaddrinfo(res);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
PyDoc_STRVAR(getnameinfo_doc,
|
|
"getnameinfo(sockaddr, flags) --> (host, port)\n\
|
|
\n\
|
|
Get host and port for a sockaddr.");
|
|
|
|
|
|
/* Python API to getting and setting the default timeout value. */
|
|
|
|
static PyObject *
|
|
socket_getdefaulttimeout(PyObject *self)
|
|
{
|
|
if (defaulttimeout < 0.0) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
else
|
|
return PyFloat_FromDouble(defaulttimeout);
|
|
}
|
|
|
|
PyDoc_STRVAR(getdefaulttimeout_doc,
|
|
"getdefaulttimeout() -> timeout\n\
|
|
\n\
|
|
Returns the default timeout in seconds (float) for new socket objects.\n\
|
|
A value of None indicates that new socket objects have no timeout.\n\
|
|
When the socket module is first imported, the default is None.");
|
|
|
|
static PyObject *
|
|
socket_setdefaulttimeout(PyObject *self, PyObject *arg)
|
|
{
|
|
double timeout;
|
|
|
|
if (arg == Py_None)
|
|
timeout = -1.0;
|
|
else {
|
|
timeout = PyFloat_AsDouble(arg);
|
|
if (timeout < 0.0) {
|
|
if (!PyErr_Occurred())
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Timeout value out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
defaulttimeout = timeout;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyDoc_STRVAR(setdefaulttimeout_doc,
|
|
"setdefaulttimeout(timeout)\n\
|
|
\n\
|
|
Set the default timeout in seconds (float) for new socket objects.\n\
|
|
A value of None indicates that new socket objects have no timeout.\n\
|
|
When the socket module is first imported, the default is None.");
|
|
|
|
/* List of functions exported by this module. */
|
|
|
|
static PyMethodDef socket_methods[] = {
|
|
{"gethostbyname", socket_gethostbyname,
|
|
METH_VARARGS, gethostbyname_doc},
|
|
{"gethostbyname_ex", socket_gethostbyname_ex,
|
|
METH_VARARGS, ghbn_ex_doc},
|
|
{"gethostbyaddr", socket_gethostbyaddr,
|
|
METH_VARARGS, gethostbyaddr_doc},
|
|
{"gethostname", socket_gethostname,
|
|
METH_NOARGS, gethostname_doc},
|
|
{"getservbyname", socket_getservbyname,
|
|
METH_VARARGS, getservbyname_doc},
|
|
{"getservbyport", socket_getservbyport,
|
|
METH_VARARGS, getservbyport_doc},
|
|
{"getprotobyname", socket_getprotobyname,
|
|
METH_VARARGS, getprotobyname_doc},
|
|
{"dup", socket_dup,
|
|
METH_O, dup_doc},
|
|
{"ntohs", socket_ntohs,
|
|
METH_VARARGS, ntohs_doc},
|
|
{"ntohl", socket_ntohl,
|
|
METH_O, ntohl_doc},
|
|
{"htons", socket_htons,
|
|
METH_VARARGS, htons_doc},
|
|
{"htonl", socket_htonl,
|
|
METH_O, htonl_doc},
|
|
{"inet_aton", socket_inet_aton,
|
|
METH_VARARGS, inet_aton_doc},
|
|
{"inet_ntoa", socket_inet_ntoa,
|
|
METH_VARARGS, inet_ntoa_doc},
|
|
{"getaddrinfo", (PyCFunction)socket_getaddrinfo,
|
|
METH_VARARGS | METH_KEYWORDS, getaddrinfo_doc},
|
|
{"getnameinfo", socket_getnameinfo,
|
|
METH_VARARGS, getnameinfo_doc},
|
|
{"getdefaulttimeout", (PyCFunction)socket_getdefaulttimeout,
|
|
METH_NOARGS, getdefaulttimeout_doc},
|
|
{"setdefaulttimeout", socket_setdefaulttimeout,
|
|
METH_O, setdefaulttimeout_doc},
|
|
{NULL, NULL} /* Sentinel */
|
|
};
|
|
|
|
|
|
/* Initialize the _socket module.
|
|
|
|
This module is actually called "_socket", and there's a wrapper
|
|
"socket.py" which implements some additional functionality.
|
|
The import of "_socket" may fail with an ImportError exception if
|
|
os-specific initialization fails. On Windows, this does WINSOCK
|
|
initialization. When WINSOCK is initialized successfully, a call to
|
|
WSACleanup() is scheduled to be made at exit time.
|
|
*/
|
|
|
|
PyDoc_STRVAR(socket_doc,
|
|
"Implementation module for socket operations.\n\
|
|
\n\
|
|
See the socket module for documentation.");
|
|
|
|
static struct PyModuleDef socketmodule = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"_socket",
|
|
socket_doc,
|
|
-1,
|
|
socket_methods,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
extern "C"
|
|
PyMODINIT_FUNC
|
|
PyInit__socket(void)
|
|
{
|
|
PyObject *m, *has_ipv6;
|
|
|
|
Py_TYPE(&sock_type) = &PyType_Type;
|
|
m = PyModule_Create(&socketmodule);
|
|
if (m == NULL)
|
|
return NULL;
|
|
|
|
Py_INCREF(PyExc_OSError);
|
|
PyModule_AddObject(m, "error", PyExc_OSError);
|
|
socket_herror = PyErr_NewException("socket.herror",
|
|
PyExc_OSError, NULL);
|
|
if (socket_herror == NULL)
|
|
return NULL;
|
|
Py_INCREF(socket_herror);
|
|
PyModule_AddObject(m, "herror", socket_herror);
|
|
socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError,
|
|
NULL);
|
|
if (socket_gaierror == NULL)
|
|
return NULL;
|
|
Py_INCREF(socket_gaierror);
|
|
PyModule_AddObject(m, "gaierror", socket_gaierror);
|
|
socket_timeout = PyErr_NewException("socket.timeout",
|
|
PyExc_OSError, NULL);
|
|
if (socket_timeout == NULL)
|
|
return NULL;
|
|
Py_INCREF(socket_timeout);
|
|
PyModule_AddObject(m, "timeout", socket_timeout);
|
|
Py_INCREF((PyObject *)&sock_type);
|
|
if (PyModule_AddObject(m, "SocketType",
|
|
(PyObject *)&sock_type) != 0)
|
|
return NULL;
|
|
Py_INCREF((PyObject *)&sock_type);
|
|
if (PyModule_AddObject(m, "socket",
|
|
(PyObject *)&sock_type) != 0)
|
|
return NULL;
|
|
|
|
has_ipv6 = Py_True;
|
|
Py_INCREF(has_ipv6);
|
|
PyModule_AddObject(m, "has_ipv6", has_ipv6);
|
|
|
|
/* Address families (we only support AF_INET and AF_UNIX) */
|
|
PyModule_AddIntConstant(m, "AF_INET", AF_INET);
|
|
PyModule_AddIntConstant(m, "AF_INET6", AF_INET6);
|
|
/* Socket types */
|
|
PyModule_AddIntConstant(m, "SOCK_STREAM", SOCK_STREAM);
|
|
PyModule_AddIntConstant(m, "SOCK_DGRAM", SOCK_DGRAM);
|
|
/* Some reserved IP v.4 addresses */
|
|
PyModule_AddIntConstant(m, "INADDR_ANY", 0x00000000);
|
|
PyModule_AddIntConstant(m, "INADDR_BROADCAST", 0xffffffff);
|
|
PyModule_AddIntConstant(m, "INADDR_LOOPBACK", 0x7F000001);
|
|
PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", 0xe0000000);
|
|
PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", 0xe0000001);
|
|
PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", 0xe00000ff);
|
|
PyModule_AddIntConstant(m, "INADDR_NONE", 0xffffffff);
|
|
/* shutdown() parameters */
|
|
PyModule_AddIntConstant(m, "SHUT_RD", 0);
|
|
PyModule_AddIntConstant(m, "SHUT_WR", 1);
|
|
PyModule_AddIntConstant(m, "SHUT_RDWR", 2);
|
|
return m;
|
|
}
|