pub struct Context { /* private fields */ }
Expand description
Library context to the PCSC service.
This structure wraps SCARDCONTEXT
.
Implementations§
source§impl Context
impl Context
sourcepub fn establish(scope: Scope) -> Result<Context, Error>
pub fn establish(scope: Scope) -> Result<Context, Error>
Examples found in repository?
More examples
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);
}
}
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);
}
}
}
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());
}
}
}
}
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);
}
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");
}
sourcepub fn release(self) -> Result<(), (Context, Error)>
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?
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
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");
}
sourcepub fn cancel(&self) -> Result<(), Error>
pub fn cancel(&self) -> Result<(), Error>
Cancel any ongoing blocking operation in the Context.
See the cancel.rs
example program.
Examples found in repository?
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);
}
}
}
sourcepub fn list_readers<'buf>(
&self,
buffer: &'buf mut [u8]
) -> Result<ReaderNames<'buf>, Error>
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.
Examples found in repository?
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
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());
}
}
}
}
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);
}
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");
}
sourcepub fn list_readers_len(&self) -> Result<usize, Error>
pub fn list_readers_len(&self) -> Result<usize, Error>
Get the needed length of a buffer to be passed to list_readers
.
Examples found in repository?
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);
}
}
sourcepub fn list_readers_owned(&self) -> Result<Vec<CString>, Error>
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?
More examples
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");
}
sourcepub fn connect(
&self,
reader: &CStr,
share_mode: ShareMode,
preferred_protocols: Protocols
) -> Result<Card, Error>
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.
Examples found in repository?
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
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");
}
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");
}
sourcepub fn get_status_change<D>(
&self,
timeout: D,
readers: &mut [ReaderState]
) -> Result<(), Error>
pub fn get_status_change<D>( &self, timeout: D, readers: &mut [ReaderState] ) -> Result<(), Error>
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 ReaderState
s 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.
Examples found in repository?
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
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());
}
}
}
}