polyphony 0.97 → 0.98

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a8218fc4160e0772ee3aada1f72ea9d063724ccf9b0aee7dfa6e9e4d69ebfe4
4
- data.tar.gz: 74aae84e991cd4330ad282553061b29e71a6434ce2dafc9985c62feb3a966a68
3
+ metadata.gz: bf93e3d5dfd0a5e3a4a70ee66d62caddc1ea22e63cf1ce44a212a75f18c2ac76
4
+ data.tar.gz: 121f84bb920ccc6822cb43b772a68dd92b2f2d81ebf9e1a510c081481dd1e3b1
5
5
  SHA512:
6
- metadata.gz: 772d0be4ef2f723fa27cc5ecb8ef9e9b5d012c501a364ab23dce7d145fc6d156d5e219e52e871a2aadb41a397c5fb044c8aaee9b42906f4894ff3447af0e93ba
7
- data.tar.gz: b74d6958ea8a77ffee45aed8184091b5ef54cb4fcaca9798351533b13d2f2202f28ab95f56a26e09692bf40f00e723d2df9c99007dbe10631d1c69c523fb3a58
6
+ metadata.gz: 286d3cb30ecd19b8f046fe43761f6d2f243f3e3a8134d01ebe14fdfdf11d6d879000f51ba66c705b0ad425e3c6a51dff02781b47e8cf75e52bc4f0439dfffc0e
7
+ data.tar.gz: 7caf9e3b7294ece38c964dc0366011b07d8977f95ec8c92a22763b9ecccc33080de40b5ab19bb66223eb4bb27be0847c92879a173dceee1b3fda9e1b03b0cdcd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.98 2023-03-08
2
+
3
+ - Add basic support for UDP sockets
4
+ - Fix `IO#read` to return empty string when reading length zero
5
+ - Fix hang on `require 'polyphony'` in irb session
6
+
1
7
  ## 0.97 2023-02-28
2
8
 
3
9
  - Fix working with IRB (#5)
data/examples/io/irb.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'irb'
5
- require 'polyphony/adapters/irb'
5
+ require 'polyphony'
6
6
 
7
7
  $counter = 0
8
8
  timer = spin do
@@ -501,6 +501,36 @@ int backend_getaddrinfo(VALUE host, VALUE port, struct sockaddr **ai_addr) {
501
501
  return addrinfo_result->ai_addrlen;
502
502
  }
503
503
 
504
+ inline VALUE name_to_addrinfo(void *name, socklen_t len) {
505
+ switch(((struct sockaddr *)name)->sa_family) {
506
+ case AF_INET:
507
+ {
508
+ struct sockaddr_in *info = name;
509
+ char buf[INET_ADDRSTRLEN];
510
+
511
+ VALUE port = INT2NUM(ntohs(info->sin_port));
512
+ if (!inet_ntop(AF_INET, &info->sin_addr, buf, sizeof(buf)))
513
+ rb_raise(rb_eRuntimeError, "Failed to get AF_INET addr");
514
+ VALUE addr = rb_str_new_cstr(buf);
515
+ return rb_ary_new_from_args(4, rb_str_new_literal("AF_INET"), port, addr, addr);
516
+ RB_GC_GUARD(addr);
517
+ }
518
+ case AF_INET6:
519
+ {
520
+ struct sockaddr_in6 *info = name;
521
+ char buf[INET6_ADDRSTRLEN];
522
+
523
+ VALUE port = INT2NUM(ntohs(info->sin6_port));
524
+ if (!inet_ntop(AF_INET6, &info->sin6_addr, buf, sizeof(buf)))
525
+ rb_raise(rb_eRuntimeError, "Failed to get AF_INET addr");
526
+ VALUE addr = rb_str_new_cstr(buf);
527
+ return rb_ary_new_from_args(4, rb_str_new_literal("AF_INET6"), port, addr, addr);
528
+ RB_GC_GUARD(addr);
529
+ }
530
+ }
531
+ return Qnil;
532
+ }
533
+
504
534
  inline struct backend_buffer_spec backend_get_buffer_spec(VALUE in, int rw) {
505
535
  if (FIXNUM_P(in)) {
506
536
  struct buffer_spec *spec = FIX2PTR(in);
@@ -148,5 +148,6 @@ void set_fd_blocking_mode(int fd, int blocking);
148
148
  void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
149
149
  void backend_setup_stats_symbols();
150
150
  int backend_getaddrinfo(VALUE host, VALUE port, struct sockaddr **ai_addr);
151
+ VALUE name_to_addrinfo(void *name, socklen_t len);
151
152
 
152
153
  #endif /* BACKEND_COMMON_H */
@@ -673,6 +673,67 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE pos)
673
673
  return buffer_spec.raw ? INT2FIX(total) : buffer;
674
674
  }
675
675
 
676
+ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts) {
677
+ Backend_t *backend;
678
+ int fd;
679
+ rb_io_t *fptr;
680
+ struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 0);
681
+ long total = 0;
682
+
683
+ GetBackend(self, backend);
684
+ backend_prepare_read_buffer(buffer, maxlen, &buffer_spec, FIX2INT(pos));
685
+ fd = fd_from_io(io, &fptr, 0, 0);
686
+
687
+ char addr_buffer[64];
688
+ struct iovec iov;
689
+ struct msghdr msg;
690
+
691
+ iov.iov_base = StringValuePtr(buffer);
692
+ iov.iov_len = maxlen;
693
+
694
+ msg.msg_name = addr_buffer;
695
+ msg.msg_namelen = sizeof(addr_buffer);
696
+ msg.msg_iov = &iov;
697
+ msg.msg_iovlen = 1;
698
+ msg.msg_control = 0;
699
+ msg.msg_controllen = 0;
700
+ msg.msg_flags = 0;
701
+
702
+ while (1) {
703
+ VALUE resume_value = Qnil;
704
+ op_context_t *ctx = context_store_acquire(&backend->store, OP_RECV);
705
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
706
+ int result;
707
+ int completed;
708
+
709
+ io_uring_prep_recvmsg(sqe, fd, &msg, NUM2INT(flags));
710
+
711
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
712
+ completed = context_store_release(&backend->store, ctx);
713
+ if (!completed) {
714
+ context_attach_buffers(ctx, 1, &buffer);
715
+ RAISE_IF_EXCEPTION(resume_value);
716
+ return resume_value;
717
+ }
718
+ RB_GC_GUARD(resume_value);
719
+
720
+ if (result < 0)
721
+ rb_syserr_fail(-result, strerror(-result));
722
+ else {
723
+ total += result;
724
+ break;
725
+ }
726
+ }
727
+
728
+ if (!total) return Qnil;
729
+
730
+ if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
731
+ VALUE addr = name_to_addrinfo(msg.msg_name, msg.msg_namelen);
732
+ VALUE rflags = INT2NUM(msg.msg_flags);
733
+ return rb_ary_new_from_args(3, buffer, addr, rflags);
734
+ RB_GC_GUARD(addr);
735
+ }
736
+
676
737
  VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
677
738
  Backend_t *backend;
678
739
  int fd;
@@ -809,6 +870,68 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE buffer, VALUE flags) {
809
870
  return INT2FIX(buffer_spec.len);
810
871
  }
811
872
 
873
+ VALUE Backend_sendmsg(VALUE self, VALUE io, VALUE buffer, VALUE flags, VALUE dest_sockaddr, VALUE controls) {
874
+ Backend_t *backend;
875
+ int fd;
876
+ rb_io_t *fptr;
877
+
878
+ struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 1);
879
+ long left = buffer_spec.len;
880
+ int flags_int = FIX2INT(flags);
881
+
882
+ GetBackend(self, backend);
883
+ fd = fd_from_io(io, &fptr, 1, 0);
884
+
885
+ struct iovec iov;
886
+ struct msghdr msg;
887
+
888
+ iov.iov_base = buffer_spec.ptr;
889
+ iov.iov_len = buffer_spec.len;
890
+
891
+ if (dest_sockaddr != Qnil) {
892
+ msg.msg_name = RSTRING_PTR(dest_sockaddr);
893
+ msg.msg_namelen = RSTRING_LEN(dest_sockaddr);
894
+ }
895
+ else {
896
+ msg.msg_name = 0;
897
+ msg.msg_namelen = 0;
898
+ }
899
+ msg.msg_iov = &iov;
900
+ msg.msg_iovlen = 1;
901
+ msg.msg_control = 0;
902
+ msg.msg_controllen = 0;
903
+ msg.msg_flags = 0;
904
+
905
+ while (left > 0) {
906
+ VALUE resume_value = Qnil;
907
+ op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
908
+ struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
909
+ int result;
910
+ int completed;
911
+
912
+ io_uring_prep_sendmsg(sqe, fd, &msg, flags_int);
913
+
914
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
915
+ completed = context_store_release(&backend->store, ctx);
916
+ if (!completed) {
917
+ context_attach_buffers(ctx, 1, &buffer);
918
+ RAISE_IF_EXCEPTION(resume_value);
919
+ return resume_value;
920
+ }
921
+ RB_GC_GUARD(resume_value);
922
+
923
+ if (result < 0)
924
+ rb_syserr_fail(-result, strerror(-result));
925
+ else {
926
+ iov.iov_base += result;
927
+ iov.iov_len -= result;
928
+ left -= result;
929
+ }
930
+ }
931
+
932
+ return INT2FIX(buffer_spec.len);
933
+ }
934
+
812
935
  VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
813
936
  int server_fd;
814
937
  rb_io_t *server_fptr;
@@ -1727,9 +1850,11 @@ void Init_Backend(void) {
1727
1850
  rb_define_method(cBackend, "read", Backend_read, 5);
1728
1851
  rb_define_method(cBackend, "read_loop", Backend_read_loop, 2);
1729
1852
  rb_define_method(cBackend, "recv", Backend_recv, 4);
1853
+ rb_define_method(cBackend, "recvmsg", Backend_recvmsg, 7);
1730
1854
  rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
1731
1855
  rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 2);
1732
1856
  rb_define_method(cBackend, "send", Backend_send, 3);
1857
+ rb_define_method(cBackend, "sendmsg", Backend_sendmsg, 5);
1733
1858
  rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1734
1859
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1735
1860
 
@@ -350,6 +350,72 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE pos)
350
350
  return Backend_read(self, io, buffer, length, Qnil, pos);
351
351
  }
352
352
 
353
+ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts) {
354
+ Backend_t *backend;
355
+ struct libev_io watcher;
356
+ int fd;
357
+ rb_io_t *fptr;
358
+
359
+ struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 0);
360
+ long total = 0;
361
+ VALUE switchpoint_result = Qnil;
362
+
363
+ GetBackend(self, backend);
364
+ backend_prepare_read_buffer(buffer, maxlen, &buffer_spec, FIX2INT(pos));
365
+ fd = fd_from_io(io, &fptr, 0, 1);
366
+ watcher.fiber = Qnil;
367
+
368
+ char addr_buffer[64];
369
+ struct iovec iov;
370
+ struct msghdr msg;
371
+
372
+ iov.iov_base = StringValuePtr(buffer);
373
+ iov.iov_len = maxlen;
374
+
375
+ msg.msg_name = addr_buffer;
376
+ msg.msg_namelen = sizeof(addr_buffer);
377
+ msg.msg_iov = &iov;
378
+ msg.msg_iovlen = 1;
379
+ msg.msg_control = 0;
380
+ msg.msg_controllen = 0;
381
+ msg.msg_flags = 0;
382
+
383
+ while (1) {
384
+ backend->base.op_count++;
385
+ ssize_t result = recvmsg(fd, &msg, NUM2INT(flags));
386
+ if (result < 0) {
387
+ int e = errno;
388
+ if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
389
+
390
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, EV_READ);
391
+
392
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
393
+ }
394
+ else {
395
+ switchpoint_result = backend_snooze(&backend->base);
396
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
397
+
398
+ if (!result) break; // EOF
399
+
400
+ total += result;
401
+ break;
402
+ }
403
+ }
404
+
405
+ if (!total) return Qnil;
406
+
407
+ if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
408
+ VALUE addr = name_to_addrinfo(msg.msg_name, msg.msg_namelen);
409
+ VALUE rflags = INT2NUM(msg.msg_flags);
410
+
411
+ return rb_ary_new_from_args(3, buffer, addr, rflags);
412
+ RB_GC_GUARD(addr);
413
+ RB_GC_GUARD(watcher.fiber);
414
+ RB_GC_GUARD(switchpoint_result);
415
+ error:
416
+ return RAISE_EXCEPTION(switchpoint_result);
417
+ }
418
+
353
419
  VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
354
420
  Backend_t *backend;
355
421
  struct libev_io watcher;
@@ -768,6 +834,73 @@ error:
768
834
  return RAISE_EXCEPTION(switchpoint_result);
769
835
  }
770
836
 
837
+ VALUE Backend_sendmsg(VALUE self, VALUE io, VALUE buffer, VALUE flags, VALUE dest_sockaddr, VALUE controls) {
838
+ Backend_t *backend;
839
+ struct libev_io watcher;
840
+ int fd;
841
+ rb_io_t *fptr;
842
+ VALUE switchpoint_result = Qnil;
843
+
844
+ struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 1);
845
+ long left = buffer_spec.len;
846
+ int flags_int = FIX2INT(flags);
847
+
848
+ GetBackend(self, backend);
849
+ fd = fd_from_io(io, &fptr, 1, 0);
850
+ watcher.fiber = Qnil;
851
+
852
+ struct iovec iov;
853
+ struct msghdr msg;
854
+
855
+ iov.iov_base = buffer_spec.ptr;
856
+ iov.iov_len = buffer_spec.len;
857
+
858
+ if (dest_sockaddr != Qnil) {
859
+ msg.msg_name = RSTRING_PTR(dest_sockaddr);
860
+ msg.msg_namelen = RSTRING_LEN(dest_sockaddr);
861
+ }
862
+ else {
863
+ msg.msg_name = 0;
864
+ msg.msg_namelen = 0;
865
+ }
866
+ msg.msg_iov = &iov;
867
+ msg.msg_iovlen = 1;
868
+ msg.msg_control = 0;
869
+ msg.msg_controllen = 0;
870
+ msg.msg_flags = 0;
871
+
872
+ while (left > 0) {
873
+ backend->base.op_count++;
874
+ ssize_t result = sendmsg(fd, &msg, flags_int);
875
+ if (result < 0) {
876
+ int e = errno;
877
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
878
+
879
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, EV_WRITE);
880
+
881
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
882
+ }
883
+ else {
884
+ iov.iov_base = (buffer_spec.ptr += result);
885
+ iov.iov_len -= result;
886
+ left -= result;
887
+ }
888
+ }
889
+
890
+ if (watcher.fiber == Qnil) {
891
+ switchpoint_result = backend_snooze(&backend->base);
892
+
893
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
894
+ }
895
+
896
+ RB_GC_GUARD(watcher.fiber);
897
+ RB_GC_GUARD(switchpoint_result);
898
+
899
+ return INT2FIX(buffer_spec.len);
900
+ error:
901
+ return RAISE_EXCEPTION(switchpoint_result);
902
+ }
903
+
771
904
  struct libev_rw_ctx {
772
905
  int ref_count;
773
906
  VALUE fiber;
@@ -1502,9 +1635,11 @@ void Init_Backend(void) {
1502
1635
  rb_define_method(cBackend, "read", Backend_read, 5);
1503
1636
  rb_define_method(cBackend, "read_loop", Backend_read_loop, 2);
1504
1637
  rb_define_method(cBackend, "recv", Backend_recv, 4);
1638
+ rb_define_method(cBackend, "recvmsg", Backend_recvmsg, 7);
1505
1639
  rb_define_method(cBackend, "recv_loop", Backend_read_loop, 2);
1506
1640
  rb_define_method(cBackend, "recv_feed_loop", Backend_feed_loop, 3);
1507
1641
  rb_define_method(cBackend, "send", Backend_send, 3);
1642
+ rb_define_method(cBackend, "sendmsg", Backend_sendmsg, 5);
1508
1643
  rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1509
1644
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1510
1645
 
@@ -21,7 +21,9 @@ ID ID_write;
21
21
 
22
22
  VALUE SYM_backend_read;
23
23
  VALUE SYM_backend_recv;
24
+ VALUE SYM_backend_recvmsg;
24
25
  VALUE SYM_backend_send;
26
+ VALUE SYM_backend_sendmsg;
25
27
  VALUE SYM_backend_write;
26
28
  VALUE SYM_call;
27
29
  VALUE SYM_comment;
@@ -66,6 +66,10 @@ VALUE Polyphony_backend_recv(VALUE self, VALUE io, VALUE buffer, VALUE length, V
66
66
  return Backend_recv(BACKEND(), io, buffer, length, pos);
67
67
  }
68
68
 
69
+ VALUE Polyphony_backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts) {
70
+ return Backend_recvmsg(BACKEND(), io, buffer, maxlen, pos, flags, maxcontrollen, opts);
71
+ }
72
+
69
73
  VALUE Polyphony_backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
70
74
  return Backend_recv_loop(BACKEND(), io, maxlen);
71
75
  }
@@ -78,6 +82,10 @@ VALUE Polyphony_backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags) {
78
82
  return Backend_send(BACKEND(), io, msg, flags);
79
83
  }
80
84
 
85
+ VALUE Polyphony_backend_sendmsg(VALUE self, VALUE io, VALUE msg, VALUE flags, VALUE dest_sockaddr, VALUE controls) {
86
+ return Backend_sendmsg(BACKEND(), io, msg, flags, dest_sockaddr, controls);
87
+ }
88
+
81
89
  VALUE Polyphony_backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
82
90
  return Backend_sendv(BACKEND(), io, ary, flags);
83
91
  }
@@ -181,9 +189,11 @@ void Init_Polyphony(void) {
181
189
  rb_define_singleton_method(mPolyphony, "backend_read", Polyphony_backend_read, 5);
182
190
  rb_define_singleton_method(mPolyphony, "backend_read_loop", Polyphony_backend_read_loop, 2);
183
191
  rb_define_singleton_method(mPolyphony, "backend_recv", Polyphony_backend_recv, 4);
192
+ rb_define_singleton_method(mPolyphony, "backend_recvmsg", Polyphony_backend_recvmsg, 7);
184
193
  rb_define_singleton_method(mPolyphony, "backend_recv_loop", Polyphony_backend_recv_loop, 2);
185
194
  rb_define_singleton_method(mPolyphony, "backend_recv_feed_loop", Polyphony_backend_recv_feed_loop, 3);
186
195
  rb_define_singleton_method(mPolyphony, "backend_send", Polyphony_backend_send, 3);
196
+ rb_define_singleton_method(mPolyphony, "backend_sendmsg", Polyphony_backend_sendmsg, 5);
187
197
  rb_define_singleton_method(mPolyphony, "backend_sendv", Polyphony_backend_sendv, 3);
188
198
  rb_define_singleton_method(mPolyphony, "backend_sleep", Polyphony_backend_sleep, 1);
189
199
  rb_define_singleton_method(mPolyphony, "backend_splice", Polyphony_backend_splice, 3);
@@ -100,9 +100,11 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
100
100
  VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos);
101
101
  VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen);
102
102
  VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos);
103
+ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts);
103
104
  VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen);
104
105
  VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
105
106
  VALUE Backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags);
107
+ VALUE Backend_sendmsg(VALUE self, VALUE io, VALUE msg, VALUE flags, VALUE dest_sockaddr, VALUE controls);
106
108
  VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
107
109
  VALUE Backend_sleep(VALUE self, VALUE duration);
108
110
  VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'polyphony'
4
-
5
3
  module Kernel
6
4
  alias_method :gets, :orig_gets
7
5
  end
@@ -143,6 +143,8 @@ class ::IO
143
143
 
144
144
  alias_method :orig_read, :read
145
145
  def read(len = nil, buf = nil, buf_pos = 0)
146
+ return '' if len == 0
147
+
146
148
  if buf
147
149
  return Polyphony.backend_read(self, buf, len, true, buf_pos)
148
150
  end
@@ -742,4 +742,33 @@ class ::UNIXSocket
742
742
  def write_nonblock(buf, exception: true)
743
743
  @io.write_nonblock(buf, exception: exception)
744
744
  end
745
- end
745
+ end
746
+
747
+ class ::UDPSocket
748
+ def recvfrom(maxlen, flags = 0)
749
+ buf = +''
750
+ Polyphony.backend_recvmsg(self, buf, maxlen, 0, flags, 0, nil)
751
+ end
752
+
753
+ def recvmsg(maxlen = nil, flags = 0, maxcontrollen = nil, opts = {})
754
+ buf = +''
755
+ Polyphony.backend_recvmsg(self, buf, maxlen || 4096, 0, flags, maxcontrollen, opts)
756
+ end
757
+
758
+ def sendmsg(msg, flags = 0, dest_sockaddr = nil, *controls)
759
+ Polyphony.backend_sendmsg(self, msg, flags, dest_sockaddr, controls)
760
+ end
761
+
762
+ def send(msg, flags, *addr)
763
+ sockaddr = case addr.size
764
+ when 2
765
+ Socket.sockaddr_in(addr[1], addr[0])
766
+ when 1
767
+ addr[0]
768
+ else
769
+ nil
770
+ end
771
+
772
+ Polyphony.backend_sendmsg(self, msg, flags, sockaddr, nil)
773
+ end
774
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.97'
4
+ VERSION = '0.98'
5
5
  end
data/lib/polyphony.rb CHANGED
@@ -133,3 +133,7 @@ if (debug_socket_path = ENV['POLYPHONY_DEBUG_SOCKET_PATH'])
133
133
  require 'polyphony/debugger'
134
134
  Polyphony.start_debug_server(debug_socket_path)
135
135
  end
136
+
137
+ if Object.const_defined?(:IRB)
138
+ require_relative './polyphony/adapters/irb'
139
+ end
data/test/test_io.rb CHANGED
@@ -93,6 +93,13 @@ class IOTest < MiniTest::Test
93
93
  assert_equal 'deffoobar', buf
94
94
  end
95
95
 
96
+ def test_read_zero
97
+ i, o = IO.pipe
98
+
99
+ o << 'hi'
100
+ assert_equal '', i.read(0)
101
+ end
102
+
96
103
  def test_readpartial
97
104
  i, o = IO.pipe
98
105
 
@@ -658,6 +665,7 @@ class IOClassMethodsTest < MiniTest::Test
658
665
 
659
666
  # writing always causes snoozing
660
667
  o << 'foo'
668
+ 3.times { snooze }
661
669
  o << 'bar'
662
670
  o.close
663
671
 
data/test/test_socket.rb CHANGED
@@ -4,11 +4,7 @@ require_relative 'helper'
4
4
  require 'fileutils'
5
5
  require 'msgpack'
6
6
 
7
- class SocketTest < MiniTest::Test
8
- def setup
9
- super
10
- end
11
-
7
+ class TCPSocketTest < MiniTest::Test
12
8
  def start_tcp_server_on_random_port(host = '127.0.0.1')
13
9
  port = rand(1100..60000)
14
10
  server = TCPServer.new(host, port)
@@ -41,13 +37,13 @@ class SocketTest < MiniTest::Test
41
37
  end
42
38
 
43
39
  def test_tcpsocket_open_with_hostname
44
- client = TCPSocket.open('google.com', 80)
45
- client.write("GET / HTTP/1.0\r\nHost: google.com\r\n\r\n")
40
+ client = TCPSocket.open('ipinfo.io', 80)
41
+ client.write("GET / HTTP/1.0\r\nHost: ipinfo.io\r\n\r\n")
46
42
  result = nil
47
43
  move_on_after(3) {
48
44
  result = client.read
49
45
  }
50
- assert result =~ /HTTP\/1.0 301 Moved Permanently/
46
+ assert result =~ /HTTP\/1.0 200 OK/
51
47
  end
52
48
 
53
49
  def test_tcp_ipv6
@@ -166,7 +162,9 @@ class SocketTest < MiniTest::Test
166
162
  server_fiber&.await
167
163
  server&.close
168
164
  end
165
+ end
169
166
 
167
+ class UNIXSocketTest < MiniTest::Test
170
168
  def test_unix_socket
171
169
  path = '/tmp/test_unix_socket'
172
170
  FileUtils.rm(path) rescue nil
@@ -193,7 +191,7 @@ class SocketTest < MiniTest::Test
193
191
  end
194
192
  end
195
193
 
196
- class SocketWithRawBufferTest < MiniTest::Test
194
+ class TCPSocketWithRawBufferTest < MiniTest::Test
197
195
  def start_tcp_server_on_random_port(host = '127.0.0.1')
198
196
  port = rand(1100..60000)
199
197
  server = TCPServer.new(host, port)
@@ -243,6 +241,68 @@ class SocketWithRawBufferTest < MiniTest::Test
243
241
  end
244
242
  end
245
243
 
244
+ class UDPSocketTest < MiniTest::Test
245
+ def test_udp_recvfrom
246
+ u1 = UDPSocket.new
247
+ u1.bind('127.0.0.1', 0)
248
+
249
+ server_fiber = spin do
250
+ msg, peer_addr = u1.recvfrom(256)
251
+ u1.send(msg, 0, peer_addr[3], peer_addr[1])
252
+ end
253
+
254
+ server_addr = u1.addr
255
+ u2 = UDPSocket.new
256
+ u2.bind('127.0.0.1', 0)
257
+ u2.send('foobar', 0, server_addr[3], server_addr[1])
258
+
259
+ msg, addr = u2.recvfrom(256)
260
+
261
+ assert_equal 'foobar', msg
262
+ assert_equal server_addr, addr
263
+ end
264
+
265
+ def test_udp_recvmsg
266
+ u1 = UDPSocket.new
267
+ u1.bind('127.0.0.1', 0)
268
+
269
+ server_fiber = spin do
270
+ msg, peer_addr = u1.recvmsg(256)
271
+ u1.send(msg, 0, peer_addr[3], peer_addr[1])
272
+ end
273
+
274
+ server_addr = u1.addr
275
+ u2 = UDPSocket.new
276
+ u2.bind('127.0.0.1', 0)
277
+ u2.send('foobar', 0, server_addr[3], server_addr[1])
278
+
279
+ msg, addr = u2.recvmsg(256)
280
+
281
+ assert_equal 'foobar', msg
282
+ assert_equal server_addr, addr
283
+ end
284
+
285
+ def test_udp_recvfrom_ipv6
286
+ u1 = UDPSocket.new :INET6
287
+ u1.bind('::1', 0)
288
+
289
+ server_fiber = spin do
290
+ msg, peer_addr = u1.recvfrom(256)
291
+ u1.send(msg, 0, peer_addr[3], peer_addr[1])
292
+ end
293
+
294
+ server_addr = u1.addr
295
+ u2 = UDPSocket.new :INET6
296
+ u2.bind('::1', 0)
297
+ u2.send('foobar', 0, server_addr[3], server_addr[1])
298
+
299
+ msg, addr = u2.recvfrom(256)
300
+
301
+ assert_equal 'foobar', msg
302
+ assert_equal server_addr, addr
303
+ end
304
+ end
305
+
246
306
  if IS_LINUX
247
307
  class HTTPClientTest < MiniTest::Test
248
308
 
@@ -261,4 +321,4 @@ if IS_LINUX
261
321
  assert_equal 'https://ipinfo.io/missingauth', response['readme']
262
322
  end
263
323
  end
264
- end
324
+ end
data/test/test_thread.rb CHANGED
@@ -40,13 +40,14 @@ class ThreadTest < MiniTest::Test
40
40
 
41
41
  def test_thread_join_with_timeout
42
42
  buffer = []
43
- spin { (1..3).each { |i| snooze; buffer << i } }
43
+ f = spin { (1..3).each { |i| snooze; buffer << i } }
44
44
  t = Thread.new { sleep 1; buffer << 4 }
45
45
  t0 = Time.now
46
46
  r = t.join(0.01)
47
47
  t = nil
48
48
 
49
49
  assert Time.now - t0 < 0.2
50
+ f.join
50
51
  assert_equal [1, 2, 3], buffer
51
52
  assert_nil r
52
53
  ensure
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.97'
4
+ version: '0.98'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-28 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler