polyphony 0.97 → 0.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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