diff --git a/moo/kernel/Socket.moo b/moo/kernel/Socket.moo index 4c9446f..8a818ff 100644 --- a/moo/kernel/Socket.moo +++ b/moo/kernel/Socket.moo @@ -248,8 +248,11 @@ class Socket(Object) from 'sck' method(#primitive) open(domain, type, proto). method(#primitive) _close. - method(#primitive) _connect(addr). - method(#primitive) endConnect. + method(#primitive) bind: addr. + method(#primitive) listen: backlog. + method(#primitive) accept: addr. + method(#primitive) _connect: addr. + method(#primitive) _socketError. method(#primitive) readBytes: bytes. method(#primitive) writeBytes: bytes. @@ -302,7 +305,7 @@ extend Socket } } - method asyncConnect: connectBlock + method connectTo: target do: connectBlock { | s1 s2 sa | @@ -310,15 +313,21 @@ extend Socket s2 := Semaphore new. sa := [:sem | -'UNSIGNALLLING ...........' dump. + + | connected | + + connected := false. System unsignal: s1; unsignal: s2; removeAsyncSemaphore: s1; removeAsyncSemaphore: s2. -'FINALIZING CONNECT' dump. - self endConnect. - connectBlock value: self value: (sem == s1) + if (sem == s1) + { + [ connected := (self _socketError == 0) ] ifCurtailed: [ connected := false ]. + }. + + connectBlock value: self value: connected. ]. s1 signalAction: sa. @@ -329,7 +338,7 @@ extend Socket signal: s2 afterSecs: 10; addAsyncSemaphore: s1; addAsyncSemaphore: s2. - self _connect((SocketAddress fromString: '192.168.1.1:80')). + self _connect: target. ] ifCurtailed: [ ## rollback sa value: s2. @@ -377,7 +386,9 @@ class MyObject(Object) { method(#class) main { - | s conact inact outact | + | conact inact outact accact | + + (SocketAddress fromString: '192.168.123.232:99') dump. '****************************' dump. @@ -427,9 +438,8 @@ thisProcess terminate. | data n | (* end of data -> 0. -no data -> -1. -has data -> 1 or moreailure indicated by primitive function 0x55a6210 - _integer_add - +no data -> -1. (e.g. EINPROGRESS) +has data -> 1 or more error -> exception *) @@ -439,7 +449,7 @@ error -> exception n := sck readBytes: data. if (n <= 0) { - if (n == 0) { sck close }. + if (n == 0) { sck close }. ## end of data break. } elsif (n > 0) @@ -465,10 +475,9 @@ error -> exception if (state) { 'CONNECTED NOW.............' dump. - s writeBytes: #[ $h, $e, $l, $l, $o, C'\n' ]. + sck writeBytes: #[ $h, $e, $l, $l, $o, $w, $o, C'\n' ]. + sck watchInput; watchOutput. - s watchInput. - s watchOutput. } else { @@ -477,17 +486,38 @@ error -> exception ]. ## ------------------------------------------------------ + accact := [:sck :state | + | newsck newaddr | + + newaddr := SocketAddress new. + newsck := sck accept: newaddr. +System log: 'new connection - '; logNl: newaddr. + newsck inputAction: inact; outputAction: outact. + newsck watchInput; watchOuptut. + ]. [ - s := Socket domain: Socket.Domain.INET type: Socket.Type.STREAM. - s inputAction: inact; outputAction: outact. - s asyncConnect: conact. + | s s2 | + [ + s := Socket domain: Socket.Domain.INET type: Socket.Type.STREAM. + s inputAction: inact; outputAction: outact. + s connectTo: (SocketAddress fromString: '127.0.0.1:9999') do: conact. - while (true) - { - System handleAsyncEvent. - }. - s close dump. + s2 := Socket domain: Socket.Domain.INET type: Socket.Type.STREAM. + s2 inputAction: accact. + s2 bind: (SocketAddress fromString: '0.0.0.0:9998'). + s2 listen: 10; watchInput. + + while (true) + { + System handleAsyncEvent. + }. + ] + ensure: + [ + if (s notNil) { s close }. + if (s2 notNil) { s2 close }. + ] ] on: Exception do: [:ex | ('Exception - ' & ex messageText) dump ]. diff --git a/moo/mod/sck-addr.c b/moo/mod/sck-addr.c index 6f77fb2..2b862a8 100644 --- a/moo/mod/sck-addr.c +++ b/moo/mod/sck-addr.c @@ -485,7 +485,6 @@ static moo_pfrc_t pf_from_string (moo_t* moo, moo_ooi_t nargs) return MOO_PF_FAILURE; } -MOO_DEBUG1(moo, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxx %O\n", rcv); MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; } diff --git a/moo/mod/sck.c b/moo/mod/sck.c index b752295..1342fea 100644 --- a/moo/mod/sck.c +++ b/moo/mod/sck.c @@ -114,30 +114,122 @@ static moo_pfrc_t pf_close_socket (moo_t* moo, moo_ooi_t nargs) static moo_pfrc_t pf_bind_socket (moo_t* moo, moo_ooi_t nargs) { oop_sck_t sck; - int fd, n; - + moo_oop_t arg; + int fd, enable; sck = (oop_sck_t)MOO_STACK_GETRCV(moo, nargs); + arg = MOO_STACK_GETARG(moo, nargs, 0); + MOO_PF_CHECK_RCV (moo, MOO_OOP_IS_POINTER(sck) && MOO_OBJ_BYTESOF(sck) >= (MOO_SIZEOF(*sck) - MOO_SIZEOF(moo_obj_t)) && MOO_OOP_IS_SMOOI(sck->handle)); + MOO_PF_CHECK_ARGS (moo, nargs, MOO_OBJ_IS_BYTE_POINTER(arg)); fd = MOO_OOP_TO_SMOOI(sck->handle); + if (fd <= -1) + { + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); + return MOO_PF_FAILURE; + } -#if 0 - n = bind(fd, &sin, MOO_SIZEOF(sin)); + enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, MOO_SIZEOF(int)) == -1 || + bind(fd, (struct sockaddr*)MOO_OBJ_GET_BYTE_SLOT(arg), moo_sck_addr_len((sck_addr_t*)MOO_OBJ_GET_BYTE_SLOT(arg))) == -1) + { + moo_seterrwithsyserr (moo, errno); + return MOO_PF_FAILURE; + } + + MOO_STACK_SETRETTORCV (moo, nargs); + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_accept_socket (moo_t* moo, moo_ooi_t nargs) +{ + oop_sck_t sck, newsck; + moo_oop_t arg; + sck_len_t addrlen; + int fd, newfd; + + sck = (oop_sck_t)MOO_STACK_GETRCV(moo, nargs); + arg = MOO_STACK_GETARG(moo, nargs, 0); + + MOO_PF_CHECK_RCV (moo, + MOO_OOP_IS_POINTER(sck) && + MOO_OBJ_BYTESOF(sck) >= (MOO_SIZEOF(*sck) - MOO_SIZEOF(moo_obj_t)) && + MOO_OOP_IS_SMOOI(sck->handle)); + MOO_PF_CHECK_ARGS (moo, nargs, MOO_OBJ_IS_BYTE_POINTER(arg)); + + fd = MOO_OOP_TO_SMOOI(sck->handle); + if (fd <= -1) + { + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); + return MOO_PF_FAILURE; + } + + addrlen = MOO_OBJ_GET_SIZE(arg); + newfd = accept(fd, (struct sockaddr*)MOO_OBJ_GET_BYTE_SLOT(arg), &addrlen); + if (newfd == -1) + { + moo_seterrwithsyserr (moo, errno); + return MOO_PF_FAILURE; + } + + newsck = (oop_sck_t)moo_instantiate (moo, MOO_OBJ_GET_CLASS(sck), MOO_NULL, 0); + if (!newsck) + { + close (newfd); + return MOO_PF_FAILURE; + } + + if (!MOO_IN_SMOOI_RANGE(newfd)) + { + /* the file descriptor is too big to be represented as a small integer */ + moo_seterrbfmt (moo, MOO_ERANGE, "socket handle %d not in the permitted range", newfd); + close (newfd); + return MOO_PF_FAILURE; + } + newsck->handle = MOO_SMOOI_TO_OOP(newfd); + + MOO_STACK_SETRETTORCV (moo, nargs); + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_listen_socket (moo_t* moo, moo_ooi_t nargs) +{ + oop_sck_t sck; + moo_oop_t arg; + int fd, n; + + sck = (oop_sck_t)MOO_STACK_GETRCV(moo, nargs); + arg = MOO_STACK_GETARG(moo, nargs, 0); + + MOO_PF_CHECK_RCV (moo, + MOO_OOP_IS_POINTER(sck) && + MOO_OBJ_BYTESOF(sck) >= (MOO_SIZEOF(*sck) - MOO_SIZEOF(moo_obj_t)) && + MOO_OOP_IS_SMOOI(sck->handle)); + MOO_PF_CHECK_ARGS (moo, nargs, MOO_OOP_IS_SMOOI(arg)); + + fd = MOO_OOP_TO_SMOOI(sck->handle); + if (fd <= -1) + { + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); + return MOO_PF_FAILURE; + } + + n = listen(fd, MOO_OOP_TO_SMOOI(arg)); if (n == -1) { moo_seterrwithsyserr (moo, errno); return MOO_PF_FAILURE; } -#endif MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; } + static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) { oop_sck_t sck; @@ -155,6 +247,11 @@ static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) MOO_PF_CHECK_ARGS (moo, nargs, MOO_OBJ_IS_BYTE_POINTER(arg)); fd = MOO_OOP_TO_SMOOI(sck->handle); + if (fd <= -1) + { + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); + return MOO_PF_FAILURE; + } oldfl = fcntl(fd, F_GETFL, 0); if (oldfl == -1 || fcntl(fd, F_SETFL, oldfl | O_NONBLOCK) == -1) goto oops_syserr; @@ -184,10 +281,11 @@ oops: return MOO_PF_FAILURE; } -static moo_pfrc_t pf_end_connect (moo_t* moo, moo_ooi_t nargs) +static moo_pfrc_t pf_get_socket_error (moo_t* moo, moo_ooi_t nargs) { oop_sck_t sck; - int fd; + int fd, ret; + sck_len_t len; sck = (oop_sck_t)MOO_STACK_GETRCV(moo, nargs); MOO_PF_CHECK_RCV (moo, @@ -197,30 +295,21 @@ static moo_pfrc_t pf_end_connect (moo_t* moo, moo_ooi_t nargs) ); fd = MOO_OOP_TO_SMOOI(sck->handle); - if (fd >= 0) + if (fd <= -1) { - socklen_t len; - int ret; - - len = MOO_SIZEOF(ret); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&ret, &len) == -1) - { - moo_seterrwithsyserr (moo, errno); - return MOO_PF_FAILURE; - } - - if (ret == EINPROGRESS) - { - return MOO_PF_FAILURE; - } - else if (ret != 0) - { - moo_seterrwithsyserr (moo, ret); - return MOO_PF_FAILURE; - } + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); + return MOO_PF_FAILURE; } - MOO_STACK_SETRETTORCV (moo, nargs); + len = MOO_SIZEOF(ret); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&ret, &len) == -1) + { + moo_seterrwithsyserr (moo, errno); + return MOO_PF_FAILURE; + } + + /* if ret == EINPROGRESS .. it's in progress */ + MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(ret)); return MOO_PF_SUCCESS; } @@ -241,14 +330,14 @@ static moo_pfrc_t pf_read_socket (moo_t* moo, moo_ooi_t nargs) fd = MOO_OOP_TO_SMOOI(sck->handle); if (fd <= -1) { - moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d\n", fd); + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); return MOO_PF_FAILURE; } buf = (moo_oop_byte_t)MOO_STACK_GETARG (moo, nargs, 0); if (!MOO_OBJ_IS_BYTE_POINTER(buf)) { - moo_seterrbfmt (moo, MOO_EINVAL, "buffer not a byte array - %O\n", buf); + moo_seterrbfmt (moo, MOO_EINVAL, "buffer not a byte array - %O", buf); return MOO_PF_FAILURE; } @@ -282,14 +371,14 @@ static moo_pfrc_t pf_write_socket (moo_t* moo, moo_ooi_t nargs) fd = MOO_OOP_TO_SMOOI(sck->handle); if (fd <= -1) { - moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d\n", fd); + moo_seterrbfmt (moo, MOO_EINVAL, "bad socket handle - %d", fd); return MOO_PF_FAILURE; } buf = (moo_oop_byte_t)MOO_STACK_GETARG (moo, nargs, 0); if (!MOO_OBJ_IS_BYTE_POINTER(buf)) { - moo_seterrbfmt (moo, MOO_EINVAL, "buffer not a byte array - %O\n", buf); + moo_seterrbfmt (moo, MOO_EINVAL, "buffer not a byte array - %O", buf); return MOO_PF_FAILURE; } @@ -324,13 +413,15 @@ struct fnctab_t static moo_pfinfo_t pfinfos[] = { - { I, { 'b','i','n','d','\0' }, 0, { pf_bind_socket, 1, 1 } }, - { I, { 'c','l','o','s','e','\0' }, 0, { pf_close_socket, 0, 0 } }, - { I, { 'c','o','n','n','e','c','t','\0' }, 0, { pf_connect, 1, 1 } }, - { I, { 'e','n','d','C','o','n','n','e','c','t','\0' }, 0, { pf_end_connect, 0, 0 } }, - { I, { 'o','p','e','n','\0' }, 0, { pf_open_socket, 3, 3 } }, - { I, { 'r','e','a','d','B','y','t','e','s',':','\0' }, 0, { pf_read_socket, 1, 1 } }, - { I, { 'w','r','i','t','e','B','y','t','e','s',':','\0' }, 0, { pf_write_socket, 1, 1 } }, + { I, { 'a','c','c','e','p','t',':','\0' }, 0, { pf_accept_socket, 1, 1 } }, + { I, { 'b','i','n','d',':','\0' }, 0, { pf_bind_socket, 1, 1 } }, + { I, { 'c','l','o','s','e','\0' }, 0, { pf_close_socket, 0, 0 } }, + { I, { 'c','o','n','n','e','c','t',':','\0' }, 0, { pf_connect, 1, 1 } }, + { I, { 'l','i','s','t','e','n',':','\0' }, 0, { pf_listen_socket, 1, 1 } }, + { I, { 'o','p','e','n','\0' }, 0, { pf_open_socket, 3, 3 } }, + { I, { 'r','e','a','d','B','y','t','e','s',':','\0' }, 0, { pf_read_socket, 1, 1 } }, + { I, { 's','o','c','k','e','t','E','r','r','o','r','\0' }, 0, { pf_get_socket_error, 0, 0 } }, + { I, { 'w','r','i','t','e','B','y','t','e','s',':','\0' }, 0, { pf_write_socket, 1, 1 } } }; /* ------------------------------------------------------------------------ */ @@ -359,5 +450,3 @@ int moo_mod_sck (moo_t* moo, moo_mod_t* mod) mod->ctx = MOO_NULL; return 0; } - -