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