Rev 2099 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2099 | jaeger | 1 | #include |
2 | #include |
||
3 | |||
4 | #include "tp.h" |
||
5 | |||
6 | extern tp_obj tp_dict(TP); |
||
7 | extern tp_obj tp_method(TP,tp_obj self,tp_obj v(TP)); |
||
8 | extern tp_obj tp_fnc(TP,tp_obj v(TP)); |
||
2110 | jaeger | 9 | extern tp_obj tp_get(TP,tp_obj self, tp_obj k); |
10 | tp_obj tp_has(TP,tp_obj self, tp_obj k); |
||
11 | #define _cdecl __attribute__((cdecl)) |
||
12 | extern int (* _cdecl con_printf)(const char* format,...); |
||
2099 | jaeger | 13 | |
2110 | jaeger | 14 | #define PRECISION 0.000001 |
15 | |||
2099 | jaeger | 16 | #define GET_SOCKET_DESCRIPTOR(_obj, _sock) do{ \ |
2110 | jaeger | 17 | if (fabs(tp_has(tp, _obj, tp_string("socket")).number.val) < PRECISION)\ |
2099 | jaeger | 18 | tp_raise(tp_None, "Socket not open", tp_None); \ |
2110 | jaeger | 19 | _sock = (__u32)(tp_get(tp, _obj, tp_string("socket")).number.val + PRECISION);\ |
2099 | jaeger | 20 | } while(0) |
21 | |||
22 | /* Socket close method. |
||
23 | * |
||
24 | * Example: |
||
25 | * s.close() # s must be a socket object created by socket. |
||
26 | * |
||
27 | * Raises exception if socket was not opened. Otherwise returns True. |
||
28 | */ |
||
2110 | jaeger | 29 | static tp_obj kolibri_close_socket(TP) |
2099 | jaeger | 30 | { |
31 | tp_obj self = TP_TYPE(TP_DICT); |
||
32 | __u32 socktype; |
||
33 | __u32 s; |
||
34 | |||
35 | GET_SOCKET_DESCRIPTOR(self, s); |
||
36 | |||
37 | socktype = (__u32)tp_get(tp, self, tp_string("type")).number.val; |
||
2110 | jaeger | 38 | GET_SOCKET_DESCRIPTOR(self, s); |
2099 | jaeger | 39 | if (socktype == SOCK_STREAM) |
40 | __menuet__close_TCP_socket(s); |
||
41 | else if (socktype == SOCK_DGRAM) |
||
42 | __menuet__close_UDP_socket(s); |
||
43 | return tp_True; |
||
44 | } |
||
45 | |||
46 | /* Socket send method. |
||
47 | * |
||
48 | * Example: |
||
49 | * data=" |
||
50 | * s.send(data) |
||
51 | * or: |
||
52 | * s.send(data, 20) # Send just 20 bytes |
||
53 | */ |
||
2110 | jaeger | 54 | static tp_obj kolibri_send(TP) |
2099 | jaeger | 55 | { |
56 | tp_obj self = TP_TYPE(TP_DICT); |
||
57 | tp_obj data_obj = TP_TYPE(TP_STRING); |
||
58 | __u32 datalen = TP_DEFAULT(tp_False).number.val; |
||
59 | __u32 socktype = (__u32)tp_get(tp, self, tp_string("type")).number.val; |
||
60 | __u32 s; |
||
2110 | jaeger | 61 | int result; |
2099 | jaeger | 62 | |
63 | GET_SOCKET_DESCRIPTOR(self, s); |
||
64 | |||
65 | if (datalen < 0 || datalen > data_obj.string.len) |
||
66 | datalen = data_obj.string.len; |
||
67 | if (socktype == SOCK_STREAM) |
||
2110 | jaeger | 68 | result = __menuet__write_TCP_socket(s, datalen, (void *)data_obj.string.val); |
2099 | jaeger | 69 | else if (socktype == SOCK_DGRAM) |
2110 | jaeger | 70 | result = __menuet__write_UDP_socket(s, datalen, (void *)data_obj.string.val); |
71 | return tp_number(!(result != 0)); |
||
2099 | jaeger | 72 | } |
73 | |||
74 | /* Socket recv method. |
||
75 | * |
||
76 | * data=" |
||
77 | * s.recv(data) |
||
78 | * or: |
||
79 | * s.recv(data, 20) # Send just 20 bytes |
||
80 | */ |
||
2110 | jaeger | 81 | static tp_obj kolibri_recv(TP) |
2099 | jaeger | 82 | { |
83 | tp_obj self = TP_TYPE(TP_DICT); |
||
84 | __u32 datalen = TP_DEFAULT(tp_False).number.val; |
||
85 | __u32 s; |
||
86 | __u8 c; |
||
87 | __u8 *buf, *p; |
||
88 | __u32 buf_size; |
||
89 | __u32 bytes_read = 0; |
||
90 | int i; |
||
91 | |||
92 | GET_SOCKET_DESCRIPTOR(self, s); |
||
93 | |||
94 | if (datalen) |
||
95 | buf_size = datalen; |
||
96 | else |
||
97 | buf_size = 2048; |
||
98 | if (!(buf = malloc(datalen))) |
||
99 | tp_raise(tp_None, "Cannot allocate buffer for received data", tp_None); |
||
100 | p = buf; |
||
101 | while (__menuet__read_socket(s, &c) && bytes_read < buf_size) |
||
102 | { |
||
103 | *p++ = c; |
||
104 | bytes_read++; |
||
105 | if (bytes_read >= buf_size && !datalen) |
||
106 | { |
||
107 | buf_size += 1024; |
||
108 | buf = realloc(buf, buf_size); |
||
109 | } |
||
110 | } |
||
111 | return tp_string_n(buf, bytes_read); |
||
112 | } |
||
113 | |||
2110 | jaeger | 114 | static void inet_pton(TP, const char *buf, int len, __u32 *addr) |
2099 | jaeger | 115 | { |
116 | char *p = (char *)buf; |
||
117 | int i = 0; |
||
118 | __u32 val = 0; |
||
119 | *addr = 0; |
||
120 | while (*p && p < buf + len && i < 4) |
||
121 | { |
||
2110 | jaeger | 122 | if (*p == '.' || !*p) |
2099 | jaeger | 123 | { |
124 | if (val > 255) |
||
2110 | jaeger | 125 | tp_raise(tp_None, "ValueError: number > 255 in IP address", tp_None); |
2099 | jaeger | 126 | *addr += (val << ((i++) << 3)); |
127 | val = 0; |
||
128 | } |
||
129 | else |
||
130 | { |
||
131 | if (*p < '0' || *p > '9') |
||
2110 | jaeger | 132 | tp_raise(tp_None, "ValueError: bad char in IP address, digit expected", tp_None); |
2099 | jaeger | 133 | val = val * 10 + *p - '0'; |
134 | } |
||
135 | p++; |
||
136 | } |
||
2110 | jaeger | 137 | if (!*p) |
138 | { |
||
139 | if (i == 3) |
||
140 | *addr += (val << ((i++) << 3)); |
||
141 | else |
||
142 | tp_raise(tp_None, "ValueError: bad IP address", tp_None); |
||
143 | } |
||
144 | |||
2099 | jaeger | 145 | } |
146 | |||
147 | /* Converter from string presentation to binary address. */ |
||
2110 | jaeger | 148 | static tp_obj kolibri_inet_pton(TP) |
2099 | jaeger | 149 | { |
150 | tp_obj obj; |
||
151 | __u32 addr; |
||
152 | obj = TP_TYPE(TP_STRING); |
||
153 | inet_pton(tp, (char *)obj.string.val, (int)obj.string.len, &addr); |
||
154 | return tp_number(addr); |
||
155 | } |
||
156 | |||
157 | /* Socket bind method. |
||
158 | * |
||
159 | * In KolibriOS it just sets local address and port. |
||
160 | * |
||
161 | * Example: |
||
162 | * s.bind('10.10.1.2', 6000) #Connects to 10.10.1.2:6000 |
||
163 | */ |
||
164 | tp_obj kolibri_bind(TP) |
||
165 | { |
||
166 | tp_obj self = TP_TYPE(TP_DICT); |
||
167 | tp_obj local_addr_obj = TP_OBJ(); |
||
168 | __u32 local_port = (__u32)TP_TYPE(TP_NUMBER).number.val; |
||
169 | __u32 local_addr; |
||
170 | |||
171 | if (local_addr_obj.type == TP_NUMBER) |
||
172 | local_addr = local_addr_obj.number.val; |
||
173 | else if (local_addr_obj.type == TP_STRING) |
||
174 | inet_pton(tp, (const char *)local_addr_obj.string.val, local_addr_obj.string.len, &local_addr); |
||
175 | |||
176 | tp_set(tp, self, tp_string("local_addr"), tp_number(local_addr)); |
||
177 | tp_set(tp, self, tp_string("local_port"), tp_number(local_port)); |
||
178 | return tp_None; |
||
179 | } |
||
180 | |||
181 | /* Socket connect method. |
||
182 | * |
||
183 | * Example: |
||
184 | * s.connect('10.10.1.1', 7000) #Connects to 10.10.1.1:7000 |
||
185 | */ |
||
186 | tp_obj kolibri_connect(TP) |
||
187 | { |
||
188 | tp_obj self = TP_TYPE(TP_DICT); |
||
189 | tp_obj remote_addr_obj = TP_OBJ(); |
||
190 | __u32 remote_addr; |
||
191 | __u32 remote_port = (__u32)TP_TYPE(TP_NUMBER).number.val; |
||
192 | __u32 local_port = tp_get(tp, self, tp_string("local_port")).number.val; |
||
193 | __u32 socktype = (__u32)tp_get(tp, self, tp_string("type")).number.val; |
||
194 | int s = -1; /* Socket descriptor */ |
||
195 | |||
196 | |||
197 | if (remote_addr_obj.type == TP_NUMBER) |
||
198 | remote_addr = remote_addr_obj.number.val; |
||
199 | else if (remote_addr_obj.type == TP_STRING) |
||
200 | inet_pton(tp, (const char *)remote_addr_obj.string.val, remote_addr_obj.string.len, &remote_addr); |
||
201 | |||
202 | if (socktype == SOCK_STREAM) |
||
203 | s = __menuet__open_TCP_socket(local_port, remote_port, remote_addr, 1); |
||
204 | else if (socktype == SOCK_DGRAM) |
||
205 | s = __menuet__open_UDP_socket(local_port, remote_port, remote_addr); |
||
206 | if (s >= 0) |
||
207 | { |
||
208 | tp_set(tp, self, tp_string("socket"), tp_number(s)); |
||
209 | return tp_True; |
||
210 | } |
||
211 | else |
||
212 | return tp_False; |
||
213 | } |
||
214 | |||
215 | /* Socket listen method. |
||
216 | * |
||
217 | * Example: |
||
218 | * s.listen('10.10.1.1', 5000) |
||
219 | */ |
||
220 | tp_obj kolibri_listen(TP) |
||
221 | { |
||
222 | tp_obj self = TP_TYPE(TP_DICT); |
||
223 | tp_obj remote_addr_obj = TP_OBJ(); |
||
224 | __u32 remote_addr; |
||
225 | __u32 remote_port = (__u32)TP_TYPE(TP_NUMBER).number.val; |
||
226 | __u32 local_port = tp_get(tp, self, tp_string("local_port")).number.val; |
||
227 | __u32 socktype = (__u32)tp_get(tp, self, tp_string("type")).number.val; |
||
228 | int s = -1; /* Socket descriptor */ |
||
229 | |||
230 | if (socktype != SOCK_STREAM) |
||
231 | tp_raise(tp_None, "IOError: attempt to listen on non-TCP socket", tp_None); |
||
232 | |||
233 | if (remote_addr_obj.type == TP_NUMBER) |
||
234 | remote_addr = remote_addr_obj.number.val; |
||
235 | else if (remote_addr_obj.type == TP_STRING) |
||
236 | inet_pton(tp, (const char *)remote_addr_obj.string.val, remote_addr_obj.string.len, &remote_addr); |
||
237 | |||
238 | if ((s = __menuet__open_TCP_socket(local_port, remote_port, remote_addr, 0)) >= 0) |
||
239 | { |
||
240 | tp_set(tp, self, tp_string("socket"), tp_number(s)); |
||
241 | return tp_True; |
||
242 | } |
||
243 | else |
||
244 | return tp_False; |
||
245 | } |
||
246 | |||
247 | |||
248 | /* Exported function. |
||
249 | * |
||
250 | * Example: |
||
251 | * |
||
252 | * s = socket(socket.AF_INET, socket.SOCK_DGRAM) |
||
253 | * |
||
254 | * Returns socket object. |
||
255 | */ |
||
256 | tp_obj kolibri_socket(TP) |
||
257 | { |
||
258 | tp_obj s; |
||
259 | tp_obj sockfamily = TP_TYPE(TP_NUMBER); |
||
260 | tp_obj socktype = TP_TYPE(TP_NUMBER); |
||
261 | |||
2110 | jaeger | 262 | if (fabs(sockfamily.number.val - AF_INET) > PRECISION || |
263 | (fabs(socktype.number.val - SOCK_STREAM) > PRECISION && |
||
264 | fabs(socktype.number.val - SOCK_DGRAM) > PRECISION)) |
||
2099 | jaeger | 265 | return tp_None; |
266 | s = tp_dict(tp); |
||
267 | tp_set(tp, s, tp_string("family"), sockfamily); |
||
268 | tp_set(tp, s, tp_string("type"), socktype); |
||
269 | tp_set(tp, s, tp_string("bind"), tp_method(tp, s, kolibri_bind)); |
||
270 | tp_set(tp, s, tp_string("connect"), tp_method(tp, s, kolibri_connect)); |
||
271 | tp_set(tp, s, tp_string("send"), tp_method(tp, s, kolibri_send)); |
||
272 | tp_set(tp, s, tp_string("recv"), tp_method(tp, s, kolibri_recv)); |
||
273 | tp_set(tp, s, tp_string("close"), tp_method(tp, s, kolibri_close_socket)); |
||
2110 | jaeger | 274 | if (fabs(socktype.number.val - SOCK_STREAM) < PRECISION) |
2099 | jaeger | 275 | tp_set(tp, s, tp_string("listen"), tp_method(tp, s, kolibri_listen)); |
276 | return s; |
||
277 | } |
||
278 | |||
279 | tp_obj kolibri_socket_module(TP) |
||
280 | { |
||
281 | tp_obj socket_mod = tp_dict(tp); |
||
282 | |||
283 | tp_set(tp, socket_mod, tp_string("AF_INET"), tp_number(AF_INET)); |
||
284 | tp_set(tp, socket_mod, tp_string("SOCK_STREAM"), tp_number(SOCK_STREAM)); |
||
285 | tp_set(tp, socket_mod, tp_string("SOCK_DGRAM"), tp_number(SOCK_DGRAM)); |
||
2110 | jaeger | 286 | tp_set(tp, socket_mod, tp_string("inet_pton"), tp_fnc(tp, kolibri_inet_pton)); |
2099 | jaeger | 287 | tp_set(tp, socket_mod, tp_string("socket"), tp_fnc(tp, kolibri_socket)); |
288 | return socket_mod; |
||
289 | }>><>><>>><>><>>>>>> |