qmsk.net/socket/sock.pyx
author Tero Marttila <terom@fixme.fi>
Sun, 16 Aug 2009 18:29:55 +0300
changeset 6 10bd48c9b6ce
permissions -rw-r--r--
socket type, mass rename
6
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     1
from sock.sock cimport *
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     2
from sock.addr cimport sockaddr, build_sockaddr
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
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     8
# XXX: do some GIL-releasin'
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     9
cdef class sock :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    10
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    11
    def __init__ (self, int fd = -1) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    12
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    13
            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
    14
        """
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
        self.fd = fd
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    17
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    18
    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
    19
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    20
            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
    21
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    22
                family      - one of AF_*
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    23
                socktype    - one of SOCK_*
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    24
                protocol    - one of IPPROTO_* or zero to select default
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    25
        """
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
        if self.fd >= 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    28
            raise Exception("Socket fd already exists")
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    29
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    30
        # socket()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    31
        self.fd = libc.socket(family, socktype, protocol)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    32
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    33
        # trap
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    34
        if self.fd < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    35
            raise_errno('socket')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    36
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    37
    def bind (self, sockaddr addr) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    38
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    39
            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
    40
            compatible address family.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    41
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    42
                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
    43
                              ephemeral port.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    44
        """
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
        cdef libc.sockaddr *sa_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    47
        cdef libc.socklen_t sa_len
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    48
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    49
        # get the address
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    50
        addr._get_sockaddr(&sa_ptr, &sa_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    51
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    52
        # bind()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    53
        if libc.bind(self.fd, sa_ptr, sa_len) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    54
            raise_errno('bind')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    55
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    56
    def listen (self, int backlog) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    57
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    58
            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
    59
            requests using sock.accept().
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    60
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    61
            It is customary to call .bind() before .listen().
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    62
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    63
                backlog     - maximum number of pending connections (those not yet .accept()'d).
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    64
        """
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
        # listen()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    67
        if libc.listen(self.fd, backlog) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    68
            raise_errno('listen')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    69
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    70
    def connect (self, sockaddr addr) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    71
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    72
            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
    73
            should be of the same or a compatible address family.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    74
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    75
            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
    76
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    77
            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
    78
            ephemeral port.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    79
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    80
                addr        - the remote address to connect to.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    81
        """
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
        cdef libc.sockaddr *sa_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    84
        cdef libc.socklen_t sa_len
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    85
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    86
        # get the address
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    87
        addr._get_sockaddr(&sa_ptr, &sa_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    88
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    89
        # connect()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    90
        if libc.connect(self.fd, sa_ptr, sa_len) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    91
            raise_errno('connect')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    92
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    93
    def accept (self) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    94
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    95
            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
    96
            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
    97
            (.listen()).
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    98
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    99
            This returns a (sock, sockaddr) tuple:
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   100
                sock        - the newly created sock, corresponding to the incoming connection
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   101
                sockaddr    - the remote address of the incoming connection
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   102
        """
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
        # prep the sockaddr that we will return
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   105
        cdef libc.sockaddr_storage ss
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   106
        cdef libc.socklen_t ss_len = sizeof(ss)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   107
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   108
        cdef socket_t sock_fd
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   109
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   110
        # accept()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   111
        sock_fd = libc.accept(self.fd, <libc.sockaddr *> &ss, &ss_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   112
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   113
        if sock_fd < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   114
            raise_errno('accept')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   115
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   116
        # prep the new socket
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   117
        sock_obj = sock(sock_fd)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   118
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   119
        # prep the new addr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   120
        sock_addr = build_sockaddr(<libc.sockaddr *> &ss, ss_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   121
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   122
        return sock_obj, sock_addr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   123
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   124
    def send (self, object buf, int flags = 0) :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   125
        """
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   126
            Transmit a message to the connected remote endpoint.
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   127
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   128
                buf     - the data to send
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   129
                flags   - MSG_* flags to send with
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   130
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   131
            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
   132
        """
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
        cdef char *buf_ptr
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   135
        cdef libc.ssize_t buf_len, ret
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   136
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   137
        # get buffer
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   138
        # XXX: test that except works right
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   139
        py.PyObject_AsCharBuffer(buf, &buf_ptr, &buf_len)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   140
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   141
        # send()
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   142
        ret = libc.send(self.fd, <void *> buf_ptr, buf_len, flags)
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   143
        
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   144
        if ret < 0 :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   145
            raise_errno('send')
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   146
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   147
        else :
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   148
            return ret
10bd48c9b6ce socket type, mass rename
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   149