@@ -124,7 +124,25 @@ class ClientContext
124124 }
125125 }
126126
127- size_t availableForWrite ()
127+ int connect (ip_addr_t * addr, uint16_t port)
128+ {
129+ err_t err = tcp_connect (_pcb, addr, port, reinterpret_cast <tcp_connected_fn>(&ClientContext::_s_connected));
130+ if (err != ERR_OK) {
131+ return 0 ;
132+ }
133+ _connect_pending = 1 ;
134+ _op_start_time = millis ();
135+ // This delay will be interrupted by esp_schedule in the connect callback
136+ delay (_timeout_ms);
137+ _connect_pending = 0 ;
138+ if (state () != ESTABLISHED) {
139+ abort ();
140+ return 0 ;
141+ }
142+ return 1 ;
143+ }
144+
145+ size_t availableForWrite ()
128146 {
129147 return _pcb? tcp_sndbuf (_pcb): 0 ;
130148 }
@@ -149,14 +167,14 @@ class ClientContext
149167 return tcp_nagle_disabled (_pcb);
150168 }
151169
152- void setNonBlocking ( bool nonblocking)
170+ void setTimeout ( int timeout_ms)
153171 {
154- _noblock = nonblocking ;
172+ _timeout_ms = timeout_ms ;
155173 }
156174
157- bool getNonBlocking ()
175+ int getTimeout ()
158176 {
159- return _noblock ;
177+ return _timeout_ms ;
160178 }
161179
162180 uint32_t getRemoteAddress ()
@@ -315,9 +333,14 @@ class ClientContext
315333
316334protected:
317335
318- void _cancel_write ()
336+ bool _is_timeout ()
337+ {
338+ return millis () - _op_start_time > _timeout_ms;
339+ }
340+
341+ void _notify_error ()
319342 {
320- if (_send_waiting) {
343+ if (_connect_pending || _send_waiting) {
321344 esp_schedule ();
322345 }
323346 }
@@ -328,10 +351,11 @@ class ClientContext
328351 assert (_send_waiting == 0 );
329352 _datasource = ds;
330353 _written = 0 ;
354+ _op_start_time = millis ();
331355 do {
332356 _write_some ();
333357
334- if (!_datasource->available () || _noblock || state () == CLOSED) {
358+ if (!_datasource->available () || _is_timeout () || state () == CLOSED) {
335359 delete _datasource;
336360 _datasource = nullptr ;
337361 break ;
@@ -431,7 +455,7 @@ class ClientContext
431455 (void ) err;
432456 if (pb == 0 ) { // connection closed
433457 DEBUGV (" :rcl\r\n " );
434- _cancel_write ();
458+ _notify_error ();
435459 abort ();
436460 return ERR_ABRT;
437461 }
@@ -456,7 +480,16 @@ class ClientContext
456480 tcp_recv (_pcb, NULL );
457481 tcp_err (_pcb, NULL );
458482 _pcb = NULL ;
459- _cancel_write ();
483+ _notify_error ();
484+ }
485+
486+ int8_t _connected (void * pcb, int8_t err)
487+ {
488+ (void ) err;
489+ assert (pcb == _pcb);
490+ assert (_connect_pending);
491+ esp_schedule ();
492+ return ERR_OK;
460493 }
461494
462495 err_t _poll (tcp_pcb*)
@@ -485,6 +518,11 @@ class ClientContext
485518 return reinterpret_cast <ClientContext*>(arg)->_sent (tpcb, len);
486519 }
487520
521+ static int8_t _s_connected (void * arg, void * pcb, int8_t err)
522+ {
523+ return reinterpret_cast <ClientContext*>(arg)->_connected (pcb, err);
524+ }
525+
488526private:
489527 tcp_pcb* _pcb;
490528
@@ -494,14 +532,16 @@ class ClientContext
494532 discard_cb_t _discard_cb;
495533 void * _discard_cb_arg;
496534
497- int _refcnt;
498- ClientContext* _next;
499-
500535 DataSource* _datasource = nullptr ;
501536 size_t _written = 0 ;
502537 size_t _write_chunk_size = 256 ;
503- bool _noblock = false ;
504- int _send_waiting = 0 ;
538+ uint32_t _timeout_ms = 5000 ;
539+ uint32_t _op_start_time = 0 ;
540+ uint8_t _send_waiting = 0 ;
541+ uint8_t _connect_pending = 0 ;
542+
543+ int8_t _refcnt;
544+ ClientContext* _next;
505545};
506546
507547#endif // CLIENTCONTEXT_H
0 commit comments