Subversion Repositories Kolibri OS

Rev

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="Preved!!!Example."
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="Preved!!!Example."
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
}