• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kaidokert / winc-rs / 13780869535

11 Mar 2025 05:14AM UTC coverage: 67.811% (-0.3%) from 68.079%
13780869535

Pull #40

github

kaidokert
Make connect behave in correct non-blocking way
Pull Request #40: Make connect behave in correct non-blocking way

0 of 26 new or added lines in 3 files covered. (0.0%)

1 existing line in 1 file now uncovered.

2233 of 3293 relevant lines covered (67.81%)

2073.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.23
/winc-rs/src/stack/socket_callbacks.rs
1
use core::net::Ipv4Addr;
2

3
use crate::manager::{EventListener, SocketError, WifiConnError, WifiConnState};
4
use crate::ConnectionInfo;
5

6
use crate::{debug, error, info};
7

8
use crate::socket::Socket;
9

10
use crate::Ipv4AddrFormatWrapper;
11

12
use super::SockHolder;
13
use crate::manager::{PingError, ScanResult, SOCKET_BUFFER_MAX_LENGTH};
14

15
/// Opaque handle to a socket. Returned by socket APIs
16
#[derive(Clone, Copy, PartialEq, Debug)]
17
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18
pub struct Handle(pub u8);
19

20
#[derive(Debug, PartialEq, Clone)]
21
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22
pub(crate) enum WifiModuleState {
23
    Reset,
24
    Starting,
25
    Started,
26
    ConnectingToAp,
27
    ConnectedToAp,
28
    ConnectionFailed,
29
}
30

31
/// Ping operation results
32
#[derive(Debug)]
33
pub struct PingResult {
34
    pub ip: Ipv4Addr,
35
    pub rtt: u32,
36
    pub num_successful: u16,
37
    pub num_failed: u16,
38
    pub error: PingError,
39
}
40

41
#[cfg(feature = "defmt")]
42
impl defmt::Format for PingResult {
43
    fn format(&self, f: defmt::Formatter) {
44
        defmt::write!(
45
            f,
46
            "ip: {}, rtt: {}, num_successful: {}, num_failed: {}, error: {}",
47
            Ipv4AddrFormatWrapper::new(&self.ip),
48
            self.rtt,
49
            self.num_successful,
50
            self.num_failed,
51
            self.error
52
        );
53
    }
54
}
55

56
// TODO: This should be exposed to user
57
#[allow(dead_code)]
58
pub struct SystemTime {
59
    year: u16,
60
    month: u8,
61
    day: u8,
62
    hour: u8,
63
    minute: u8,
64
    second: u8,
65
}
66

67
pub(crate) struct ConnectionState {
68
    conn_state: WifiConnState,
69
    pub conn_error: Option<WifiConnError>,
70
    pub ip_conf: Option<crate::manager::IPConf>,
71
    system_time: Option<SystemTime>,
72
    ip_conflict: Option<Ipv4Addr>,
73
    pub scan_number_aps: Option<Option<u8>>,
74
    pub scan_results: Option<Option<ScanResult>>,
75
    pub conn_info: Option<Option<ConnectionInfo>>,
76
    pub rssi_level: Option<Option<i8>>,
77
    pub ping_result: Option<Option<PingResult>>,
78
}
79

80
impl ConnectionState {
81
    fn new() -> Self {
21✔
82
        Self {
21✔
83
            conn_state: WifiConnState::Disconnected,
21✔
84
            conn_error: None,
21✔
85
            ip_conf: None,
21✔
86
            system_time: None,
21✔
87
            rssi_level: None,
21✔
88
            ip_conflict: None,
21✔
89
            conn_info: None,
21✔
90
            scan_number_aps: None,
21✔
91
            scan_results: None,
21✔
92
            ping_result: None,
21✔
93
        }
21✔
94
    }
21✔
95
}
96

97
pub(crate) const UDP_SOCK_OFFSET: usize = 7;
98
pub(crate) const MAX_UDP_SOCKETS: usize = 4;
99

100
pub(crate) struct SocketCallbacks {
101
    // #define TCP_SOCK_MAX                                                                                (7)
102
    // indexes 0-6
103
    pub tcp_sockets: SockHolder<UDP_SOCK_OFFSET, 0>,
104
    // #define UDP_SOCK_MAX                                                                                4
105
    pub udp_sockets: SockHolder<MAX_UDP_SOCKETS, UDP_SOCK_OFFSET>,
106
    // Needed to keep track of connect() and recvfrom address
107
    pub udp_sockets_addr: [Option<core::net::SocketAddrV4>; MAX_UDP_SOCKETS],
108
    pub udp_socket_connect_addr: [Option<core::net::SocketAddrV4>; MAX_UDP_SOCKETS],
109
    pub recv_buffer: [u8; SOCKET_BUFFER_MAX_LENGTH],
110

111
    // All this should be moved into an enum rather, these are response
112
    // callbacks, mutually exclusive
113
    // Todo: make this per socket
114
    pub recv_len: usize,
115
    // Todo: Make this per socket
116
    pub last_error: crate::manager::SocketError,
117
    // This is also per socket
118
    pub last_accept_addr: Option<core::net::SocketAddrV4>,
119
    pub last_accepted_socket: Option<Socket>,
120

121
    // This is global
122
    pub dns_resolved_addr: Option<Option<core::net::Ipv4Addr>>,
123
    pub connection_state: ConnectionState,
124
    pub state: WifiModuleState,
125
}
126

127
#[derive(Debug, Clone, Copy, PartialEq)]
128
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129
pub(crate) struct ConnectResult {
130
    pub error: SocketError,
131
}
132

133
#[derive(PartialEq, Clone, Copy, Debug)]
134
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
135
pub enum ClientSocketOp {
136
    None,
137
    New,
138
    Connect((u32, Option<ConnectResult>)),
139
    Send(i16),
140
    SendTo(i16),
141
    Recv,
142
    RecvFrom,
143
    Bind,
144
    Listen,
145
    Accept,
146
}
147

148
impl SocketCallbacks {
149
    pub fn new() -> Self {
21✔
150
        Self {
21✔
151
            tcp_sockets: SockHolder::new(),
21✔
152
            udp_sockets: SockHolder::new(),
21✔
153
            udp_sockets_addr: [None; MAX_UDP_SOCKETS],
21✔
154
            udp_socket_connect_addr: [None; MAX_UDP_SOCKETS],
21✔
155
            recv_buffer: [0; SOCKET_BUFFER_MAX_LENGTH],
21✔
156
            recv_len: 0,
21✔
157
            last_error: crate::manager::SocketError::NoError,
21✔
158
            last_accept_addr: None,
21✔
159
            dns_resolved_addr: None,
21✔
160
            last_accepted_socket: None,
21✔
161
            connection_state: ConnectionState::new(),
21✔
162
            state: WifiModuleState::Reset,
21✔
163
        }
21✔
164
    }
21✔
165
    pub fn resolve(&mut self, socket: Socket) -> Option<&mut (Socket, ClientSocketOp)> {
×
166
        if socket.v < UDP_SOCK_OFFSET as u8 {
×
167
            debug!("resolving tcp: {:?}", socket.v);
×
168
            self.tcp_sockets.get(Handle(socket.v))
×
169
        } else {
170
            debug!("resolving udp: {:?}", socket.v);
×
171
            self.udp_sockets
×
172
                .get(Handle(socket.v - UDP_SOCK_OFFSET as u8))
×
173
        }
174
    }
×
175
}
176

177
impl EventListener for SocketCallbacks {
178
    fn on_rssi(&mut self, level: i8) {
1✔
179
        info!("client: Got RSSI:{}", level);
1✔
180
        self.connection_state.rssi_level = Some(Some(level));
1✔
181
    }
1✔
182

183
    fn on_resolve(&mut self, ip: core::net::Ipv4Addr, host: &str) {
6✔
184
        debug!(
6✔
185
            "on_resolve: ip:{:?} host:{:?}",
×
186
            Ipv4AddrFormatWrapper::new(&ip),
×
187
            host
188
        );
189
        self.dns_resolved_addr = Some(Some(ip));
6✔
190
    }
6✔
191

192
    fn on_default_connect(&mut self, connected: bool) {
×
193
        debug!("client: got connected {}", connected)
×
194
    }
×
195
    fn on_dhcp(&mut self, conf: crate::manager::IPConf) {
×
196
        debug!("client: on_dhcp: IP config: {}", conf);
×
197
        self.connection_state.ip_conf = Some(conf);
×
198
    }
×
199
    fn on_connstate_changed(&mut self, state: WifiConnState, err: WifiConnError) {
3✔
200
        debug!("client: Connection state changed: {:?} {:?}", state, err);
3✔
201
        self.connection_state.conn_state = state;
3✔
202
        self.connection_state.conn_error = Some(err);
3✔
203
        match self.state {
3✔
204
            WifiModuleState::ConnectingToAp => match self.connection_state.conn_state {
3✔
205
                WifiConnState::Connected => {
2✔
206
                    self.state = WifiModuleState::ConnectedToAp;
2✔
207
                }
2✔
208
                _ => {
209
                    self.state = WifiModuleState::ConnectionFailed;
1✔
210
                    debug!(
1✔
211
                        "on_connstate_changed FAILED: {:?} {:?}",
×
212
                        self.connection_state.conn_state, self.connection_state.conn_error
213
                    );
214
                }
215
            },
216
            _ => {
217
                error!(
×
218
                    "UNKNOWN STATE on_connstate_changed: {:?} {:?}",
×
219
                    self.connection_state.conn_state, self.connection_state.conn_error
220
                );
221
            }
222
        }
223
    }
3✔
224

225
    fn on_connection_info(&mut self, info: ConnectionInfo) {
1✔
226
        debug!("client: conninfo, state:{}", info);
1✔
227
        self.connection_state.conn_info = Some(Some(info));
1✔
228
    }
1✔
229
    fn on_system_time(&mut self, year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) {
×
230
        debug!(
×
231
            "client: on_system_time: {}-{:02}-{:02} {:02}:{:02}:{:02}",
×
232
            year, month, day, hour, minute, second
233
        );
234
        self.connection_state.system_time = Some(SystemTime {
×
235
            year,
×
236
            month,
×
237
            day,
×
238
            hour,
×
239
            minute,
×
240
            second,
×
241
        });
×
242
    }
×
243
    fn on_ip_conflict(&mut self, ip: Ipv4Addr) {
×
244
        info!(
×
245
            "client: on_ip_conflict: {:?}",
×
246
            Ipv4AddrFormatWrapper::new(&ip)
×
247
        );
248
        self.connection_state.ip_conflict = Some(ip);
×
249
    }
×
250

251
    fn on_scan_result(&mut self, result: ScanResult) {
1✔
252
        debug!("Scanresult {}", result);
1✔
253
        self.connection_state.scan_results = Some(Some(result));
1✔
254
    }
1✔
255
    fn on_scan_done(&mut self, num_aps: u8, err: WifiConnError) {
1✔
256
        debug!("Scan done, aps:{} error:{}", num_aps, err);
1✔
257
        if err != WifiConnError::Unhandled {
1✔
258
            self.connection_state.conn_error = Some(err);
×
259
        }
1✔
260
        self.connection_state.scan_number_aps = Some(Some(num_aps));
1✔
261
    }
1✔
262
    fn on_ping(
1✔
263
        &mut self,
1✔
264
        ip: Ipv4Addr,
1✔
265
        token: u32,
1✔
266
        rtt: u32,
1✔
267
        num_successful: u16,
1✔
268
        num_failed: u16,
1✔
269
        error: PingError,
1✔
270
    ) {
1✔
271
        let ping_result = PingResult {
1✔
272
            ip,
1✔
273
            rtt,
1✔
274
            num_successful,
1✔
275
            num_failed,
1✔
276
            error,
1✔
277
        };
1✔
278
        debug!("client: on_ping: {:?} token:# {}", ping_result, token);
1✔
279
        self.connection_state.ping_result = Some(Some(ping_result));
1✔
280
    }
1✔
281

282
    // todo: Consolidate the error cases to match statements below
283
    fn on_connect(&mut self, socket: Socket, err: crate::manager::SocketError) {
×
284
        debug!("on_connect: socket {:?}", socket);
×
UNCOV
285
        if let Some((s, op)) = self.resolve(socket) {
×
NEW
286
            if let ClientSocketOp::Connect((_, option)) = op {
×
287
                debug!("on_connect: socket:{:?} error:{:?}", s, err);
×
NEW
288
                option.replace(ConnectResult { error: err });
×
289
            } else {
290
                error!(
×
291
                    "UNKNOWN STATE on_connect (x): socket:{:?} error:{:?} state:{:?}",
×
292
                    s, err, *op
293
                );
294
            }
295
        } else {
296
            error!(
×
297
                "on_connect (x): COULD NOT FIND SOCKET socket:{:?} error:{:?}",
×
298
                socket, err
299
            );
300
        }
301
    }
×
302
    fn on_send_to(&mut self, socket: Socket, len: i16) {
×
303
        debug!("on_send_to: socket:{:?} length:{:?}", socket, len);
×
304
        if let Some((s, op)) = self.resolve(socket) {
×
305
            match op {
×
306
                ClientSocketOp::SendTo(req_len) => {
×
307
                    if len >= *req_len {
×
308
                        debug!("FIN: on_send_to: socket:{:?} length:{:?}", socket, len);
×
309
                        *op = ClientSocketOp::None;
×
310
                    } else {
311
                        debug!("CONT: on_send_to: socket:{:?} length:{:?}", socket, len);
×
312
                        *req_len -= len;
×
313
                    }
314
                }
315
                _ => {
316
                    error!(
×
317
                        "UNKNOWN STATE on_send_to (x): socket:{:?} len:{:?} state:{:?}",
×
318
                        s, len, *op
319
                    );
320
                }
321
            }
322
        } else {
323
            error!(
×
324
                "UNKNOWN STATE on_send_to (x): socket:{:?} len:{:?}",
×
325
                socket, len
326
            );
327
        }
328
    }
×
329
    fn on_send(&mut self, socket: Socket, len: i16) {
×
330
        debug!("on_send: socket {:?} len:{}", socket, len);
×
331

332
        if let Some((s, op)) = self.resolve(socket) {
×
333
            match op {
×
334
                ClientSocketOp::Send(req_len) => {
×
335
                    if len >= *req_len {
×
336
                        debug!("FIN: on_send: socket:{:?} length:{:?}", socket, len);
×
337
                        *op = ClientSocketOp::None;
×
338
                    } else {
339
                        debug!("CONT: on_send: socket:{:?} length:{:?}", socket, len);
×
340
                        *req_len -= len;
×
341
                    }
342
                }
343
                _ => {
344
                    error!(
×
345
                        "UNKNOWN STATE on_send (x): socket:{:?} len:{:?} state:{:?}",
×
346
                        s, len, *op
347
                    );
348
                }
349
            }
350
        } else {
351
            error!(
×
352
                "on_send (x): COULD NOT FIND SOCKET socket:{:?} len:{:?}",
×
353
                socket, len
354
            );
355
        }
356
    }
×
357
    fn on_recv(
×
358
        &mut self,
×
359
        socket: Socket,
×
360
        address: core::net::SocketAddrV4,
×
361
        data: &[u8],
×
362
        err: crate::manager::SocketError,
×
363
    ) {
×
364
        debug!("on_recv: socket {:?}", socket);
×
365
        let mut found = false;
×
366
        if let Some((s, op)) = self.resolve(socket) {
×
367
            if *op == ClientSocketOp::Recv {
×
368
                debug!(
×
369
                    "on_recv: socket:{:?} address:{:?} data:{:?} len:{:?} error:{:?}",
×
370
                    s,
×
371
                    Ipv4AddrFormatWrapper::new(address.ip()),
×
372
                    data,
×
373
                    data.len(),
×
374
                    err
375
                );
376
                *op = ClientSocketOp::None;
×
377
                found = true;
×
378
            } else {
379
                error!(
×
380
                    "UNKNOWN on_recv: socket:{:?} address:{:?} port:{:?} data:{:?} len:{:?} error:{:?}",
×
381
                    socket,
×
382
                    Ipv4AddrFormatWrapper::new(address.ip()),
×
383
                    address.port(),
×
384
                    data,
×
385
                    data.len(),
×
386
                    err
387
                );
388
            }
389
        } else {
390
            error!(
×
391
                "UNKNOWN on_recv: socket:{:?} address:{:?} port:{:?} data:{:?} error:{:?}",
×
392
                socket,
×
393
                Ipv4AddrFormatWrapper::new(address.ip()),
×
394
                address.port(),
×
395
                data,
396
                err
397
            );
398
        }
399
        if found {
×
400
            self.recv_buffer[..data.len()].copy_from_slice(data);
×
401
            self.recv_len = data.len();
×
402
            self.last_error = err;
×
403
        }
×
404
    }
×
405
    fn on_recvfrom(
×
406
        &mut self,
×
407
        socket: Socket,
×
408
        address: core::net::SocketAddrV4,
×
409
        data: &[u8],
×
410
        err: crate::manager::SocketError,
×
411
    ) {
×
412
        debug!("on_recvfrom: socket {:?}", socket);
×
413
        let mut found = false;
×
414
        if let Some((s, op)) = self.resolve(socket) {
×
415
            if *op == ClientSocketOp::RecvFrom {
×
416
                debug!(
×
417
                    "on_recvfrom: raw:{:?} socket:{:?} address:{:?} data:{:?} error:{:?}",
×
418
                    socket,
×
419
                    s,
×
420
                    Ipv4AddrFormatWrapper::new(address.ip()),
×
421
                    data,
422
                    err
423
                );
424
                *op = ClientSocketOp::None;
×
425
                self.last_error = err;
×
426
                found = true;
×
427
            } else {
428
                error!(
×
429
                    "UNKNOWN on_recvfrom: socket:{:?} address:{:?} data:{:?} error:{:?}",
×
430
                    socket,
×
431
                    Ipv4AddrFormatWrapper::new(address.ip()),
×
432
                    data,
433
                    err
434
                );
435
            }
436
        } else {
437
            error!(
×
438
                "UNKNOWN on_recvfrom: socket:{:?} address:{:?} data:{:?} error:{:?}",
×
439
                socket,
×
440
                Ipv4AddrFormatWrapper::new(address.ip()),
×
441
                data,
442
                err
443
            );
444
        }
445
        if found {
×
446
            self.recv_buffer[..data.len()].copy_from_slice(data);
×
447
            self.recv_len = data.len();
×
448
            self.last_error = err;
×
449
            self.udp_sockets_addr[socket.v as usize - UDP_SOCK_OFFSET].replace(address);
×
450
        }
×
451
    }
×
452
    fn on_bind(&mut self, sock: Socket, err: crate::manager::SocketError) {
×
453
        debug!("on_bind: socket {:?}", sock);
×
454
        if let Some((s, op)) = self.resolve(sock) {
×
455
            if *op == ClientSocketOp::Bind {
×
456
                *op = ClientSocketOp::None;
×
457
                self.last_error = err;
×
458
            } else {
×
459
                error!(
×
460
                    "UNKNOWN on_bind: socket:{:?} error:{:?} state:{:?}",
×
461
                    s, err, *op
462
                );
463
            }
464
        }
×
465
    }
×
466
    fn on_listen(&mut self, sock: Socket, err: crate::manager::SocketError) {
×
467
        debug!("on_listen: socket {:?}", sock);
×
468
        if let Some((s, op)) = self.resolve(sock) {
×
469
            if *op == ClientSocketOp::Listen {
×
470
                *op = ClientSocketOp::None;
×
471
                self.last_error = err;
×
472
            } else {
×
473
                error!(
×
474
                    "UNKNOWN on_listen: socket:{:?} error:{:?} state:{:?}",
×
475
                    s, err, *op
476
                );
477
            }
478
        }
×
479
    }
×
480

481
    // This is different, no error being passed
482
    fn on_accept(
×
483
        &mut self,
×
484
        address: core::net::SocketAddrV4,
×
485
        listen_socket: Socket,
×
486
        accepted_socket: Socket,
×
487
        _data_offset: u16,
×
488
    ) {
×
489
        debug!(
×
490
            "on_accept: address:{:?} port:{:?} listen_socket:{:?} accepted_socket:{:?}",
×
491
            Ipv4AddrFormatWrapper::new(address.ip()),
×
492
            address.port(),
×
493
            listen_socket,
494
            accepted_socket
495
        );
496

497
        if let Some((_s, op)) = self.resolve(listen_socket) {
×
498
            if *op == ClientSocketOp::Accept {
×
499
                *op = ClientSocketOp::None;
×
500
                self.last_error = SocketError::NoError;
×
501
                self.last_accept_addr = Some(address);
×
502
                self.last_accepted_socket = Some(accepted_socket);
×
503
            } else {
×
504
                error!(
×
505
                    "Socket was NOT in accept : address:{:?} port:{:?} listen_socket:{:?} accepted_socket:{:?}
×
506
                    actual state:{:?}",
×
507
                Ipv4AddrFormatWrapper::new(address.ip()),
×
508
                address.port(),
×
509
                listen_socket,
510
                accepted_socket,
511
                *op);
512
            }
513
        } else {
514
            error!(
×
515
                "UNKNOWN socket on_accept: address:{:?} port:{:?} listen_socket:{:?} accepted_socket:{:?}",
×
516
                Ipv4AddrFormatWrapper::new(address.ip()),
×
517
                address.port(),
×
518
                listen_socket,
519
                accepted_socket
520
            );
521
        };
522
    }
×
523
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc