diff --git a/stio/lib/main.c b/stio/lib/main.c index 7f454ec..55a8ad5 100644 --- a/stio/lib/main.c +++ b/stio/lib/main.c @@ -97,23 +97,23 @@ static void tcp_on_disconnect (stio_dev_tcp_t* tcp) { if (tcp->state & STIO_DEV_TCP_CONNECTING) { - printf ("TCP DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", tcp->sck); + printf ("TCP DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", (int)tcp->sck); } else if (tcp->state & STIO_DEV_TCP_LISTENING) { - printf ("SHUTTING DOWN THE SERVER SOCKET(%d)...\n", tcp->sck); + printf ("SHUTTING DOWN THE SERVER SOCKET(%d)...\n", (int)tcp->sck); } else if (tcp->state & STIO_DEV_TCP_CONNECTED) { - printf ("CLIENT ORIGINATING FROM HERE GOT DISCONNECTED(%d).......\n", tcp->sck); + printf ("CLIENT ORIGINATING FROM HERE GOT DISCONNECTED(%d).......\n", (int)tcp->sck); } else if (tcp->state & STIO_DEV_TCP_ACCEPTED) { - printf ("CLIENT BEING SERVED GOT DISCONNECTED(%d).......\n", tcp->sck); + printf ("CLIENT BEING SERVED GOT DISCONNECTED(%d).......\n", (int)tcp->sck); } else { - printf ("TCP DISCONNECTED - THIS MUST NOT HAPPEN (%d)\n", tcp->sck); + printf ("TCP DISCONNECTED - THIS MUST NOT HAPPEN (%d - %x)\n", (int)tcp->sck, (unsigned int)tcp->state); } } static int tcp_on_connect (stio_dev_tcp_t* tcp) @@ -143,8 +143,6 @@ printf ("SEDING TIMED OUT...........\n"); } else { - - ts = (tcp_server_t*)(tcp + 1); printf (">>> SENT MESSAGE %d of length %ld\n", ts->tally, (long int)wrlen); @@ -194,12 +192,23 @@ printf ("DISABLING READING..............................\n"); /* ========================================================================= */ -static int sck_on_read (stio_dev_sck_t* dev, const void* buf, stio_len_t len, const stio_sckadr_t* srcadr) +static int arp_sck_on_read (stio_dev_sck_t* dev, const void* data, stio_len_t dlen, const stio_adr_t* srcadr) { + stio_etharp_pkt_t* eap; + + if (dlen < STIO_SIZEOF(*eap)) return 0; /* drop */ + + eap = (stio_etharp_pkt_t*)data; + printf ("ARP OPCODE: %d", ntohs(eap->arphdr.opcode)); + printf (" SHA: %02X:%02X:%02X:%02X:%02X:%02X", eap->arppld.sha[0], eap->arppld.sha[1], eap->arppld.sha[2], eap->arppld.sha[3], eap->arppld.sha[4], eap->arppld.sha[5]); + printf (" SPA: %d.%d.%d.%d", eap->arppld.spa[0], eap->arppld.spa[1], eap->arppld.spa[2], eap->arppld.spa[3]); + printf (" THA: %02X:%02X:%02X:%02X:%02X:%02X", eap->arppld.tha[0], eap->arppld.tha[1], eap->arppld.tha[2], eap->arppld.tha[3], eap->arppld.tha[4], eap->arppld.tha[5]); + printf (" TPA: %d.%d.%d.%d", eap->arppld.tpa[0], eap->arppld.tpa[1], eap->arppld.tpa[2], eap->arppld.tpa[3]); + printf ("\n"); return 0; } -static int sck_on_write (stio_dev_sck_t* dev, stio_len_t wrlen, void* wrctx) +static int arp_sck_on_write (stio_dev_sck_t* dev, stio_len_t wrlen, void* wrctx) { return 0; } @@ -322,8 +331,8 @@ int main () memset (&sck_make, 0, STIO_SIZEOF(sck_make)); sck_make.type = STIO_DEV_SCK_ARP; //sck_make.type = STIO_DEV_SCK_ARP_DGRAM; - sck_make.on_write = sck_on_write; - sck_make.on_read = sck_on_read; + sck_make.on_write = arp_sck_on_write; + sck_make.on_read = arp_sck_on_read; sck = stio_dev_sck_make (stio, 0, &sck_make); if (!sck) { @@ -341,16 +350,15 @@ int main () adr.ptr = &sll; adr.len = sizeof(sll); sll.sll_family = AF_PACKET; - //sll.sll_protocol = STIO_CONST_HTON16(0x0003); /* P_ALL */ - sll.sll_protocol = STIO_CONST_HTON16(STIO_ETHHDR_PROTO_ARP); - sll.sll_hatype = STIO_CONST_HTON16(STIO_ARPHDR_HTYPE_ETH); +// sll.sll_protocol = STIO_CONST_HTON16(STIO_ETHHDR_PROTO_ARP); +// sll.sll_hatype = STIO_CONST_HTON16(STIO_ARPHDR_HTYPE_ETH); sll.sll_halen = STIO_ETHADR_LEN; memcpy (sll.sll_addr, "\xFF\xFF\xFF\xFF\xFF\xFF", sll.sll_halen); sll.sll_ifindex = if_nametoindex ("enp0s25.3"); /* if unicast ... */ //sll.sll_pkttype = PACKET_OTHERHOST; - sll.sll_pkttype = PACKET_BROADCAST; +// sll.sll_pkttype = PACKET_BROADCAST; memset (ðarp, 0, sizeof(etharp)); diff --git a/stio/lib/stio-arp.c b/stio/lib/stio-arp.c index 90248fe..a32e6da 100644 --- a/stio/lib/stio-arp.c +++ b/stio/lib/stio-arp.c @@ -158,7 +158,6 @@ static int arp_on_read (stio_dev_t* dev, const void* data, stio_len_t len) { printf ("dATA received %d bytes\n", (int)len); return 0; - } static int arp_on_write (stio_dev_t* dev, stio_len_t wrlen, void* wrctx) diff --git a/stio/lib/stio-arp.h b/stio/lib/stio-arp.h index 12c6f5f..eab8eb9 100644 --- a/stio/lib/stio-arp.h +++ b/stio/lib/stio-arp.h @@ -30,7 +30,6 @@ #include #include -typedef struct stio_dev_arp_t stio_dev_arp_t; #define STIO_ETHHDR_PROTO_IP4 0x0800 #define STIO_ETHHDR_PROTO_ARP 0x0806 @@ -80,8 +79,8 @@ struct stio_etharp_pkt_t stio_etharp_t arppld; }; typedef struct stio_etharp_pkt_t stio_etharp_pkt_t; -#pragma pack(pop) +#pragma pack(pop) #if 0 typedef int (*stio_dev_arp_on_read_t) (stio_dev_arp_t* dev, stio_pkt_arp_t* pkt, stio_len_t len); diff --git a/stio/lib/stio-prv.h b/stio/lib/stio-prv.h index 01fce37..23100a1 100644 --- a/stio/lib/stio-prv.h +++ b/stio/lib/stio-prv.h @@ -42,18 +42,12 @@ #define STIO_ASSERT assert -#define STIO_USE_TMRJOB_IDXPTR - struct stio_tmrjob_t { void* ctx; stio_ntime_t when; stio_tmrjob_handler_t handler; -#if defined(STIO_USE_TMRJOB_IDXPTR) stio_tmridx_t* idxptr; /* pointer to the index holder */ -#else - stio_tmrjob_updater_t updater; -#endif }; #define STIO_TMRIDX_INVALID ((stio_tmridx_t)-1) diff --git a/stio/lib/stio-sck.c b/stio/lib/stio-sck.c index 3cb03da..48f42c4 100644 --- a/stio/lib/stio-sck.c +++ b/stio/lib/stio-sck.c @@ -111,40 +111,66 @@ int stio_getsckadrinfo (stio_t* stio, const stio_sckadr_t* addr, stio_scklen_t* /* ========================================================================= */ + +#define IS_STATEFUL(sck) ((sck)->dev_capa & STIO_DEV_CAPA_STREAM) + struct sck_type_map_t { int domain; int type; int proto; -} sck_type_map[] = -{ - { AF_INET, SOCK_STREAM, 0 }, - { AF_INET6, SOCK_STREAM, 0 }, - { AF_INET, SOCK_DGRAM, 0 }, - { AF_INET6, SOCK_DGRAM, 0 }, - - { AF_PACKET, SOCK_RAW, STIO_CONST_HTON16(0x0806) }, - { AF_PACKET, SOCK_DGRAM, STIO_CONST_HTON16(0x0806) } + int extra_dev_capa; + int sck_capa; }; +static struct sck_type_map_t sck_type_map[] = +{ + { AF_INET, SOCK_STREAM, 0, STIO_DEV_CAPA_STREAM | STIO_DEV_CAPA_OUT_QUEUED }, + { AF_INET6, SOCK_STREAM, 0, STIO_DEV_CAPA_STREAM | STIO_DEV_CAPA_OUT_QUEUED }, + { AF_INET, SOCK_DGRAM, 0, 0 }, + { AF_INET6, SOCK_DGRAM, 0, 0 }, + + { AF_PACKET, SOCK_RAW, STIO_CONST_HTON16(0x0806), 0 }, + { AF_PACKET, SOCK_DGRAM, STIO_CONST_HTON16(0x0806), 0 } +}; + +/* ======================================================================== */ + +static void tmr_connect_handle (stio_t* stio, const stio_ntime_t* now, stio_tmrjob_t* job) +{ + stio_dev_sck_t* rdev = (stio_dev_sck_t*)job->ctx; + + STIO_ASSERT (IS_STATEFUL(rdev)); + + if (rdev->state & STIO_DEV_SCK_CONNECTING) + { + /* the state check for STIO_DEV_TCP_CONNECTING is actually redundant + * as it must not be fired after it gets connected. the timer job + * doesn't need to be deleted when it gets connected for this check + * here. this libarary, however, deletes the job when it gets + * connected. */ + stio_dev_sck_halt (rdev); + } +} + +/* ======================================================================== */ + static int dev_sck_make (stio_dev_t* dev, void* ctx) { stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; stio_dev_sck_make_t* arg = (stio_dev_sck_make_t*)ctx; - - if (arg->type < 0 && arg->type >= STIO_COUNTOF(sck_type_map)) - { - dev->stio->errnum = STIO_EINVAL; - return -1; - } + STIO_ASSERT (arg->type >= 0 && arg->type < STIO_COUNTOF(sck_type_map)); rdev->sck = stio_openasyncsck (dev->stio, sck_type_map[arg->type].domain, sck_type_map[arg->type].type, sck_type_map[arg->type].proto); if (rdev->sck == STIO_SCKHND_INVALID) goto oops; - rdev->dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT; + rdev->dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT | sck_type_map[arg->type].extra_dev_capa; rdev->on_write = arg->on_write; rdev->on_read = arg->on_read; + rdev->type = arg->type; + + rdev->tmridx_connect = STIO_TMRIDX_INVALID; return 0; oops: @@ -156,9 +182,40 @@ oops: return -1; } +static int dev_sck_make_client (stio_dev_t* dev, void* ctx) +{ + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + stio_syshnd_t* sck = (stio_syshnd_t*)ctx; + + rdev->sck = *sck; + if (stio_makesckasync (rdev->stio, rdev->sck) <= -1) return -1; + + return 0; +} + static void dev_sck_kill (stio_dev_t* dev) { stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + + if (IS_STATEFUL(rdev)) + { + if (rdev->state & (STIO_DEV_SCK_ACCEPTED | STIO_DEV_SCK_CONNECTED | STIO_DEV_SCK_CONNECTING | STIO_DEV_SCK_LISTENING)) + { + if (rdev->on_disconnect) rdev->on_disconnect (rdev); + } + + if (rdev->tmridx_connect != STIO_TMRIDX_INVALID) + { + stio_deltmrjob (dev->stio, rdev->tmridx_connect); + STIO_ASSERT (rdev->tmridx_connect == STIO_TMRIDX_INVALID); + } + } + else + { + STIO_ASSERT (rdev->state == 0); + STIO_ASSERT (rdev->tmridx_connect == STIO_TMRIDX_INVALID); + } + if (rdev->sck != STIO_SCKHND_INVALID) { stio_closeasyncsck (rdev->stio, rdev->sck); @@ -172,11 +229,29 @@ static stio_syshnd_t dev_sck_getsyshnd (stio_dev_t* dev) return (stio_syshnd_t)rdev->sck; } -static int dev_sck_read (stio_dev_t* dev, void* buf, stio_len_t* len, stio_adr_t* srcadr) +static int dev_sck_read_stateful (stio_dev_t* dev, void* buf, stio_len_t* len, stio_adr_t* srcadr) +{ + stio_dev_sck_t* tcp = (stio_dev_sck_t*)dev; + ssize_t x; + + x = recv (tcp->sck, buf, *len, 0); + if (x == -1) + { + if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data available */ + if (errno == EINTR) return 0; + tcp->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + *len = x; + return 1; +} + +static int dev_sck_read_stateless (stio_dev_t* dev, void* buf, stio_len_t* len, stio_adr_t* srcadr) { stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; stio_scklen_t srcadrlen; - int x; + ssize_t x; srcadrlen = srcadr->len; x = recvfrom (rdev->sck, buf, *len, 0, srcadr->ptr, &srcadrlen); @@ -193,7 +268,44 @@ static int dev_sck_read (stio_dev_t* dev, void* buf, stio_len_t* len, stio_adr_t return 1; } -static int dev_sck_write (stio_dev_t* dev, const void* data, stio_len_t* len, const stio_adr_t* dstadr) + +static int dev_sck_write_stateful (stio_dev_t* dev, const void* data, stio_len_t* len, const stio_adr_t* dstadr) +{ + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + ssize_t x; + int flags = 0; + + if (*len <= 0) + { + /* it's a writing finish indicator. close the writing end of + * the socket, probably leaving it in the half-closed state */ + if (shutdown (rdev->sck, SHUT_WR) == -1) + { + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + return 1; + } + + /* TODO: flags MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB, MSG_NOSIGNAL */ +#if defined(MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif + x = send (rdev->sck, data, *len, flags); + if (x == -1) + { + if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data can be written */ + if (errno == EINTR) return 0; + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + *len = x; + return 1; +} + +static int dev_sck_write_stateless (stio_dev_t* dev, const void* data, stio_len_t* len, const stio_adr_t* dstadr) { stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; ssize_t x; @@ -211,64 +323,427 @@ static int dev_sck_write (stio_dev_t* dev, const void* data, stio_len_t* len, co return 1; } - static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg) { + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + + switch (cmd) + { + case STIO_DEV_SCK_BIND: + { + stio_dev_sck_bind_t* bnd = (stio_dev_sck_bind_t*)arg; + struct sockaddr* sa = (struct sockaddr*)&bnd->addr; + stio_scklen_t sl; + stio_sckfam_t fam; + int x; + + if (stio_getsckadrinfo (dev->stio, &bnd->addr, &sl, &fam) <= -1) return -1; + + /* the socket is already non-blocking */ + x = bind (rdev->sck, sa, sl); + if (x == -1) + { + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + return 0; + } + + case STIO_DEV_SCK_CONNECT: + { + stio_dev_sck_connect_t* conn = (stio_dev_sck_connect_t*)arg; + struct sockaddr* sa = (struct sockaddr*)&conn->addr; + stio_scklen_t sl; + int x; + + if (!IS_STATEFUL(rdev)) + { + dev->stio->errnum = STIO_ENOCAPA; + return -1; + } + + if (sa->sa_family == AF_INET) sl = STIO_SIZEOF(struct sockaddr_in); + else if (sa->sa_family == AF_INET6) sl = STIO_SIZEOF(struct sockaddr_in6); + else + { + dev->stio->errnum = STIO_EINVAL; + return -1; + } + + /* the socket is already non-blocking */ + x = connect (rdev->sck, sa, sl); + if (x == -1) + { + if (errno == EINPROGRESS || errno == EWOULDBLOCK) + { + if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) >= 0) + { + stio_tmrjob_t tmrjob; + + if (!stio_isnegtime(&conn->tmout)) + { + STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob)); + tmrjob.ctx = rdev; + stio_gettime (&tmrjob.when); + stio_addtime (&tmrjob.when, &conn->tmout, &tmrjob.when); + tmrjob.handler = tmr_connect_handle; + tmrjob.idxptr = &rdev->tmridx_connect; + + STIO_ASSERT (rdev->tmridx_connect == STIO_TMRIDX_INVALID); + rdev->tmridx_connect = stio_instmrjob (rdev->stio, &tmrjob); + if (rdev->tmridx_connect == STIO_TMRIDX_INVALID) + { + stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN); + /* event manipulation failure can't be handled properly. so ignore it. + * anyway, it's already in a failure condition */ + return -1; + } + } + + rdev->state |= STIO_DEV_SCK_CONNECTING; + rdev->peer = conn->addr; + rdev->on_connect = conn->on_connect; + rdev->on_disconnect = conn->on_disconnect; + return 0; + } + } + + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + /* connected immediately */ + rdev->state |= STIO_DEV_SCK_CONNECTED; + rdev->peer = conn->addr; + rdev->on_connect = conn->on_connect; + rdev->on_disconnect = conn->on_disconnect; + return 0; + } + + case STIO_DEV_SCK_LISTEN: + { + stio_dev_sck_listen_t* lstn = (stio_dev_sck_listen_t*)arg; + int x; + + if (!IS_STATEFUL(rdev)) + { + dev->stio->errnum = STIO_ENOCAPA; + return -1; + } + + x = listen (rdev->sck, lstn->backlogs); + if (x == -1) + { + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + rdev->state |= STIO_DEV_SCK_LISTENING; + rdev->on_connect = lstn->on_connect; + rdev->on_disconnect = lstn->on_disconnect; + return 0; + } + } + return 0; } -static stio_dev_mth_t dev_mth_sck = +static stio_dev_mth_t dev_mth_sck_stateless = { dev_sck_make, dev_sck_kill, dev_sck_getsyshnd, - dev_sck_read, - dev_sck_write, + dev_sck_read_stateless, + dev_sck_write_stateless, dev_sck_ioctl, /* ioctl */ }; +static stio_dev_mth_t dev_mth_sck_stateful = +{ + dev_sck_make, + dev_sck_kill, + dev_sck_getsyshnd, + + dev_sck_read_stateful, + dev_sck_write_stateful, + dev_sck_ioctl, /* ioctl */ +}; + + +static stio_dev_mth_t dev_mth_clisck = +{ + dev_sck_make_client, + dev_sck_kill, + dev_sck_getsyshnd, + + dev_sck_read_stateful, + dev_sck_write_stateful, + dev_sck_ioctl +}; /* ========================================================================= */ -static int dev_evcb_sck_ready (stio_dev_t* dev, int events) +static int dev_evcb_sck_ready_stateful (stio_dev_t* dev, int events) { -/* TODO: ... */ - if (events & STIO_DEV_EVENT_ERR) printf ("SCK READY ERROR.....\n"); - if (events & STIO_DEV_EVENT_HUP) printf ("SCK READY HANGUP.....\n"); - if (events & STIO_DEV_EVENT_PRI) printf ("SCK READY PRI.....\n"); - if (events & STIO_DEV_EVENT_IN) printf ("SCK READY IN.....\n"); - if (events & STIO_DEV_EVENT_OUT) printf ("SCK READY OUT.....\n"); + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + if (events & STIO_DEV_EVENT_ERR) + { + int errcode; + stio_scklen_t len; + + len = STIO_SIZEOF(errcode); + if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) + { + /* the error number is set to the socket error code. + * errno resulting from getsockopt() doesn't reflect the actual + * socket error. so errno is not used to set the error number. + * instead, the generic device error STIO_EDEVERRR is used */ + rdev->stio->errnum = STIO_EDEVERR; + } + else + { + rdev->stio->errnum = stio_syserrtoerrnum (errcode); + } + return -1; + } + + /* this socket can connect */ + if (rdev->state & STIO_DEV_SCK_CONNECTING) + { + if (events & STIO_DEV_EVENT_HUP) + { + /* device hang-up */ + rdev->stio->errnum = STIO_EDEVHUP; + return -1; + } + else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN)) + { + /* invalid event masks. generic device error */ + rdev->stio->errnum = STIO_EDEVERR; + return -1; + } + else if (events & STIO_DEV_EVENT_OUT) + { + int errcode; + stio_scklen_t len; + + STIO_ASSERT (!(rdev->state & STIO_DEV_SCK_CONNECTED)); + + len = STIO_SIZEOF(errcode); + if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) + { + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + else if (errcode == 0) + { + rdev->state &= ~STIO_DEV_SCK_CONNECTING; + rdev->state |= STIO_DEV_SCK_CONNECTED; + + if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_RENEW, 0) <= -1) return -1; + + if (rdev->tmridx_connect != STIO_TMRIDX_INVALID) + { + stio_deltmrjob (rdev->stio, rdev->tmridx_connect); + STIO_ASSERT (rdev->tmridx_connect == STIO_TMRIDX_INVALID); + } + + if (rdev->on_connect (rdev) <= -1) + { + printf ("ON_CONNECTE HANDLER RETURNEF FAILURE...\n"); + return -1; + } + } + else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK) + { + /* still in progress */ + } + else + { + rdev->stio->errnum = stio_syserrtoerrnum(errcode); + return -1; + } + } + + return 0; /* success but don't invoke on_read() */ + } + else if (rdev->state & STIO_DEV_SCK_LISTENING) + { + if (events & STIO_DEV_EVENT_HUP) + { + /* device hang-up */ + rdev->stio->errnum = STIO_EDEVHUP; + return -1; + } + else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_OUT)) + { + rdev->stio->errnum = STIO_EDEVERR; + return -1; + } + else if (events & STIO_DEV_EVENT_IN) + { + stio_sckhnd_t clisck; + stio_sckadr_t peer; + stio_scklen_t addrlen; + stio_dev_sck_t* clidev; + + /* this is a server(lisening) socket */ + + addrlen = STIO_SIZEOF(peer); + clisck = accept (rdev->sck, (struct sockaddr*)&peer, &addrlen); + if (clisck == STIO_SCKHND_INVALID) + { + if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; + if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */ + + rdev->stio->errnum = stio_syserrtoerrnum(errno); + return -1; + } + + /* use rdev->dev_size when instantiating a client sck device + * instead of STIO_SIZEOF(stio_dev_sck_t). therefore, the + * extension area as big as that of the master sck device + * is created in the client sck device */ + clidev = (stio_dev_sck_t*)stio_makedev (rdev->stio, rdev->dev_size, &dev_mth_clisck, rdev->dev_evcb, &clisck); + if (!clidev) + { + close (clisck); + return -1; + } + + clidev->dev_capa |= STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT | STIO_DEV_CAPA_STREAM; + clidev->state |= STIO_DEV_SCK_ACCEPTED; + clidev->peer = peer; + /*clidev->parent = sck;*/ + + /* inherit some event handlers from the parent. + * you can still change them inside the on_connect handler */ + clidev->on_connect = rdev->on_connect; + clidev->on_disconnect = rdev->on_disconnect; + clidev->on_write = rdev->on_write; + clidev->on_read = rdev->on_read; + + clidev->tmridx_connect = STIO_TMRIDX_INVALID; + if (clidev->on_connect(clidev) <= -1) stio_dev_sck_halt (clidev); + + return 0; /* success but don't invoke on_read() */ + } + } + else if (events & STIO_DEV_EVENT_HUP) + { + if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT)) + { + /* probably half-open? */ + return 1; + } + + rdev->stio->errnum = STIO_EDEVHUP; + return -1; + } + + return 1; /* the device is ok. carry on reading or writing */ +} + +static int dev_evcb_sck_ready_stateless (stio_dev_t* dev, int events) +{ + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + + if (events & STIO_DEV_EVENT_ERR) + { + int errcode; + stio_scklen_t len; + + len = STIO_SIZEOF(errcode); + if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) + { + /* the error number is set to the socket error code. + * errno resulting from getsockopt() doesn't reflect the actual + * socket error. so errno is not used to set the error number. + * instead, the generic device error STIO_EDEVERRR is used */ + rdev->stio->errnum = STIO_EDEVERR; + } + else + { + rdev->stio->errnum = stio_syserrtoerrnum (errcode); + } + return -1; + } + else if (events & STIO_DEV_EVENT_HUP) + { + rdev->stio->errnum = STIO_EDEVHUP; + return -1; + } return 1; /* the device is ok. carry on reading or writing */ } static int dev_evcb_sck_on_read (stio_dev_t* dev, const void* data, stio_len_t dlen, const stio_adr_t* adr) { -printf ("dATA received %d bytes\n", (int)dlen); - return 0; - + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + return rdev->on_read (rdev, data, dlen, adr); } static int dev_evcb_sck_on_write (stio_dev_t* dev, stio_len_t wrlen, void* wrctx, const stio_adr_t* adr) { - return 0; - + stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev; + return rdev->on_write (rdev, wrlen, wrctx); } -static stio_dev_evcb_t dev_evcb_sck = +static stio_dev_evcb_t dev_evcb_sck_stateful = { - dev_evcb_sck_ready, + dev_evcb_sck_ready_stateful, dev_evcb_sck_on_read, dev_evcb_sck_on_write }; -/* ======================================================================== */ - -stio_dev_sck_t* stio_dev_sck_make (stio_t* stio, stio_size_t xtnsize, const stio_dev_sck_make_t* data) +static stio_dev_evcb_t dev_evcb_sck_stateless = { - return (stio_dev_sck_t*)stio_makedev (stio, STIO_SIZEOF(stio_dev_sck_t) + xtnsize, &dev_mth_sck, &dev_evcb_sck, (void*)data); + dev_evcb_sck_ready_stateless, + dev_evcb_sck_on_read, + dev_evcb_sck_on_write +}; + +/* ========================================================================= */ + +stio_dev_sck_t* stio_dev_sck_make (stio_t* stio, stio_size_t xtnsize, const stio_dev_sck_make_t* mkinf) +{ + stio_dev_sck_t* rdev; + + + if (mkinf->type < 0 && mkinf->type >= STIO_COUNTOF(sck_type_map)) + { + stio->errnum = STIO_EINVAL; + return STIO_NULL; + } + + if (sck_type_map[mkinf->type].extra_dev_capa & STIO_DEV_CAPA_STREAM) /* can't use the IS_STATEFUL() macro yet */ + { + rdev = (stio_dev_sck_t*)stio_makedev (stio, STIO_SIZEOF(stio_dev_sck_t) + xtnsize, &dev_mth_sck_stateful, &dev_evcb_sck_stateful, (void*)mkinf); + } + else + { + rdev = (stio_dev_sck_t*)stio_makedev (stio, STIO_SIZEOF(stio_dev_sck_t) + xtnsize, &dev_mth_sck_stateless, &dev_evcb_sck_stateless, (void*)mkinf); + } + + return rdev; +} + +int stio_dev_sck_bind (stio_dev_sck_t* dev, stio_dev_sck_bind_t* info) +{ + return stio_dev_ioctl ((stio_dev_t*)dev, STIO_DEV_SCK_BIND, info); +} + +int stio_dev_sck_connect (stio_dev_sck_t* dev, stio_dev_sck_connect_t* info) +{ + return stio_dev_ioctl ((stio_dev_t*)dev, STIO_DEV_SCK_CONNECT, info); +} + +int stio_dev_sck_listen (stio_dev_sck_t* dev, stio_dev_sck_listen_t* info) +{ + return stio_dev_ioctl ((stio_dev_t*)dev, STIO_DEV_SCK_LISTEN, info); } int stio_dev_sck_write (stio_dev_sck_t* dev, const void* data, stio_len_t dlen, void* wrctx, const stio_adr_t* dstadr) diff --git a/stio/lib/stio-sck.h b/stio/lib/stio-sck.h index 41ad259..186df3f 100644 --- a/stio/lib/stio-sck.h +++ b/stio/lib/stio-sck.h @@ -80,11 +80,40 @@ typedef int stio_sckfam_t; /* ========================================================================= */ +enum stio_dev_sck_ioctl_cmd_t +{ + STIO_DEV_SCK_BIND, + STIO_DEV_SCK_CONNECT, + STIO_DEV_SCK_LISTEN +}; +typedef enum stio_dev_sck_ioctl_cmd_t stio_dev_sck_ioctl_cmd_t; + + +enum stio_dev_sck_state_t +{ + STIO_DEV_SCK_CONNECTING = (1 << 0), + STIO_DEV_SCK_CONNECTED = (1 << 1), + STIO_DEV_SCK_LISTENING = (1 << 2), + STIO_DEV_SCK_ACCEPTED = (1 << 3) +}; +typedef enum stio_dev_sck_state_t stio_dev_sck_state_t; typedef struct stio_dev_sck_t stio_dev_sck_t; -typedef int (*stio_dev_sck_on_read_t) (stio_dev_sck_t* dev, const void* data, stio_len_t dlen, const stio_sckadr_t* srcadr); -typedef int (*stio_dev_sck_on_write_t) (stio_dev_sck_t* dev, stio_len_t wrlen, void* wrctx); +typedef int (*stio_dev_sck_on_read_t) ( + stio_dev_sck_t* dev, + const void* data, + stio_len_t dlen, + const stio_adr_t* srcadr +); +typedef int (*stio_dev_sck_on_write_t) ( + stio_dev_sck_t* dev, + stio_len_t wrlen, + void* wrctx +); + +typedef int (*stio_dev_sck_on_connect_t) (stio_dev_sck_t* dev); +typedef void (*stio_dev_sck_on_disconnect_t) (stio_dev_sck_t* dev); enum stio_dev_sck_type_t { @@ -106,20 +135,64 @@ struct stio_dev_sck_make_t stio_dev_sck_on_read_t on_read; }; +typedef struct stio_dev_sck_bind_t stio_dev_sck_bind_t; +struct stio_dev_sck_bind_t +{ + int opts; /* TODO: REUSEADDR , TRANSPARENT, etc or someting?? */ + stio_sckadr_t addr; + /* TODO: add device name for BIND_TO_DEVICE */ +}; + +typedef struct stio_dev_sck_connect_t stio_dev_sck_connect_t; +struct stio_dev_sck_connect_t +{ + stio_sckadr_t addr; + stio_ntime_t tmout; /* connect timeout */ + stio_dev_sck_on_connect_t on_connect; + stio_dev_sck_on_disconnect_t on_disconnect; +}; + +typedef struct stio_dev_sck_listen_t stio_dev_sck_listen_t; +struct stio_dev_sck_listen_t +{ + int backlogs; + stio_dev_sck_on_connect_t on_connect; /* optional, but new connections are dropped immediately without this */ + stio_dev_sck_on_disconnect_t on_disconnect; /* should on_discconneted be part of on_accept_t??? */ +}; + +typedef struct stio_dev_sck_accept_t stio_dev_sck_accept_t; +struct stio_dev_sck_accept_t +{ + stio_syshnd_t sck; +/* TODO: add timeout */ + stio_sckadr_t peer; +}; + + + struct stio_dev_sck_t { STIO_DEV_HEADERS; + stio_dev_sck_type_t type; stio_sckhnd_t sck; + stio_dev_sck_on_write_t on_write; stio_dev_sck_on_read_t on_read; -}; + int state; + /** return 0 on succes, -1 on failure/ + * called on a new tcp device for an accepted client or + * on a tcp device conntected to a remote server */ + stio_dev_sck_on_connect_t on_connect; + stio_dev_sck_on_disconnect_t on_disconnect; + stio_tmridx_t tmridx_connect; + stio_sckadr_t peer; +}; #ifdef __cplusplus extern "C" { #endif - STIO_EXPORT stio_sckhnd_t stio_openasyncsck ( stio_t* stio, int domain, @@ -149,7 +222,22 @@ STIO_EXPORT int stio_getsckadrinfo ( STIO_EXPORT stio_dev_sck_t* stio_dev_sck_make ( stio_t* stio, stio_size_t xtnsize, - const stio_dev_sck_make_t* data + const stio_dev_sck_make_t* info +); + +STIO_EXPORT int stio_dev_sck_bind ( + stio_dev_sck_t* dev, + stio_dev_sck_bind_t* info +); + +STIO_EXPORT int stio_dev_sck_connect ( + stio_dev_sck_t* dev, + stio_dev_sck_connect_t* info +); + +STIO_EXPORT int stio_dev_sck_listen ( + stio_dev_sck_t* dev, + stio_dev_sck_listen_t* info ); STIO_EXPORT int stio_dev_sck_write ( @@ -169,6 +257,45 @@ STIO_EXPORT int stio_dev_sck_timedwrite ( const stio_adr_t* dstadr ); +#if defined(STIO_HAVE_INLINE) + +static STIO_INLINE void stio_dev_sck_halt (stio_dev_sck_t* sck) +{ + stio_dev_halt ((stio_dev_t*)sck); + +} + +static STIO_INLINE int stio_dev_sck_read (stio_dev_sck_t* sck, int enabled) +{ + return stio_dev_read ((stio_dev_t*)sck, enabled); +} + +/* +static STIO_INLINE int stio_dev_sck_write (stio_dev_sck_t* sck, const void* data, stio_len_t len, void* wrctx, const stio_adr_t* dstadr) +{ + return stio_dev_write ((stio_dev_t*)sck, data, len, wrctx, STIO_NULL); +} + +static STIO_INLINE int stio_dev_sck_timedwrite (stio_dev_sck_t* sck, const void* data, stio_len_t len, const stio_ntime_t* tmout, void* wrctx) +{ + return stio_dev_timedwrite ((stio_dev_t*)sck, data, len, tmout, wrctx, STIO_NULL); +} +*/ + + +#else + +#define stio_dev_sck_halt(sck) stio_dev_halt((stio_dev_t*)sck) +#define stio_dev_sck_read(sck,enabled) stio_dev_read((stio_dev_t*)sck, enabled) +/* +#define stio_dev_sck_write(sck,data,len,wrctx) stio_dev_write((stio_dev_t*)sck, data, len, wrctx, STIO_NULL) +#define stio_dev_sck_timedwrite(sck,data,len,tmout,wrctx) stio_dev_timedwrite((stio_dev_t*)sck, data, len, tmout, wrctx, STIO_NULL) +*/ + + + +#endif + #ifdef __cplusplus } diff --git a/stio/lib/stio-tcp.c b/stio/lib/stio-tcp.c index 285f445..ea3954d 100644 --- a/stio/lib/stio-tcp.c +++ b/stio/lib/stio-tcp.c @@ -182,17 +182,6 @@ static void tmr_connect_handle (stio_t* stio, const stio_ntime_t* now, stio_tmrj } } -#if defined(STIO_USE_TMRJOB_IDXPTR) -/* nothing to define */ -#else -static void tmr_connect_update (stio_t* stio, stio_tmridx_t old_index, stio_tmridx_t new_index, stio_tmrjob_t* job) -{ - stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)job->ctx; - tcp->tmridx_connect = new_index; -} -#endif - - static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; @@ -261,11 +250,7 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) stio_gettime (&tmrjob.when); stio_addtime (&tmrjob.when, &conn->tmout, &tmrjob.when); tmrjob.handler = tmr_connect_handle; - #if defined(STIO_USE_TMRJOB_IDXPTR) tmrjob.idxptr = &tcp->tmridx_connect; - #else - tmrjob.updater = tmr_connect_update; - #endif STIO_ASSERT (tcp->tmridx_connect == STIO_TMRIDX_INVALID); tcp->tmridx_connect = stio_instmrjob (tcp->stio, &tmrjob); diff --git a/stio/lib/stio-tcp.h b/stio/lib/stio-tcp.h index 050b27c..2582e2e 100644 --- a/stio/lib/stio-tcp.h +++ b/stio/lib/stio-tcp.h @@ -50,7 +50,6 @@ typedef enum stio_dev_tcp_state_t stio_dev_tcp_state_t; typedef struct stio_dev_tcp_t stio_dev_tcp_t; typedef int (*stio_dev_tcp_on_connect_t) (stio_dev_tcp_t* dev); -typedef void (*stio_dev_tcp_on_accepted_t) (stio_dev_tcp_t* dev, stio_dev_tcp_t* clidev); typedef void (*stio_dev_tcp_on_disconnect_t) (stio_dev_tcp_t* dev); typedef int (*stio_dev_tcp_on_read_t) (stio_dev_tcp_t* dev, const void* data, stio_len_t len); diff --git a/stio/lib/stio-tmr.c b/stio/lib/stio-tmr.c index 4a7b142..a2c46e8 100644 --- a/stio/lib/stio-tmr.c +++ b/stio/lib/stio-tmr.c @@ -46,28 +46,14 @@ static stio_tmridx_t sift_up (stio_t* stio, stio_tmridx_t index, int notify) if (index > 0 && YOUNGER_THAN(&stio->tmr.jobs[index], &stio->tmr.jobs[parent])) { stio_tmrjob_t item; -#if defined(STIO_USE_TMRJOB_IDXPTR) - /* nothing */ -#else - stio_tmridx_t old_index; -#endif item = stio->tmr.jobs[index]; -#if defined(STIO_USE_TMRJOB_IDXPTR) - /* nothing */ -#else - old_index = index; -#endif do { /* move down the parent to my current position */ stio->tmr.jobs[index] = stio->tmr.jobs[parent]; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#else - stio->tmr.jobs[index].updater (stio, parent, index, &stio->tmr.jobs[index]); -#endif /* traverse up */ index = parent; @@ -76,15 +62,7 @@ static stio_tmridx_t sift_up (stio_t* stio, stio_tmridx_t index, int notify) while (index > 0 && YOUNGER_THAN(&item, &stio->tmr.jobs[parent])); stio->tmr.jobs[index] = item; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#else - /* we send no notification if the item is added with stio_instmrjob() - * or updated with stio_updtmrjob(). the caller of these functions - * must rely on the return value. */ - if (notify && index != old_index) - stio->tmr.jobs[index].updater (stio, old_index, index, &stio->tmr.jobs[index]); -#endif } return index; @@ -97,20 +75,9 @@ static stio_tmridx_t sift_down (stio_t* stio, stio_tmridx_t index, int notify) if (index < base) /* at least 1 child is under the 'index' position */ { stio_tmrjob_t item; -#if defined(STIO_USE_TMRJOB_IDXPTR) - /* nothing */ -#else - stio_tmridx_t old_index; -#endif item = stio->tmr.jobs[index]; -#if defined(STIO_USE_TMRJOB_IDXPTR) - /* nothing */ -#else - old_index = index; -#endif - do { stio_tmridx_t left, right, younger; @@ -130,23 +97,14 @@ static stio_tmridx_t sift_down (stio_t* stio, stio_tmridx_t index, int notify) if (YOUNGER_THAN(&item, &stio->tmr.jobs[younger])) break; stio->tmr.jobs[index] = stio->tmr.jobs[younger]; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#else - stio->tmr.jobs[index].updater (stio, younger, index, &stio->tmr.jobs[index]); -#endif index = younger; } while (index < base); stio->tmr.jobs[index] = item; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#else - if (notify && index != old_index) - stio->tmr.jobs[index].updater (stio, old_index, index, &stio->tmr.jobs[index]); -#endif } return index; @@ -159,21 +117,13 @@ void stio_deltmrjob (stio_t* stio, stio_tmridx_t index) STIO_ASSERT (index < stio->tmr.size); item = stio->tmr.jobs[index]; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = STIO_TMRIDX_INVALID; -#else - stio->tmr.jobs[index].updater (stio, index, STIO_TMRIDX_INVALID, &stio->tmr.jobs[index]); -#endif stio->tmr.size = stio->tmr.size - 1; if (stio->tmr.size > 0 && index != stio->tmr.size) { stio->tmr.jobs[index] = stio->tmr.jobs[stio->tmr.size]; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#else - stio->tmr.jobs[index].updater (stio, stio->tmr.size, index, &stio->tmr.jobs[index]); -#endif YOUNGER_THAN(&stio->tmr.jobs[index], &item)? sift_up(stio, index, 1): sift_down(stio, index, 1); } } @@ -202,9 +152,7 @@ stio_tmridx_t stio_instmrjob (stio_t* stio, const stio_tmrjob_t* job) stio->tmr.size = stio->tmr.size + 1; stio->tmr.jobs[index] = *job; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#endif return sift_up (stio, index, 0); } @@ -213,9 +161,7 @@ stio_tmridx_t stio_updtmrjob (stio_t* stio, stio_tmridx_t index, const stio_tmrj stio_tmrjob_t item; item = stio->tmr.jobs[index]; stio->tmr.jobs[index] = *job; -#if defined(STIO_USE_TMRJOB_IDXPTR) if (stio->tmr.jobs[index].idxptr) *stio->tmr.jobs[index].idxptr = index; -#endif return YOUNGER_THAN(job, &item)? sift_up (stio, index, 0): sift_down (stio, index, 0); } diff --git a/stio/lib/stio.c b/stio/lib/stio.c index 64a8e4f..a03ac9f 100644 --- a/stio/lib/stio.c +++ b/stio/lib/stio.c @@ -847,7 +847,6 @@ enqueue_data: } else { - q->dstadr.ptr = STIO_NULL; q->dstadr.len = 0; } diff --git a/stio/lib/stio.h b/stio/lib/stio.h index c32aee6..1373610 100644 --- a/stio/lib/stio.h +++ b/stio/lib/stio.h @@ -48,12 +48,11 @@ struct stio_ntime_t #define STIO_SYSHND_INVALID (-1) #endif - typedef struct stio_adr_t stio_adr_t; struct stio_adr_t { + int len; void* ptr; - int len; }; #define STIO_CONST_SWAP16(x) \ @@ -101,7 +100,7 @@ enum stio_errnum_t STIO_ECONRF, /* connection refused */ STIO_ECONRS, /* connection reset */ STIO_ENOCAPA, /* no capability */ - STIO_ETMOUT, /* timed out */ + STIO_ETMOUT, /* timed out */ STIO_EDEVMAKE, STIO_EDEVERR,