summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/socket.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/socket.c b/src/socket.c
index fc2abed5b..7203db979 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -664,6 +664,86 @@ mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self)
}
static mrb_value
+mrb_win32_basicsocket_read(mrb_state *mrb, mrb_value self)
+{
+#define BUF_LEN 4096
+ char buf[BUF_LEN];
+ int sd, bytes_read;
+ mrb_int read_len;
+ mrb_value str = mrb_str_new(mrb, NULL, 0);
+ mrb_value len_arg = mrb_nil_value();
+
+ /* For compatibility with IO::read, we accept an object instead of just
+ * an mrb_int. Then we raise an exception if it isn't an mrb_int or nil.
+ */
+ mrb_get_args(mrb, "|o", &len_arg);
+ if (mrb_fixnum_p(len_arg)) {
+ read_len = mrb_fixnum(len_arg);
+ if (read_len < 0) {
+ mrb_str_cat_cstr(mrb, str, "negative length: ");
+ mrb_str_append(mrb, str, len_arg);
+ mrb_str_cat_cstr(mrb, str, " given");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, mrb_string_value_cstr(mrb, &str));
+ return mrb_nil_value();
+ } else if (read_len == 0) {
+ return str;
+ }
+ } else if (mrb_nil_p(len_arg)) {
+ read_len = 0;
+ } else {
+ mrb_str_cat_cstr(mrb, str, "can't convert ");
+ mrb_str_append(mrb, str, len_arg);
+ mrb_str_cat_cstr(mrb, str, " into Integer");
+ mrb_raise(mrb, E_TYPE_ERROR, mrb_string_value_cstr(mrb, &str));
+ return mrb_nil_value();
+ }
+
+ sd = socket_fd(mrb, self);
+ bytes_read = 0;
+
+ /* Behavior of positive integer argument: read until length bytes have been
+ * read, or until the socket has closed. */
+ if (read_len > 0) {
+ int n = 0;
+ int max_read_len = BUF_LEN;
+ int keep_reading = 1;
+ while (keep_reading) {
+ if (max_read_len > (read_len - bytes_read))
+ max_read_len = read_len - bytes_read;
+ n = recv(sd, buf, max_read_len, 0);
+
+ if (n == SOCKET_ERROR) {
+ mrb_sys_fail(mrb, "recv");
+ } else if (n == 0) {
+ keep_reading = 0;
+ } else {
+ mrb_str_cat(mrb, str, buf, n);
+ bytes_read += n;
+ if (bytes_read >= read_len)
+ keep_reading = 0;
+ }
+ }
+ }
+ /* Behavior of nil/default argument: read until socket has closed */
+ else {
+ int keep_reading = 1;
+ while (keep_reading) {
+ bytes_read = recv(sd, buf, BUF_LEN, 0);
+ if (bytes_read == SOCKET_ERROR) {
+ mrb_sys_fail(mrb, "recv");
+ } else if (bytes_read == 0) {
+ keep_reading = 0;
+ } else {
+ mrb_str_cat(mrb, str, buf, bytes_read);
+ }
+ }
+ }
+
+ return str;
+#undef BUF_LEN
+}
+
+static mrb_value
mrb_win32_basicsocket_write(mrb_state *mrb, mrb_value self)
{
int n;
@@ -762,6 +842,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb)
/* Windows IO Method Overrides on BasicSocket */
#ifdef _WIN32
mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE());
+ mrb_define_method(mrb, bsock, "read", mrb_win32_basicsocket_read, MRB_ARGS_OPT(1));
mrb_define_method(mrb, bsock, "write", mrb_win32_basicsocket_write, MRB_ARGS_REQ(1));
#endif