Beispiel #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(websock);
    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);
}
Beispiel #2
0
STATIC mp_obj_t stream_flush(mp_obj_t self) {
    const mp_stream_p_t *stream_p = mp_get_stream(self);
    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;
}
Beispiel #3
0
mp_obj_t mp_stream_close(mp_obj_t stream) {
    const mp_stream_p_t *stream_p = mp_get_stream(stream);
    int error;
    mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
    if (res == MP_STREAM_ERROR) {
        mp_raise_OSError(error);
    }
    return mp_const_none;
}
Beispiel #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(self->sock);
    return stream_p->write(self->sock, buf, size, errcode);
}
Beispiel #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(args[0]);

    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);
        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);
}
Beispiel #6
0
STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
    mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
    if (request == MP_STREAM_CLOSE) {
        mbedtls_pk_free(&self->pkey);
        mbedtls_x509_crt_free(&self->cert);
        mbedtls_x509_crt_free(&self->cacert);
        mbedtls_ssl_free(&self->ssl);
        mbedtls_ssl_config_free(&self->conf);
        mbedtls_ctr_drbg_free(&self->ctr_drbg);
        mbedtls_entropy_free(&self->entropy);
    }
    // Pass all requests down to the underlying socket
    return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
}
Beispiel #7
0
STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
    const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);
    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;
}
Beispiel #8
0
STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
    mp_obj_t sock = *(mp_obj_t*)ctx;

    const mp_stream_p_t *sock_stream = mp_get_stream(sock);
    int err;

    mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
    if (out_sz == MP_STREAM_ERROR) {
        if (mp_is_nonblocking_error(err)) {
            return MBEDTLS_ERR_SSL_WANT_READ;
        }
        return -err;
    } else {
        return out_sz;
    }
}
Beispiel #9
0
STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
    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]);
        }
    }

    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
    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);
}
Beispiel #10
0
STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
    const mp_stream_p_t *stream_p = mp_get_stream(self_in);

    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);
}
Beispiel #11
0
// Returns error condition in *errcode, if non-zero, return value is number of bytes written
// before error condition occurred. If *errcode == 0, returns total bytes written (which will
// be equal to input size).
mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) {
    byte *buf = buf_;
    typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
    io_func_t io_func;
    const mp_stream_p_t *stream_p = mp_get_stream(stream);
    if (flags & MP_STREAM_RW_WRITE) {
        io_func = (io_func_t)stream_p->write;
    } else {
        io_func = stream_p->read;
    }

    *errcode = 0;
    mp_uint_t done = 0;
    while (size > 0) {
        mp_uint_t out_sz = io_func(stream, buf, size, errcode);
        // For read, out_sz == 0 means EOF. For write, it's unspecified
        // what it means, but we don't make any progress, so returning
        // is still the best option.
        if (out_sz == 0) {
            return done;
        }
        if (out_sz == MP_STREAM_ERROR) {
            // If we read something before getting EAGAIN, don't leak it
            if (mp_is_nonblocking_error(*errcode) && done != 0) {
                *errcode = 0;
            }
            return done;
        }
        if (flags & MP_STREAM_RW_ONCE) {
            return out_sz;
        }

        buf += out_sz;
        size -= out_sz;
        done += out_sz;
    }
    return done;
}
Beispiel #12
0
STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
    struct mp_stream_seek_t seek_s;
    // TODO: Could be uint64
    seek_s.offset = mp_obj_get_int(args[1]);
    seek_s.whence = SEEK_SET;
    if (n_args == 3) {
        seek_s.whence = mp_obj_get_int(args[2]);
    }

    // In POSIX, it's error to seek before end of stream, we enforce it here.
    if (seek_s.whence == SEEK_SET && seek_s.offset < 0) {
        mp_raise_OSError(MP_EINVAL);
    }

    const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
    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);
}
Beispiel #13
0
STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) {
    // 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]);
    }

    const mp_stream_p_t *stream_p = mp_get_stream(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);
            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);
    }
}
Beispiel #14
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(websock);
    sock_stream->write(websock, str, sz, &err);
}
Beispiel #15
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(self->sock);
    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;
        }

        if (self->hdr.type == PUT_FILE) {
            DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz);
            int err;
            mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err);
            if (err != 0 || res != buf_sz) {
                assert(0);
            }
        } else if (self->hdr.type == GET_FILE) {
            assert(buf_sz == 1);
            assert(self->data_to_recv == 0);
            assert(filebuf[0] == 0);
            mp_uint_t out_sz = write_file_chunk(self);
            if (out_sz != 0) {
                self->data_to_recv = 1;
            }
        }

        if (self->data_to_recv == 0) {
            mp_stream_close(self->cur_file);
            self->hdr_to_recv = sizeof(struct webrepl_file);
            DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type);
            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;
}