Пример #1
0
STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {
    const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
    int err;
    int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err);
    sock_stream->write(websock, buf, len, &err);
    sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, old_opts, &err);
}
Пример #2
0
STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
    mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);

    // CPython extension: if 2nd arg is provided, that's max len to read,
    // instead of full buffer. Similar to
    // https://docs.python.org/3/library/socket.html#socket.socket.recv_into
    mp_uint_t len = bufinfo.len;
    if (n_args > 2) {
        len = mp_obj_get_int(args[2]);
        if (len > bufinfo.len) {
            len = bufinfo.len;
        }
    }

    int error;
    mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error);
    if (error != 0) {
        if (mp_is_nonblocking_error(error)) {
            return mp_const_none;
        }
        mp_raise_OSError(error);
    } else {
        return MP_OBJ_NEW_SMALL_INT(out_sz);
    }
}
Пример #3
0
STATIC mp_obj_t stream_flush(mp_obj_t self) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL);
    int error;
    mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error);
    if (res == MP_STREAM_ERROR) {
        mp_raise_OSError(error);
    }
    return mp_const_none;
}
Пример #4
0
STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
    mp_obj_webrepl_t *self = self_in;
    if (self->state == STATE_PASSWD) {
        // Don't forward output until passwd is entered
        return size;
    }
    const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_WRITE);
    return stream_p->write(self->sock, buf, size, errcode);
}
Пример #5
0
// Unbuffered, inefficient implementation of readline() for raw I/O files.
STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ);

    mp_int_t max_size = -1;
    if (n_args > 1) {
        max_size = MP_OBJ_SMALL_INT_VALUE(args[1]);
    }

    vstr_t vstr;
    if (max_size != -1) {
        vstr_init(&vstr, max_size);
    } else {
        vstr_init(&vstr, 16);
    }

    while (max_size == -1 || max_size-- != 0) {
        char *p = vstr_add_len(&vstr, 1);
        if (p == NULL) {
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
        }

        int error;
        mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error);
        if (out_sz == MP_STREAM_ERROR) {
            if (mp_is_nonblocking_error(error)) {
                if (vstr.len == 1) {
                    // We just incremented it, but otherwise we read nothing
                    // and immediately got EAGAIN. This case is not well
                    // specified in
                    // https://docs.python.org/3/library/io.html#io.IOBase.readline
                    // unlike similar case for read(). But we follow the latter's
                    // behavior - return None.
                    vstr_clear(&vstr);
                    return mp_const_none;
                } else {
                    goto done;
                }
            }
            mp_raise_OSError(error);
        }
        if (out_sz == 0) {
done:
            // Back out previously added byte
            // Consider, what's better - read a char and get OutOfMemory (so read
            // char is lost), or allocate first as we do.
            vstr_cut_tail_bytes(&vstr, 1);
            break;
        }
        if (*p == '\n') {
            break;
        }
    }

    return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);
}
Пример #6
0
STATIC int get_fd(mp_obj_t fdlike) {
    if (mp_obj_is_obj(fdlike)) {
        const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL);
        int err;
        mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err);
        if (res != MP_STREAM_ERROR) {
            return res;
        }
    }
    return mp_obj_get_int(fdlike);
}
Пример #7
0
STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    mp_arg_check_num(n_args, n_kw, 1, 2, false);
    mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
    DEBUG_printf("sizeof(struct webrepl_file) = %lu\n", sizeof(struct webrepl_file));
    mp_obj_webrepl_t *o = m_new_obj(mp_obj_webrepl_t);
    o->base.type = type;
    o->sock = args[0];
    o->hdr_to_recv = sizeof(struct webrepl_file);
    o->data_to_recv = 0;
    o->state = STATE_PASSWD;
    write_webrepl_str(args[0], SSTR(passwd_prompt));
    return o;
}
Пример #8
0
STATIC mp_obj_t ppp_make_new(mp_obj_t stream) {
    mp_get_stream_raise(stream, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE);

    ppp_if_obj_t *self = m_new_obj_with_finaliser(ppp_if_obj_t);

    self->base.type = &ppp_if_type;
    self->stream = stream;
    self->active = false;
    self->connected = false;
    self->clean_close = false;
    self->client_task_handle = NULL;

    return MP_OBJ_FROM_PTR(self);
}
Пример #9
0
STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
    const mp_stream_p_t *file_stream =
        mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
    byte readbuf[2 + 256];
    int err;
    mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err);
    if (out_sz == MP_STREAM_ERROR) {
        return out_sz;
    }
    readbuf[0] = out_sz;
    readbuf[1] = out_sz >> 8;
    DEBUG_printf("webrepl: Sending %d bytes of file\n", out_sz);
    write_webrepl(self->sock, readbuf, 2 + out_sz);
    return out_sz;
}
Пример #10
0
STATIC unsigned char read_src_stream(TINF_DATA *data) {
    byte *p = (void*)data;
    p -= offsetof(mp_obj_decompio_t, decomp);
    mp_obj_decompio_t *self = (mp_obj_decompio_t*)p;

    const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ);
    int err;
    byte c;
    mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);
    if (out_sz == MP_STREAM_ERROR) {
        mp_raise_OSError(err);
    }
    if (out_sz == 0) {
        nlr_raise(mp_obj_new_exception(&mp_type_EOFError));
    }
    return c;
}
Пример #11
0
mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) {
    mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE);

    int error;
    mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags);
    if (error != 0) {
        if (mp_is_nonblocking_error(error)) {
            // http://docs.python.org/3/library/io.html#io.RawIOBase.write
            // "None is returned if the raw stream is set not to block and
            // no single byte could be readily written to it."
            return mp_const_none;
        }
        mp_raise_OSError(error);
    } else {
        return MP_OBJ_NEW_SMALL_INT(out_sz);
    }
}
Пример #12
0
STATIC void handle_op(mp_obj_webrepl_t *self) {
    mp_obj_t open_args[2] = {
        mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false),
        MP_OBJ_NEW_QSTR(MP_QSTR_rb)
    };

    if (self->hdr.type == PUT_FILE) {
        open_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_wb);
    }

    self->cur_file = mp_builtin_open(2, open_args, (mp_map_t*)&mp_const_empty_map);
    const mp_stream_p_t *file_stream =
        mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);

    #if 0
    struct mp_stream_seek_t seek = { .offset = self->hdr.offset, .whence = 0 };
    int err;
    mp_uint_t res = file_stream->ioctl(self->cur_file, MP_STREAM_SEEK, (uintptr_t)&seek, &err);
    assert(res != MP_STREAM_ERROR);
    #endif

    write_webrepl_resp(self->sock, 0);

    if (self->hdr.type == PUT_FILE) {
        self->data_to_recv = self->hdr.size;
    } else if (self->hdr.type == GET_FILE) {
        byte readbuf[2 + 256];
        int err;
        // TODO: It's not ideal that we block connection while sending file
        // and don't process any input.
        while (1) {
            mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err);
            assert(out_sz != MP_STREAM_ERROR);
            readbuf[0] = out_sz;
            readbuf[1] = out_sz >> 8;
            DEBUG_printf("webrepl: Sending %d bytes of file\n", out_sz);
            write_webrepl(self->sock, readbuf, 2 + out_sz);
            if (out_sz == 0) {
                break;
            }
        }

        write_webrepl_resp(self->sock, 0);
        self->hdr_to_recv = sizeof(struct webrepl_file);
    }
}
Пример #13
0
STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL);

    struct mp_stream_seek_t seek_s;
    // TODO: Could be uint64
    seek_s.offset = mp_obj_get_int(args[1]);
    seek_s.whence = 0;
    if (n_args == 3) {
        seek_s.whence = mp_obj_get_int(args[2]);
    }

    int error;
    mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
    if (res == MP_STREAM_ERROR) {
        mp_raise_OSError(error);
    }

    // TODO: Could be uint64
    return mp_obj_new_int_from_uint(seek_s.offset);
}
Пример #14
0
STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL);

    mp_buffer_info_t bufinfo;
    uintptr_t val = 0;
    if (n_args > 2) {
        if (mp_get_buffer(args[2], &bufinfo, MP_BUFFER_WRITE)) {
            val = (uintptr_t)bufinfo.buf;
        } else {
            val = mp_obj_get_int_truncated(args[2]);
        }
    }

    int error;
    mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error);
    if (res == MP_STREAM_ERROR) {
        mp_raise_OSError(error);
    }

    return mp_obj_new_int(res);
}
Пример #15
0
STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {
    for (mp_uint_t i = 0; i < obj_len; i++) {
        mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
        if (elem->value == NULL) {
            // object not found; get its ioctl and add it to the poll list
            const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
            poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
            poll_obj->obj = obj[i];
            poll_obj->ioctl = stream_p->ioctl;
            poll_obj->flags = flags;
            poll_obj->flags_ret = 0;
            elem->value = poll_obj;
        } else {
            // object exists; update its flags
            if (or_flags) {
                ((poll_obj_t*)elem->value)->flags |= flags;
            } else {
                ((poll_obj_t*)elem->value)->flags = flags;
            }
        }
    }
}
Пример #16
0
STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_READ);

    mp_uint_t total_size = 0;
    vstr_t vstr;
    vstr_init(&vstr, DEFAULT_BUFFER_SIZE);
    char *p = vstr.buf;
    mp_uint_t current_read = DEFAULT_BUFFER_SIZE;
    while (true) {
        int error;
        mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error);
        if (out_sz == MP_STREAM_ERROR) {
            if (mp_is_nonblocking_error(error)) {
                // With non-blocking streams, we read as much as we can.
                // If we read nothing, return None, just like read().
                // Otherwise, return data read so far.
                if (total_size == 0) {
                    return mp_const_none;
                }
                break;
            }
            mp_raise_OSError(error);
        }
        if (out_sz == 0) {
            break;
        }
        total_size += out_sz;
        if (out_sz < current_read) {
            current_read -= out_sz;
            p += out_sz;
        } else {
            p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE);
            current_read = DEFAULT_BUFFER_SIZE;
        }
    }

    vstr.len = total_size;
    return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);
}
Пример #17
0
STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) {
    int err;
    const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
    sock_stream->write(websock, str, sz, &err);
}
Пример #18
0
STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);
    ujson_stream_t s = {stream_obj, stream_p->read, 0, 0};
    vstr_t vstr;
    vstr_init(&vstr, 8);
    mp_obj_list_t stack; // we use a list as a simple stack for nested JSON
    stack.len = 0;
    stack.items = NULL;
    mp_obj_t stack_top = MP_OBJ_NULL;
    mp_obj_type_t *stack_top_type = NULL;
    mp_obj_t stack_key = MP_OBJ_NULL;
    S_NEXT(s);
    for (;;) {
        cont:
        if (S_END(s)) {
            break;
        }
        mp_obj_t next = MP_OBJ_NULL;
        bool enter = false;
        byte cur = S_CUR(s);
        S_NEXT(s);
        switch (cur) {
            case ',':
            case ':':
            case ' ':
            case '\t':
            case '\n':
            case '\r':
                goto cont;
            case 'n':
                if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') {
                    S_NEXT(s);
                    next = mp_const_none;
                } else {
                    goto fail;
                }
                break;
            case 'f':
                if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') {
                    S_NEXT(s);
                    next = mp_const_false;
                } else {
                    goto fail;
                }
                break;
            case 't':
                if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') {
                    S_NEXT(s);
                    next = mp_const_true;
                } else {
                    goto fail;
                }
                break;
            case '"':
                vstr_reset(&vstr);
                for (; !S_END(s) && S_CUR(s) != '"';) {
                    byte c = S_CUR(s);
                    if (c == '\\') {
                        c = S_NEXT(s);
                        switch (c) {
                            case 'b': c = 0x08; break;
                            case 'f': c = 0x0c; break;
                            case 'n': c = 0x0a; break;
                            case 'r': c = 0x0d; break;
                            case 't': c = 0x09; break;
                            case 'u': {
                                mp_uint_t num = 0;
                                for (int i = 0; i < 4; i++) {
                                    c = (S_NEXT(s) | 0x20) - '0';
                                    if (c > 9) {
                                        c -= ('a' - ('9' + 1));
                                    }
                                    num = (num << 4) | c;
                                }
                                vstr_add_char(&vstr, num);
                                goto str_cont;
                            }
                        }
                    }
                    vstr_add_byte(&vstr, c);
                str_cont:
                    S_NEXT(s);
                }
                if (S_END(s)) {
                    goto fail;
                }
                S_NEXT(s);
                next = mp_obj_new_str(vstr.buf, vstr.len, false);
                break;
            case '-':
            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
                bool flt = false;
                vstr_reset(&vstr);
                for (;;) {
                    vstr_add_byte(&vstr, cur);
                    cur = S_CUR(s);
                    if (cur == '.' || cur == 'E' || cur == 'e') {
                        flt = true;
                    } else if (cur == '-' || unichar_isdigit(cur)) {
                        // pass
                    } else {
                        break;
                    }
                    S_NEXT(s);
                }
                if (flt) {
                    next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL);
                } else {
                    next = mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
                }
                break;
            }
            case '[':
                next = mp_obj_new_list(0, NULL);
                enter = true;
                break;
            case '{':
                next = mp_obj_new_dict(0);
                enter = true;
                break;
            case '}':
            case ']': {
                if (stack_top == MP_OBJ_NULL) {
                    // no object at all
                    goto fail;
                }
                if (stack.len == 0) {
                    // finished; compound object
                    goto success;
                }
                stack.len -= 1;
                stack_top = stack.items[stack.len];
                stack_top_type = mp_obj_get_type(stack_top);
                goto cont;
            }
            default:
                goto fail;
        }
        if (stack_top == MP_OBJ_NULL) {
            stack_top = next;
            stack_top_type = mp_obj_get_type(stack_top);
            if (!enter) {
                // finished; single primitive only
                goto success;
            }
        } else {
            // append to list or dict
            if (stack_top_type == &mp_type_list) {
                mp_obj_list_append(stack_top, next);
            } else {
                if (stack_key == MP_OBJ_NULL) {
                    stack_key = next;
                    if (enter) {
                        goto fail;
                    }
                } else {
                    mp_obj_dict_store(stack_top, stack_key, next);
                    stack_key = MP_OBJ_NULL;
                }
            }
            if (enter) {
                if (stack.items == NULL) {
                    mp_obj_list_init(&stack, 1);
                    stack.items[0] = stack_top;
                } else {
                    mp_obj_list_append(MP_OBJ_FROM_PTR(&stack), stack_top);
                }
                stack_top = next;
                stack_top_type = mp_obj_get_type(stack_top);
            }
        }
    }
    success:
    // eat trailing whitespace
    while (unichar_isspace(S_CUR(s))) {
        S_NEXT(s);
    }
    if (!S_END(s)) {
        // unexpected chars
        goto fail;
    }
    if (stack_top == MP_OBJ_NULL || stack.len != 0) {
        // not exactly 1 object
        goto fail;
    }
    vstr_clear(&vstr);
    return stack_top;

    fail:
    nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "syntax error in JSON"));
}
Пример #19
0
STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
    // We know that os.dupterm always calls with size = 1
    assert(size == 1);
    mp_obj_webrepl_t *self = self_in;
    const mp_stream_p_t *sock_stream = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
    mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode);
    //DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz);
    if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
        return out_sz;
    }

    if (self->state == STATE_PASSWD) {
        char c = *(char*)buf;
        if (c == '\r' || c == '\n') {
            self->hdr.fname[self->data_to_recv] = 0;
            DEBUG_printf("webrepl: entered password: %s\n", self->hdr.fname);

            if (strcmp(self->hdr.fname, webrepl_passwd) != 0) {
                write_webrepl_str(self->sock, SSTR(denied_prompt));
                return 0;
            }

            self->state = STATE_NORMAL;
            self->data_to_recv = 0;
            write_webrepl_str(self->sock, SSTR(connected_prompt));
        } else if (self->data_to_recv < 10) {
            self->hdr.fname[self->data_to_recv++] = c;
        }
        return -2;
    }

    // If last read data belonged to text record (== REPL)
    int err;
    if (sock_stream->ioctl(self->sock, MP_STREAM_GET_DATA_OPTS, 0, &err) == 1) {
        return out_sz;
    }

    DEBUG_printf("webrepl: received bin data, hdr_to_recv: %d, data_to_recv=%d\n", self->hdr_to_recv, self->data_to_recv);

    if (self->hdr_to_recv != 0) {
        char *p = (char*)&self->hdr + sizeof(self->hdr) - self->hdr_to_recv;
        *p++ = *(char*)buf;
        if (--self->hdr_to_recv != 0) {
            mp_uint_t hdr_sz = sock_stream->read(self->sock, p, self->hdr_to_recv, errcode);
            if (hdr_sz == MP_STREAM_ERROR) {
                return hdr_sz;
            }
            self->hdr_to_recv -= hdr_sz;
            if (self->hdr_to_recv != 0) {
                return -2;
            }
        }

        DEBUG_printf("webrepl: op: %d, file: %s, chunk @%x, sz=%d\n", self->hdr.type, self->hdr.fname, (uint32_t)self->hdr.offset, self->hdr.size);

        handle_op(self);

        return -2;
    }

    if (self->data_to_recv != 0) {
        static byte filebuf[512];
        filebuf[0] = *(byte*)buf;
        mp_uint_t buf_sz = 1;
        if (--self->data_to_recv != 0) {
            size_t to_read = MIN(sizeof(filebuf) - 1, self->data_to_recv);
            mp_uint_t sz = sock_stream->read(self->sock, filebuf + 1, to_read, errcode);
            if (sz == MP_STREAM_ERROR) {
                return sz;
            }
            self->data_to_recv -= sz;
            buf_sz += sz;
        }

        DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz);
        int err;
        mp_uint_t res = mp_stream_writeall(self->cur_file, filebuf, buf_sz, &err);
        if(res == MP_STREAM_ERROR) {
            assert(0);
        }

        if (self->data_to_recv == 0) {
            close_meth(self->cur_file);
            self->hdr_to_recv = sizeof(struct webrepl_file);
            DEBUG_printf("webrepl: Finished writing file\n");
            write_webrepl_resp(self->sock, 0);
        }

        #ifdef MICROPY_PY_WEBREPL_DELAY
        // Some platforms may have broken drivers and easily gets
        // overloaded with modest traffic WebREPL file transfers
        // generate. The basic workaround is a crude rate control
        // done in such way.
        mp_hal_delay_ms(MICROPY_PY_WEBREPL_DELAY);
        #endif
    }

    return -2;
}
Пример #20
0
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
    // Verify the socket object has the full stream protocol
    mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);

#if MICROPY_PY_USSL_FINALISER
    mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
#else
    mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
#endif
    o->base.type = &ussl_socket_type;
    o->sock = sock;

    int ret;
    mbedtls_ssl_init(&o->ssl);
    mbedtls_ssl_config_init(&o->conf);
    mbedtls_x509_crt_init(&o->cacert);
    mbedtls_x509_crt_init(&o->cert);
    mbedtls_pk_init(&o->pkey);
    mbedtls_ctr_drbg_init(&o->ctr_drbg);
    #ifdef MBEDTLS_DEBUG_C
    // Debug level (0-4)
    mbedtls_debug_set_threshold(0);
    #endif

    mbedtls_entropy_init(&o->entropy);
    const byte seed[] = "upy";
    ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed));
    if (ret != 0) {
        goto cleanup;
    }

    ret = mbedtls_ssl_config_defaults(&o->conf,
                    args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
                    MBEDTLS_SSL_TRANSPORT_STREAM,
                    MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0) {
        goto cleanup;
    }

    mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
    mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);
    #ifdef MBEDTLS_DEBUG_C
    mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);
    #endif

    ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
    if (ret != 0) {
        goto cleanup;
    }

    if (args->server_hostname.u_obj != mp_const_none) {
        const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
        ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
        if (ret != 0) {
            goto cleanup;
        }
    }

    mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);

    if (args->key.u_obj != MP_OBJ_NULL) {
        size_t key_len;
        const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len);
        // len should include terminating null
        ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
        assert(ret == 0);

        size_t cert_len;
        const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
        // len should include terminating null
        ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
        assert(ret == 0);

        ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
        assert(ret == 0);
    }

    if (args->do_handshake.u_bool) {
        while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
            if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
                printf("mbedtls_ssl_handshake error: -%x\n", -ret);
                goto cleanup;
            }
        }
    }

    return o;

cleanup:
    mbedtls_pk_free(&o->pkey);
    mbedtls_x509_crt_free(&o->cert);
    mbedtls_x509_crt_free(&o->cacert);
    mbedtls_ssl_free(&o->ssl);
    mbedtls_ssl_config_free(&o->conf);
    mbedtls_ctr_drbg_free(&o->ctr_drbg);
    mbedtls_entropy_free(&o->entropy);

    if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
        mp_raise_OSError(MP_ENOMEM);
    } else {
        mp_raise_OSError(MP_EIO);
    }
}
Пример #21
0
STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
    mp_obj_websocket_t *self = self_in;
    const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
    while (1) {
        if (self->to_recv != 0) {
            mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);
            if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
                return out_sz;
            }
            self->buf_pos += out_sz;
            self->to_recv -= out_sz;
            if (self->to_recv != 0) {
                *errcode = EAGAIN;
                return MP_STREAM_ERROR;
            }
        }

        switch (self->state) {
            case FRAME_HEADER: {
                // TODO: Split frame handling below is untested so far, so conservatively disable it
                assert(self->buf[0] & 0x80);

                // "Control frames MAY be injected in the middle of a fragmented message."
                // So, they must be processed before data frames (and not alter
                // self->ws_flags)
                byte frame_type = self->buf[0];
                self->last_flags = frame_type;
                frame_type &= FRAME_OPCODE_MASK;

                if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {
                    // Preserve previous frame type
                    self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);
                } else {
                    self->ws_flags = self->buf[0];
                }

                // Reset mask in case someone will use "simplified" protocol
                // without masks.
                memset(self->mask, 0, sizeof(self->mask));

                int to_recv = 0;
                size_t sz = self->buf[1] & 0x7f;
                if (sz == 126) {
                    // Msg size is next 2 bytes
                    to_recv += 2;
                } else if (sz == 127) {
                    // Msg size is next 8 bytes
                    assert(0);
                }
                if (self->buf[1] & 0x80) {
                    // Next 4 bytes is mask
                    to_recv += 4;
                }

                self->buf_pos = 0;
                self->to_recv = to_recv;
                self->msg_sz = sz; // May be overriden by FRAME_OPT
                if (to_recv != 0) {
                    self->state = FRAME_OPT;
                } else {
                    if (frame_type >= FRAME_CLOSE) {
                        self->state = CONTROL;
                    } else {
                        self->state = PAYLOAD;
                    }
                }
                continue;
            }

            case FRAME_OPT: {
                if ((self->buf_pos & 3) == 2) {
                    // First two bytes are message length
                    self->msg_sz = (self->buf[0] << 8) | self->buf[1];
                }
                if (self->buf_pos >= 4) {
                    // Last 4 bytes is mask
                    memcpy(self->mask, self->buf + self->buf_pos - 4, 4);
                }
                self->buf_pos = 0;
                if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {
                    self->state = CONTROL;
                } else {
                    self->state = PAYLOAD;
                }
                continue;
            }

            case PAYLOAD:
            case CONTROL: {
                mp_uint_t out_sz = 0;
                if (self->msg_sz == 0) {
                    // In case message had zero payload
                    goto no_payload;
                }

                size_t sz = MIN(size, self->msg_sz);
                out_sz = stream_p->read(self->sock, buf, sz, errcode);
                if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
                    return out_sz;
                }

                sz = out_sz;
                for (byte *p = buf; sz--; p++) {
                    *p ^= self->mask[self->mask_pos++ & 3];
                }

                self->msg_sz -= out_sz;
                if (self->msg_sz == 0) {
                    byte last_state;
no_payload:
                    last_state = self->state;
                    self->state = FRAME_HEADER;
                    self->to_recv = 2;
                    self->mask_pos = 0;
                    self->buf_pos = 0;

                    // Handle control frame
                    if (last_state == CONTROL) {
                        byte frame_type = self->last_flags & FRAME_OPCODE_MASK;
                        if (frame_type == FRAME_CLOSE) {
                            static char close_resp[2] = {0x88, 0};
                            int err;
                            websocket_write(self_in, close_resp, sizeof(close_resp), &err);
                            return 0;
                        }

                        //DEBUG_printf("Finished receiving ctrl message %x, ignoring\n", self->last_flags);
                        continue;
                    }
                }

                if (out_sz != 0) {
                    return out_sz;
                }
                // Empty (data) frame received is not EOF
                continue;
            }

        }
    }
}
Пример #22
0
STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) {
    const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ);

    // What to do if sz < -1?  Python docs don't specify this case.
    // CPython does a readall, but here we silently let negatives through,
    // and they will cause a MemoryError.
    mp_int_t sz;
    if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) {
        return stream_readall(args[0]);
    }

    #if MICROPY_PY_BUILTINS_STR_UNICODE
    if (stream_p->is_text) {
        // We need to read sz number of unicode characters.  Because we don't have any
        // buffering, and because the stream API can only read bytes, we must read here
        // in units of bytes and must never over read.  If we want sz chars, then reading
        // sz bytes will never over-read, so we follow this approach, in a loop to keep
        // reading until we have exactly enough chars.  This will be 1 read for text
        // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII
        // chars.  For text with lots of non-ASCII chars, it'll be pretty inefficient
        // in time and memory.

        vstr_t vstr;
        vstr_init(&vstr, sz);
        mp_uint_t more_bytes = sz;
        mp_uint_t last_buf_offset = 0;
        while (more_bytes > 0) {
            char *p = vstr_add_len(&vstr, more_bytes);
            if (p == NULL) {
                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
            }
            int error;
            mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error);
            if (error != 0) {
                vstr_cut_tail_bytes(&vstr, more_bytes);
                if (mp_is_nonblocking_error(error)) {
                    // With non-blocking streams, we read as much as we can.
                    // If we read nothing, return None, just like read().
                    // Otherwise, return data read so far.
                    // TODO what if we have read only half a non-ASCII char?
                    if (vstr.len == 0) {
                        vstr_clear(&vstr);
                        return mp_const_none;
                    }
                    break;
                }
                mp_raise_OSError(error);
            }

            if (out_sz < more_bytes) {
                // Finish reading.
                // TODO what if we have read only half a non-ASCII char?
                vstr_cut_tail_bytes(&vstr, more_bytes - out_sz);
                if (out_sz == 0) {
                    break;
                }
            }

            // count chars from bytes just read
            for (mp_uint_t off = last_buf_offset;;) {
                byte b = vstr.buf[off];
                int n;
                if (!UTF8_IS_NONASCII(b)) {
                    // 1-byte ASCII char
                    n = 1;
                } else if ((b & 0xe0) == 0xc0) {
                    // 2-byte char
                    n = 2;
                } else if ((b & 0xf0) == 0xe0) {
                    // 3-byte char
                    n = 3;
                } else if ((b & 0xf8) == 0xf0) {
                    // 4-byte char
                    n = 4;
                } else {
                    // TODO
                    n = 5;
                }
                if (off + n <= vstr.len) {
                    // got a whole char in n bytes
                    off += n;
                    sz -= 1;
                    last_buf_offset = off;
                    if (off >= vstr.len) {
                        more_bytes = sz;
                        break;
                    }
                } else {
                    // didn't get a whole char, so work out how many extra bytes are needed for
                    // this partial char, plus bytes for additional chars that we want
                    more_bytes = (off + n - vstr.len) + (sz - 1);
                    break;
                }
            }
        }

        return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
    }
    #endif

    vstr_t vstr;
    vstr_init_len(&vstr, sz);
    int error;
    mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags);
    if (error != 0) {
        vstr_clear(&vstr);
        if (mp_is_nonblocking_error(error)) {
            // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read
            // "If the object is in non-blocking mode and no bytes are available,
            // None is returned."
            // This is actually very weird, as naive truth check will treat
            // this as EOF.
            return mp_const_none;
        }
        mp_raise_OSError(error);
    } else {
        vstr.len = out_sz;
        return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);
    }
}