21#if defined(ARDUINO) && DETWS_NEED_DET_CLIENT
23#include "lwip/priv/tcpip_priv.h"
35 volatile bool connected;
48static DetClientCtx s_client;
56static err_t cc_recv(
void *arg,
struct tcp_pcb *tpcb,
struct pbuf *p, err_t err)
59 ClientConn *c = (ClientConn *)arg;
74 for (
struct pbuf *q = p; q; q = q->next)
75 h = det_ring_write_span(c->rx,
DETWS_CLIENT_RX_BUF, h, (
const uint8_t *)q->payload, q->len);
86static err_t cc_connected(
void *arg,
struct tcp_pcb *tpcb, err_t err)
89 ClientConn *c = (ClientConn *)arg;
100static void cc_err(
void *arg, err_t err)
103 ClientConn *c = (ClientConn *)arg;
115 struct tcpip_api_call_data base;
123 struct tcpip_api_call_data base;
131 struct tcpip_api_call_data base;
136static err_t cc_do_connect(
struct tcpip_api_call_data *cd)
138 CcConnCall *k = (CcConnCall *)cd;
139 ClientConn *c = k->c;
140 c->pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
147 tcp_recv(c->pcb, cc_recv);
148 tcp_err(c->pcb, cc_err);
149 k->result = tcp_connect(c->pcb, &k->addr, k->port, cc_connected);
153static err_t cc_do_send(
struct tcpip_api_call_data *cd)
155 CcSendCall *k = (CcSendCall *)cd;
156 ClientConn *c = k->c;
159 k->result = ERR_CONN;
162 k->result = tcp_write(c->pcb, k->data, k->len, TCP_WRITE_FLAG_COPY);
163 if (k->result == ERR_OK)
168static err_t cc_do_close(
struct tcpip_api_call_data *cd)
170 CcSendCall *k = (CcSendCall *)cd;
171 ClientConn *c = k->c;
174 tcp_arg(c->pcb,
nullptr);
175 tcp_recv(c->pcb,
nullptr);
176 tcp_err(c->pcb,
nullptr);
177 if (tcp_close(c->pcb) != ERR_OK)
184static err_t cc_do_recved(
struct tcpip_api_call_data *cd)
186 CcRecvedCall *k = (CcRecvedCall *)cd;
188 tcp_recved(k->c->pcb, k->len);
194int det_client_open(
const char *host, uint16_t port, uint32_t timeout_ms)
198 if (!s_client.cc[i].in_use)
206 ClientConn *c = &s_client.cc[cid];
208 c->connected =
false;
217 if (!detws_dns_resolve(host, &ip))
225 memset(&k, 0,
sizeof(k));
227 IP_ADDR4(&k.addr, (uint8_t)(ip >> 24), (uint8_t)(ip >> 16), (uint8_t)(ip >> 8), (uint8_t)ip);
229 tcpip_api_call(cc_do_connect, &k.base);
230 if (k.result != ERR_OK)
235 while (!c->connected && !c->closed && (int32_t)(deadline -
detws_millis()) > 0)
247 return cid >= 0 && cid <
DETWS_CLIENT_CONNS && s_client.cc[cid].in_use && s_client.cc[cid].connected &&
248 !s_client.cc[cid].closed;
255 return s_client.cc[cid].closed;
263 memset(&k, 0,
sizeof(k));
264 k.c = &s_client.cc[cid];
266 k.len = (u16_t)(len > 0xFFFF ? 0xFFFF : len);
267 tcpip_api_call(cc_do_send, &k.base);
268 return k.result == ERR_OK;
275 ClientConn *c = &s_client.cc[cid];
283 ClientConn *c = &s_client.cc[cid];
289 memset(&k, 0,
sizeof(k));
292 tcpip_api_call(cc_do_recved, &k.base);
302 memset(&k, 0,
sizeof(k));
303 k.c = &s_client.cc[cid];
304 tcpip_api_call(cc_do_close, &k.base);
305 s_client.cc[cid].in_use =
false;
#define DETWS_CLIENT_CONNS
Number of simultaneous outbound client connections (BSS pool size).
#define DETWS_CLIENT_RX_BUF
Per-connection wire receive ring size (bytes).
bool det_client_connected(int)
True once the TCP handshake has completed for cid.
size_t det_client_available(int)
Wire bytes currently buffered and ready to read.
bool det_client_is_closed(int)
True once the peer closed (FIN) or the connection errored.
int det_client_open(const char *, uint16_t, uint32_t)
Resolve host (dotted-quad fast path, else DNS) and connect to host : port, blocking up to timeout_ms.
size_t det_client_read(int, uint8_t *, size_t)
Drain up to cap buffered wire bytes into buf; returns the count.
void det_client_close(int)
Tear down the connection (marshaled) and return the slot to the pool.
bool det_client_send(int, const void *, size_t)
Queue len wire bytes for transmission (marshaled tcp_write + output).
Layer 4 outbound TCP client transport - the client-side peer of the (server) transport in tcp....
Pluggable monotonic clock for all library timing.
uint32_t detws_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
DNS resolver with answer verification (DETWS_ENABLE_DNS_RESOLVER).
Shared single-producer / single-consumer byte-ring primitive.