Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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