qmsk/net/socket/socket.pyx
author Tero Marttila <terom@fixme.fi>
Sun, 16 Aug 2009 19:01:21 +0300
changeset 7 74fde84264b1
parent 6 qmsk.net/socket/sock.pyx@10bd48c9b6ce
child 8 b3880dafbab1
permissions -rw-r--r--
broke Cython with this package magic
7
74fde84264b1 broke Cython with this package magic
Tero Marttila <terom@fixme.fi>
parents: 6
diff changeset
     1
from qmsk.net.socket.socket cimport *
74fde84264b1 broke Cython with this package magic
Tero Marttila <terom@fixme.fi>
parents: 6
diff changeset
     2
from qmsk.net.socket.addr cimport sockaddr, build_sockaddr
6
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     3
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     4
cimport libc, py
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     5
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     6
from py cimport raise_errno
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     7
7
74fde84264b1 broke Cython with this package magic
Tero Marttila <terom@fixme.fi>
parents: 6
diff changeset
     8
6
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     9
# XXX: do some GIL-releasin'
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    10
cdef class sock :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    11
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    12
    def __init__ (self, int fd = -1) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    13
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    14
            Construct this socket with the given fd, or -1 to mark it as fd-less
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    15
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    16
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    17
        self.fd = fd
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    18
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    19
    def socket (self, int family = libc.AF_INET, int socktype = libc.SOCK_STREAM, int protocol = 0) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    20
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    21
            Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    22
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    23
                family      - one of AF_*
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    24
                socktype    - one of SOCK_*
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    25
                protocol    - one of IPPROTO_* or zero to select default
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    26
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    27
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    28
        if self.fd >= 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    29
            raise Exception("Socket fd already exists")
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    30
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    31
        # socket()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    32
        self.fd = libc.socket(family, socktype, protocol)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    33
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    34
        # trap
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    35
        if self.fd < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    36
            raise_errno('socket')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    37
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    38
    def bind (self, sockaddr addr) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    39
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    40
            Bind this socket to the given local socket address. The given sockaddr should be of the same or a
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    41
            compatible address family.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    42
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    43
                addr        - the local address to bind to. The port may be zero to let the system choose an unused
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    44
                              ephemeral port.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    45
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    46
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    47
        cdef libc.sockaddr *sa_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    48
        cdef libc.socklen_t sa_len
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    49
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    50
        # get the address
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    51
        addr._get_sockaddr(&sa_ptr, &sa_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    52
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    53
        # bind()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    54
        if libc.bind(self.fd, sa_ptr, sa_len) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    55
            raise_errno('bind')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    56
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    57
    def listen (self, int backlog) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    58
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    59
            Listen for connections, marking this socket as a passive socket, which can accept incoming connection
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    60
            requests using sock.accept().
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    61
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    62
            It is customary to call .bind() before .listen().
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    63
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    64
                backlog     - maximum number of pending connections (those not yet .accept()'d).
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    65
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    66
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    67
        # listen()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    68
        if libc.listen(self.fd, backlog) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    69
            raise_errno('listen')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    70
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    71
    def connect (self, sockaddr addr) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    72
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    73
            Initiate a connection, connecting this socket to the remote endpoint specified by `addr`. The given sockaddr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    74
            should be of the same or a compatible address family.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    75
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    76
            If the socket is in non-blocking mode, this will presumeably return errno.EINPROGRESS.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    77
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    78
            If the socket has not yet been bound (using .bind()), the system will pick an appropriate local address and
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    79
            ephemeral port.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    80
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    81
                addr        - the remote address to connect to.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    82
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    83
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    84
        cdef libc.sockaddr *sa_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    85
        cdef libc.socklen_t sa_len
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    86
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    87
        # get the address
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    88
        addr._get_sockaddr(&sa_ptr, &sa_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    89
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    90
        # connect()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    91
        if libc.connect(self.fd, sa_ptr, sa_len) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    92
            raise_errno('connect')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    93
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    94
    def accept (self) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    95
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    96
            Accept a connection, dequeueing the first pending connection and returning a new sock object for it. This
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    97
            socket must be a connection-based socket (SOCK_STREAM/SOCK_SEQPACKET) and in the passive listening mode
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    98
            (.listen()).
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    99
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   100
            This returns a (sock, sockaddr) tuple:
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   101
                sock        - the newly created sock, corresponding to the incoming connection
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   102
                sockaddr    - the remote address of the incoming connection
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   103
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   104
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   105
        # prep the sockaddr that we will return
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   106
        cdef libc.sockaddr_storage ss
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   107
        cdef libc.socklen_t ss_len = sizeof(ss)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   108
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   109
        cdef socket_t sock_fd
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   110
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   111
        # accept()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   112
        sock_fd = libc.accept(self.fd, <libc.sockaddr *> &ss, &ss_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   113
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   114
        if sock_fd < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   115
            raise_errno('accept')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   116
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   117
        # prep the new socket
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   118
        sock_obj = sock(sock_fd)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   119
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   120
        # prep the new addr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   121
        sock_addr = build_sockaddr(<libc.sockaddr *> &ss, ss_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   122
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   123
        return sock_obj, sock_addr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   124
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   125
    def send (self, object buf, int flags = 0) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   126
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   127
            Transmit a message to the connected remote endpoint.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   128
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   129
                buf     - the data to send
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   130
                flags   - MSG_* flags to send with
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   131
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   132
            Returns the number of bytes sent, which may be less than the length of buf.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   133
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   134
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   135
        cdef char *buf_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   136
        cdef libc.ssize_t buf_len, ret
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   137
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   138
        # get buffer
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   139
        # XXX: test that except works right
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   140
        py.PyObject_AsCharBuffer(buf, &buf_ptr, &buf_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   141
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   142
        # send()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   143
        ret = libc.send(self.fd, <void *> buf_ptr, buf_len, flags)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   144
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   145
        if ret < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   146
            raise_errno('send')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   147
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   148
        else :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   149
            return ret
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   150