Federated Naming Service Programming Guide

Printer Programming Example

Printer client and server software can take advantage of FNS to advertise and to browse the printers available with respect to organizations, sites, users, and hosts. The APIs used by the server and the client are XFN APIs, thereby ensuring that the application is portable across the different naming services used for storing printer bindings.

The programming example in this section shows how printer clients and servers obtain and store printer bindings. Users can then make use of the FNS commands, fnlist and fnlookup, to browse the printer context.

For example, use fnlist to look at the user printer context for jsmith:


% fnlist user/jsmith/service/printer
celeste
lp
_default
myprinter

Similarly, you can look at the organization's printers:


% fnlist org/wiz.com/service/printer
sales_printer
mktg_printer
eng_printer

Alternatively, you can type:


% fnlist thisorgunit/service/printer

You can look at the printers at a specific site, for example, the printers in the MTV site:


% fnlist thisorgunit/site/MTV/service/printer
b1_printer
b2_printer

Client

The scenario for Example 3-2 is a user who would like to print to a printer named colorful in his organization's context, thisorgunit/service/printer/colorful. The example printer client illustrates how the bindings for a specific printer are obtained.

The variable printer_binding contains the reference (the binding information) of the named printer. Using the binding information, the printer client can connect to the server and send the printer request. Note that the fn_ctx_lookup() function can be replaced by fn_ctx_list_name() or fn_ctx_list_bindings() to list all the names and their bindings.


Example 3-2 Print Client source


#include <stdio.h>
#include <xfn/xfn.h>
#include <string.h>
#include <stdlib.h>
 
/*
 * Routine to obtain the address of a specific printe.
 * This routine takes the printer name and the address type
 * as the input arguments and returns the address
 * of the requested printer.
 */
 
char *
get_address_of_printer(const char *printer_name,
	    const char *address_type)
{
   FN_composite_name_t *printer_name_comp;
   FN_status_t *status = fn_status_create();
   FN_ctx_t *initial_context;
   FN_ref_t *printer_ref;
   const FN_identifier_t *addr_id;
   const FN_ref_addr_t *address;
   char *addr_data; /* Return value */
 
   void *ip;
   size_t address_type_len, addr_len;
 
   /* Convert the printer name to a composite name */
   printer_name_comp = fn_composite_name_from_string(
      (const unsigned char *)printer_name);
 
   /* Get the initial context */
   initial_context = fn_ctx_handle_from_initial(0, status);
 
   /* Check status for any error messages */
   if (!fn_status_is_success(status)){
    fprintf(stderr,
         "Unable to obtain the initial context\n");
    return (0);
	}
  /* Perform a lookup for the printer name */
  printer_ref = fn_ctx_lookup(initial_context,
     printer_name_comp, status);
 
  /* Check status for any error messages */
  if (!fn_status_is_success(status)){
    fprintf(stderr, "Lookup failed on: %s\n",
        printer_name);
    return (0);
  }
 
  fn_ctx_handle_destroy(initial_context);
  fn_composite_name_destroy(printer_name_comp);
  address_type_len = strlen(address_type);
 
  /* Obtain the requested address from the address type */
  for (address = fn_ref_first(printer_ref, &ip);
     address != NULL;
     address = fn_ref_next(printer_ref, &ip)) {
         addr_id = fn_ref_addr_type(address);
         if (addr_id->length == address_type_len &&
            strncmp(address_type,
                (char *)addr_id->contents,
                address_type_len) == 0)
                break;
   }
  if (address == NULL)
      return (0);
  addr_len = fn_ref_addr_length(address);
  addr_data = (char *)(malloc(addr_len + 1));
  strncpy(addr_data,(char*)(fn_ref_addr_data(address)),
          addr_len);
  addr_data[addr_len] = '\0';
  fn_ref_destroy(printer_ref);
  return (addr_data);
}

Calling the Printer Client Function

The following code could be used to call the get_address_of_printer() routine shown above.


char* printer_server;
printer_server = get_address_of_printer
 
    "thisorgunit/service/printer/colorful",
 
    "onc_bsdaddr");

Server

Using the XFN APIs, print servers can advertise their services. Example 3-3 illustrates a host, labpc, that would like to advertise the binding for the color printer colorful. The FNS name for this printer is thisorgunit/service/printer/colorful.

The main tasks are to obtain the composite name for the printer name, to generate the binding (reference) for the printer, and to bind the name and references to the FNS namespace.


Example 3-3 Print Server Source


#include <stdio.h>
#include <xfn/xfn.h>
#include <string.h>
/*
 * Routine to export the printer binding to the FNS name space.
 * This routine takes the printer name along with its
 *  reference type, address type, and address. Returns the status.
 */
int
export_printer_to_fns(const char *printer_name,
		      const char *reference_type,
		      const char *address_type,
		      const char *address_data)
{
  int return_status;
  FN_composite_name_t *printer_name_comp;
  FN_identifier_t ref_id, addr_id;
  FN_status_t *status;
  FN_ref_t *printer_ref;
  FN_ref_addr_t *address;
  FN_ctx_t *initial_context;
 
  /* Obtain the initial context */
  status = fn_status_create();
  initial_context = fn_ctx_handle_from_initial(0, status);
  /* Check status for any error messages */
  if ((return_status = fn_status_code(status)) != FN_SUCCESS) {
      fprintf(stderr, "Unable to obtain the initial context\n");
      return (return_status);
  }
  /* Construct the composite name for the printer name */
  printer_name_comp = fn_composite_name_from_string(
      (unsigned char *)printer_name);
 
  /* Construct the printer address */
  addr_id.format = FN_ID_STRING;
  addr_id.length = strlen(address_type);
  addr_id.contents = (void *) address_type;
  address = fn_ref_addr_create(&addr_id,
      strlen(address_data), (const void *) address_data);
 
  /* Construct the printer reference */
  ref_id.format = FN_ID_STRING;
	  ref_id.length = strlen(reference_type);
	  ref_id.contents = (void *) reference_type;
  	printer_ref = fn_ref_create(&ref_id);
 
	  /* Add the printer address to the printer reference */
	  fn_ref_append_addr(printer_ref, address);
	
  	/* Bind the reference to the context */
  	fn_ctx_bind(initial_context, printer_name_comp, printer_ref, 0,
          status);
	  /* Check the error status and return */
  return_status = fn_status_code(status);
 
  fn_composite_name_destroy(printer_name_comp);
  fn_ref_addr_destroy(address);
  fn_ref_destroy(printer_ref);
  fn_status_destroy(status);
  fn_ctx_handle_destroy(initial_context);
  return (return_status);
}

Calling the Printer Server Function

The following code could be used to call the export_printer_to_fns() routine shown above.


export_printer_to_fns
    "thisorgunit/service/printer/colorful",
	    "onc_printers",
	    "onc_bsdaddr",
	    "labpc");