Struct pcsc::Context

source ·
pub struct Context { /* private fields */ }
Expand description

Library context to the PCSC service.

This structure wraps SCARDCONTEXT.

Implementations§

source§

impl Context

source

pub fn establish(scope: Scope) -> Result<Context, Error>

Establish a new context.

This function wraps SCardEstablishContext (pcsclite, MSDN).

Examples found in repository?
examples/list-readers-owned.rs (line 6)
4
5
6
7
8
9
10
11
12
13
14
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // Instead of manually allocating the buffer for the reader names, we let pcsc take care of
    // that
    let names = ctx.list_readers_owned().expect("failed to list readers");
    for name in names {
        println!("{:?}", name);
    }
}
More examples
Hide additional examples
examples/list-readers.rs (line 6)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // First allocate the required buffer.
    let len = ctx.list_readers_len().expect("failed to list readers needed len");
    let mut readers_buf = vec![0; len];
    // Alternatively, we could have just used a sufficiently large
    // statically sized, stack allocated buffer instead, like we do in
    // other examples:
    // let mut readers_buf = [0; 2048];

    let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
    for name in names {
        println!("{:?}", name);
    }
}
examples/cancel.rs (line 15)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // Spawn a thread which waits for a key-press then cancels the operation.
    {
        let ctx = ctx.clone();
        std::thread::spawn(move || {
            wait_for_enter_keypress();
            ctx.cancel().expect("failed to cancel");
        });
    }

    // Set up the blocking call, and wait for cancel or timeout.
    println!("Entering blocking call; press Enter to cancel");
    let mut reader_states = vec![ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE)];
    match ctx.get_status_change(Duration::from_secs(5), &mut reader_states) {
        Ok(()) => {
            println!("Blocking call exited normally");
        }
        Err(Error::Cancelled) => {
            println!("Blocking call canceled");
        }
        Err(Error::Timeout) => {
            println!("Blocking call timed out");
        }
        Err(error) => {
            panic!("failed to get status changes: {:?}", error);
        }
    }
}
examples/monitor.rs (line 5)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
fn main() {
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    let mut readers_buf = [0; 2048];
    let mut reader_states = vec![
        // Listen for reader insertions/removals, if supported.
        ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE),
    ];
    loop {
        // Remove dead readers.
        fn is_dead(rs: &ReaderState) -> bool {
            rs.event_state().intersects(State::UNKNOWN | State::IGNORE)
        }
        for rs in &reader_states {
            if is_dead(rs) {
                println!("Removing {:?}", rs.name());
            }
        }
        reader_states.retain(|rs| !is_dead(rs));

        // Add new readers.
        let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
        for name in names {
            if !reader_states.iter().any(|rs| rs.name() == name) {
                println!("Adding {:?}", name);
                reader_states.push(ReaderState::new(name, State::UNAWARE));
            }
        }

        // Update the view of the state to wait on.
        for rs in &mut reader_states {
            rs.sync_current_state();
        }

        // Wait until the state changes.
        ctx.get_status_change(None, &mut reader_states)
            .expect("failed to get status change");

        // Print current state.
        println!();
        for rs in &reader_states {
            if rs.name() != PNP_NOTIFICATION() {
                println!("{:?} {:?} {:?}", rs.name(), rs.event_state(), rs.atr());
            }
        }
    }
}
examples/readme.rs (line 5)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
fn main() {
    // Establish a PC/SC context.
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => {
            eprintln!("Failed to establish context: {}", err);
            std::process::exit(1);
        }
    };

    // List available readers.
    let mut readers_buf = [0; 2048];
    let mut readers = match ctx.list_readers(&mut readers_buf) {
        Ok(readers) => readers,
        Err(err) => {
            eprintln!("Failed to list readers: {}", err);
            std::process::exit(1);
        }
    };

    // Use the first reader.
    let reader = match readers.next() {
        Some(reader) => reader,
        None => {
            println!("No readers are connected.");
            return;
        }
    };
    println!("Using reader: {:?}", reader);

    // Connect to the card.
    let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(Error::NoSmartcard) => {
            println!("A smartcard is not present in the reader.");
            return;
        }
        Err(err) => {
            eprintln!("Failed to connect to card: {}", err);
            std::process::exit(1);
        }
    };

    // Send an APDU command.
    let apdu = b"\x00\xa4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("Sending APDU: {:?}", apdu);
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = match card.transmit(apdu, &mut rapdu_buf) {
        Ok(rapdu) => rapdu,
        Err(err) => {
            eprintln!("Failed to transmit APDU command to card: {}", err);
            std::process::exit(1);
        }
    };
    println!("APDU response: {:?}", rapdu);
}
examples/connect-owned.rs (line 6)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn release(self) -> Result<(), (Context, Error)>

Release the context.

In case of error, ownership of the context is returned to the caller.

This function wraps SCardReleaseContext (pcsclite, MSDN).

Note

Context implements Drop which automatically releases the context; you only need to call this function if you want to handle errors.

If the Context was cloned, and a clone is still alive, this function will fail with Error::CantDispose.

Examples found in repository?
examples/connect-owned.rs (line 83)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
More examples
Hide additional examples
examples/connect.rs (line 102)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn is_valid(&self) -> Result<(), Error>

Check whether the Context is still valid.

This function wraps SCardIsValidContext (pcsclite, MSDN).

source

pub fn cancel(&self) -> Result<(), Error>

Cancel any ongoing blocking operation in the Context.

See the cancel.rs example program.

This function wraps SCardCancel (pcsclite, MSDN).

Examples found in repository?
examples/cancel.rs (line 22)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // Spawn a thread which waits for a key-press then cancels the operation.
    {
        let ctx = ctx.clone();
        std::thread::spawn(move || {
            wait_for_enter_keypress();
            ctx.cancel().expect("failed to cancel");
        });
    }

    // Set up the blocking call, and wait for cancel or timeout.
    println!("Entering blocking call; press Enter to cancel");
    let mut reader_states = vec![ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE)];
    match ctx.get_status_change(Duration::from_secs(5), &mut reader_states) {
        Ok(()) => {
            println!("Blocking call exited normally");
        }
        Err(Error::Cancelled) => {
            println!("Blocking call canceled");
        }
        Err(Error::Timeout) => {
            println!("Blocking call timed out");
        }
        Err(error) => {
            panic!("failed to get status changes: {:?}", error);
        }
    }
}
source

pub fn list_readers<'buf>( &self, buffer: &'buf mut [u8] ) -> Result<ReaderNames<'buf>, Error>

List all connected card readers.

buffer is a buffer that should be large enough to hold all of the connected reader names. The function list_readers_len can be used to find the exact required length.

Returns an iterator over the reader names. The iterator yields values directly from buffer.

If the buffer is not large enough to hold all of the names, Error::InsufficientBuffer is returned.

This function wraps SCardListReaders (pcsclite, MSDN).

Examples found in repository?
examples/list-readers.rs (line 16)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // First allocate the required buffer.
    let len = ctx.list_readers_len().expect("failed to list readers needed len");
    let mut readers_buf = vec![0; len];
    // Alternatively, we could have just used a sufficiently large
    // statically sized, stack allocated buffer instead, like we do in
    // other examples:
    // let mut readers_buf = [0; 2048];

    let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
    for name in names {
        println!("{:?}", name);
    }
}
More examples
Hide additional examples
examples/monitor.rs (line 25)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
fn main() {
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    let mut readers_buf = [0; 2048];
    let mut reader_states = vec![
        // Listen for reader insertions/removals, if supported.
        ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE),
    ];
    loop {
        // Remove dead readers.
        fn is_dead(rs: &ReaderState) -> bool {
            rs.event_state().intersects(State::UNKNOWN | State::IGNORE)
        }
        for rs in &reader_states {
            if is_dead(rs) {
                println!("Removing {:?}", rs.name());
            }
        }
        reader_states.retain(|rs| !is_dead(rs));

        // Add new readers.
        let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
        for name in names {
            if !reader_states.iter().any(|rs| rs.name() == name) {
                println!("Adding {:?}", name);
                reader_states.push(ReaderState::new(name, State::UNAWARE));
            }
        }

        // Update the view of the state to wait on.
        for rs in &mut reader_states {
            rs.sync_current_state();
        }

        // Wait until the state changes.
        ctx.get_status_change(None, &mut reader_states)
            .expect("failed to get status change");

        // Print current state.
        println!();
        for rs in &reader_states {
            if rs.name() != PNP_NOTIFICATION() {
                println!("{:?} {:?} {:?}", rs.name(), rs.event_state(), rs.atr());
            }
        }
    }
}
examples/readme.rs (line 15)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
fn main() {
    // Establish a PC/SC context.
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => {
            eprintln!("Failed to establish context: {}", err);
            std::process::exit(1);
        }
    };

    // List available readers.
    let mut readers_buf = [0; 2048];
    let mut readers = match ctx.list_readers(&mut readers_buf) {
        Ok(readers) => readers,
        Err(err) => {
            eprintln!("Failed to list readers: {}", err);
            std::process::exit(1);
        }
    };

    // Use the first reader.
    let reader = match readers.next() {
        Some(reader) => reader,
        None => {
            println!("No readers are connected.");
            return;
        }
    };
    println!("Using reader: {:?}", reader);

    // Connect to the card.
    let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(Error::NoSmartcard) => {
            println!("A smartcard is not present in the reader.");
            return;
        }
        Err(err) => {
            eprintln!("Failed to connect to card: {}", err);
            std::process::exit(1);
        }
    };

    // Send an APDU command.
    let apdu = b"\x00\xa4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("Sending APDU: {:?}", apdu);
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = match card.transmit(apdu, &mut rapdu_buf) {
        Ok(rapdu) => rapdu,
        Err(err) => {
            eprintln!("Failed to transmit APDU command to card: {}", err);
            std::process::exit(1);
        }
    };
    println!("APDU response: {:?}", rapdu);
}
examples/connect.rs (line 10)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn list_readers_len(&self) -> Result<usize, Error>

Get the needed length of a buffer to be passed to list_readers.

This function wraps SCardListReaders (pcsclite, MSDN).

Examples found in repository?
examples/list-readers.rs (line 9)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // First allocate the required buffer.
    let len = ctx.list_readers_len().expect("failed to list readers needed len");
    let mut readers_buf = vec![0; len];
    // Alternatively, we could have just used a sufficiently large
    // statically sized, stack allocated buffer instead, like we do in
    // other examples:
    // let mut readers_buf = [0; 2048];

    let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
    for name in names {
        println!("{:?}", name);
    }
}
source

pub fn list_readers_owned(&self) -> Result<Vec<CString>, Error>

List all connected card readers, allocating buffers of the required size.

This function wraps SCardListReaders (pcsclite, MSDN). It is an owned version of list_readers, calling list_readers_len to determine the required buffer size.

Examples found in repository?
examples/list-readers-owned.rs (line 10)
4
5
6
7
8
9
10
11
12
13
14
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // Instead of manually allocating the buffer for the reader names, we let pcsc take care of
    // that
    let names = ctx.list_readers_owned().expect("failed to list readers");
    for name in names {
        println!("{:?}", name);
    }
}
More examples
Hide additional examples
examples/connect-owned.rs (line 9)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn connect( &self, reader: &CStr, share_mode: ShareMode, preferred_protocols: Protocols ) -> Result<Card, Error>

Connect to a card which is present in a reader.

See the connect.rs example program.

This function wraps SCardConnect (pcsclite, MSDN).

Examples found in repository?
examples/readme.rs (line 34)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
fn main() {
    // Establish a PC/SC context.
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => {
            eprintln!("Failed to establish context: {}", err);
            std::process::exit(1);
        }
    };

    // List available readers.
    let mut readers_buf = [0; 2048];
    let mut readers = match ctx.list_readers(&mut readers_buf) {
        Ok(readers) => readers,
        Err(err) => {
            eprintln!("Failed to list readers: {}", err);
            std::process::exit(1);
        }
    };

    // Use the first reader.
    let reader = match readers.next() {
        Some(reader) => reader,
        None => {
            println!("No readers are connected.");
            return;
        }
    };
    println!("Using reader: {:?}", reader);

    // Connect to the card.
    let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(Error::NoSmartcard) => {
            println!("A smartcard is not present in the reader.");
            return;
        }
        Err(err) => {
            eprintln!("Failed to connect to card: {}", err);
            std::process::exit(1);
        }
    };

    // Send an APDU command.
    let apdu = b"\x00\xa4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("Sending APDU: {:?}", apdu);
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = match card.transmit(apdu, &mut rapdu_buf) {
        Ok(rapdu) => rapdu,
        Err(err) => {
            eprintln!("Failed to transmit APDU command to card: {}", err);
            std::process::exit(1);
        }
    };
    println!("APDU response: {:?}", rapdu);
}
More examples
Hide additional examples
examples/connect-owned.rs (line 19)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
examples/connect.rs (line 22)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn get_status_change<D>( &self, timeout: D, readers: &mut [ReaderState] ) -> Result<(), Error>
where D: Into<Option<Duration>>,

Wait for card and card reader state changes.

The function blocks until the state of one of the readers changes from corresponding passed-in ReaderState. The ReaderStates are updated to report the new state.

A special reader name, \\?PnP?\Notification, can be used to detect card reader insertions and removals, as opposed to state changes of a specific reader. Use PNP_NOTIFICATION() to easily obtain a static reference to this name.

See the monitor.rs example program.

This function wraps SCardGetStatusChange (pcsclite, MSDN).

Examples found in repository?
examples/cancel.rs (line 29)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // Spawn a thread which waits for a key-press then cancels the operation.
    {
        let ctx = ctx.clone();
        std::thread::spawn(move || {
            wait_for_enter_keypress();
            ctx.cancel().expect("failed to cancel");
        });
    }

    // Set up the blocking call, and wait for cancel or timeout.
    println!("Entering blocking call; press Enter to cancel");
    let mut reader_states = vec![ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE)];
    match ctx.get_status_change(Duration::from_secs(5), &mut reader_states) {
        Ok(()) => {
            println!("Blocking call exited normally");
        }
        Err(Error::Cancelled) => {
            println!("Blocking call canceled");
        }
        Err(Error::Timeout) => {
            println!("Blocking call timed out");
        }
        Err(error) => {
            panic!("failed to get status changes: {:?}", error);
        }
    }
}
More examples
Hide additional examples
examples/monitor.rs (line 39)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
fn main() {
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    let mut readers_buf = [0; 2048];
    let mut reader_states = vec![
        // Listen for reader insertions/removals, if supported.
        ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE),
    ];
    loop {
        // Remove dead readers.
        fn is_dead(rs: &ReaderState) -> bool {
            rs.event_state().intersects(State::UNKNOWN | State::IGNORE)
        }
        for rs in &reader_states {
            if is_dead(rs) {
                println!("Removing {:?}", rs.name());
            }
        }
        reader_states.retain(|rs| !is_dead(rs));

        // Add new readers.
        let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
        for name in names {
            if !reader_states.iter().any(|rs| rs.name() == name) {
                println!("Adding {:?}", name);
                reader_states.push(ReaderState::new(name, State::UNAWARE));
            }
        }

        // Update the view of the state to wait on.
        for rs in &mut reader_states {
            rs.sync_current_state();
        }

        // Wait until the state changes.
        ctx.get_status_change(None, &mut reader_states)
            .expect("failed to get status change");

        // Print current state.
        println!();
        for rs in &reader_states {
            if rs.name() != PNP_NOTIFICATION() {
                println!("{:?} {:?} {:?}", rs.name(), rs.event_state(), rs.atr());
            }
        }
    }
}

Trait Implementations§

source§

impl Clone for Context

source§

fn clone(&self) -> Self

Clone the Context.

Implementation note

This is implemented in the Rust side with an Arc::clone.

1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Send for Context

source§

impl Sync for Context

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.