📄 usedir.c
字号:
/*
** usedir.c -- Demonstrates how to use Client-Library to query the
** directory service for available servers.
**
** This program searches for Sybase server entries in the directory,
** prints a description of each entry found, and lets the user choose
** a server to connect to.
**
** Inputs
** -------
** None. The program relies on the directory driver configuration
** to specify the directory source and the subtree (DIT-Base) to
** search.
**
** If no directory driver is configured, the SYBASE interfaces file
** (or SQL.INI file for Windows and OS/2 machines) is searched.
** Directory drivers are configured in the driver configuration
** file (libtcl.cfg in the main Sybase installation directory).
**
** The username and password defined in example.h are used to
** connect to the chosen server.
**
** Outputs
** -------
** Displays each server's information until the user picks a server to
** connect to.
**
** Routines Used
** -------------
** ct_ds_dropobj
** ct_ds_lookup
** ct_ds_objinfo
** ct_callback
** ct_con_alloc, ct_con_drop
** ct_con_props
*/
/*
** C Standard libraries.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
** Include the Client-Library header file.
*/
#include <ctpublic.h>
/*
** Example header files.
** - example.h defines the user name, the password, and some global
** macros.
** - exutils.h prototypes the exutils.c utility routines. Any routine
** called here that begins with ex_ is defined in exutils.c
*/
#include "example.h"
#include "exutils.h"
/*
** Global data and structures.
*/
/*
** Login property values for connecting to the server.
*/
CS_STATIC CS_CHAR *Ex_appname = "Directory search example";
CS_STATIC CS_CHAR *Ex_user = EX_USERNAME;
CS_STATIC CS_CHAR *Ex_password = EX_PASSWORD;
/*
** AttributesToDisplay is a read-only static array used by
** the show_server_info() function. It contains the Object
** Identifier (OID) strings for the server attributes to
** display, in the order that they are to be displayed.
*/
typedef struct
{
CS_CHAR type_string[CS_MAX_DS_STRING];
CS_CHAR english_name[CS_MAX_DS_STRING];
} AttrForDisplay;
#define N_ATTRIBUTES 7
CS_STATIC AttrForDisplay AttributesToDisplay[N_ATTRIBUTES + 1] =
{
{CS_OID_ATTRSERVNAME, "Server name"},
{CS_OID_ATTRSERVICE, "Service type"},
{CS_OID_ATTRVERSION, "Server entry version"},
{CS_OID_ATTRSTATUS, "Server status"},
{CS_OID_ATTRADDRESS, "Network addresses"},
{CS_OID_ATTRRETRYCOUNT, "Connection retry count"},
{CS_OID_ATTRLOOPDELAY, "Connection retry loop delay"},
{"", ""}
};
/*
** (SERVER_INFO_LIST *) is the abstract data type that we use
** to collect a list of servers from the directory. The sil_
** routines operate on the list type.
*/
#define MAX_SERVER_LIST 256
typedef struct _server_info
{
CS_DS_OBJECT *object;
} SERVER_INFO;
typedef struct _server_info_list
{
SERVER_INFO *servers; /* Array of size MAX_SERVER_LIST */
CS_INT len;/* Current length of list */
} SERVER_INFO_LIST;
/*
** Private defines.
*/
#define STRLEN(s) ((s) == NULL ? 0 : strlen(s))
#define CHOOSE_SERVER_MAX_INPUT 128
/*
** Private prototypes.
*/
CS_RETCODE provider_setup PROTOTYPE((
CS_CONNECTION *conn
));
CS_RETCODE get_servers PROTOTYPE((
CS_CONNECTION *conn,
SERVER_INFO_LIST **servers
));
CS_RETCODE CS_PUBLIC directory_cb PROTOTYPE((
CS_CONNECTION *conn,
CS_INT reqid,
CS_RETCODE status,
CS_INT numentries,
CS_DS_OBJECT *ds_object,
CS_VOID *userdata
));
CS_RETCODE choose_server PROTOTYPE((
CS_CONNECTION *conn,
SERVER_INFO_LIST *slp,
CS_CHAR server_name [],
CS_INT buflen,
CS_INT *outlen
));
CS_RETCODE show_server_info PROTOTYPE((
CS_DS_OBJECT *ds_object,
FILE *outfile
));
CS_RETCODE attr_get_by_type PROTOTYPE((
CS_DS_OBJECT *ds_object,
CS_CHAR *attr_type_str,
CS_ATTRIBUTE *attr_metadata,
CS_ATTRVALUE **p_attrvals
));
CS_RETCODE attr_display_values PROTOTYPE((
CS_ATTRIBUTE *attr_meta,
CS_ATTRVALUE attr_vals[],
FILE *outfile
));
CS_RETCODE attr_val_as_string PROTOTYPE((
CS_ATTRIBUTE *attr_metadata,
CS_ATTRVALUE *val,
CS_CHAR *buf,
CS_INT buflen,
CS_INT *outlen
));
CS_RETCODE attr_enum_english_name PROTOTYPE((
CS_INT enum_val,
CS_OID *attr_type,
CS_CHAR *buffer,
CS_INT buflen,
CS_INT *outlen
));
int match_OID PROTOTYPE((
CS_OID *oid,
CS_CHAR *oid_string
));
CS_RETCODE sil_init_list PROTOTYPE((
SERVER_INFO_LIST **slp
));
CS_RETCODE sil_drop_list PROTOTYPE((
CS_CONNECTION *conn,
SERVER_INFO_LIST *slp
));
CS_RETCODE sil_add_object PROTOTYPE((
SERVER_INFO_LIST *slp,
CS_DS_OBJECT *ds_object
));
CS_RETCODE sil_extract_object PROTOTYPE((
SERVER_INFO_LIST *slp,
CS_INT number,
CS_DS_OBJECT **p_dsobject
));
CS_INT sil_list_len PROTOTYPE((
SERVER_INFO_LIST *slp
));
/*
** main() -- Entry point for our program.
*/
int
main()
{
CS_RETCODE ret;
CS_CONTEXT *ctx;
CS_CONNECTION *conn1;
CS_CONNECTION *conn2;
SERVER_INFO_LIST *servers;
CS_CHAR server_name[512];
EX_SCREEN_INIT();
/*
** Initialize CS-Library and Client-Library.
*/
ret = ex_init(&ctx);
if (ret != CS_SUCCEED)
{
ex_panic("Initialization failed.");
}
/*
** Allocate a connection structure. We need it to query the
** directory.
*/
ret = ct_con_alloc(ctx, &conn1);
if (ret != CS_SUCCEED)
{
ex_panic("ct_con_alloc() failed.");
}
/*
** Get a list of available servers.
*/
ret = get_servers(conn1, &servers);
if (ret != CS_SUCCEED)
{
ex_panic("get_servers() failed.");
}
/*
** Let the user choose a server and attempt a connection to it.
*/
ret = choose_server(conn1, servers, server_name, 512, NULL);
if (ret != 0)
{
/*
** User chose to quit, or an error occurred. In either
** case, clean up and exit.
*/
fprintf(stdout, "Exiting.\n");
(CS_VOID)sil_drop_list(conn1, servers);
ret = ct_con_drop(conn1);
ret = ex_ctx_cleanup(ctx, ret);
exit(ret == 1 ? EX_EXIT_SUCCEED : EX_EXIT_FAIL);
}
/*
** Connect to the chosen server. We could do this with the same
** connection, that we used to query the directory. We don't do
** that here because ex_connect() won't use a pre-allocated
** connection.
*/
fprintf(stdout, "Connecting to %s ...\n", server_name);
ret = ex_connect(ctx, &conn2, Ex_appname, Ex_user, Ex_password,
server_name);
if (ret != CS_SUCCEED)
{
ex_panic("Connect attempt failed.");
}
/*
** Drop the list of servers.
*/
ret = sil_drop_list(conn1, servers);
if (ret != CS_SUCCEED)
{
ex_panic("sil_drop_list() failed.");
}
/*
** Clean up Client-Library and drop the CS_CONTEXT. We can't use
** ex_con_cleanup() on conn1 because it's not open.
*/
ret = ct_con_drop(conn1);
if (ret != CS_SUCCEED)
{
ex_error("Cleanup of connection 1 failed.");
}
ret = ex_con_cleanup(conn2, ret);
if (ret != CS_SUCCEED)
{
ex_error("Cleanup of connection 2 failed.");
}
ret = ex_ctx_cleanup(ctx, ret);
if (ret != CS_SUCCEED)
{
ex_error("Context-level cleanup failed.");
}
exit(EX_EXIT_SUCCEED);
} /* main() */
/*
** get_servers() -- Query the directory for servers and
** get a list of directory objects that contain details
** for each.
**
** Parameters
** conn -- Pointer to allocated connection structure.
** pserver_list -- Address of a pointer to a SERVER_INFO_LIST.
** Upon successful return, the list will be initialized
** and contain an object for each server found in the
** search.
**
** NOTE: The caller must clean up the list with sil_drop_list()
** when done with it.
**
** Returns
** CS_SUCCEED or CS_FAIL.
*/
CS_RETCODE
get_servers(conn, pserver_list)
CS_CONNECTION *conn;
SERVER_INFO_LIST **pserver_list;
{
CS_RETCODE ret;
CS_INT reqid;
CS_VOID *oldcallback;
CS_OID oid;
CS_DS_LOOKUP_INFO lookup_info;
/*
** Steps for synchronous-mode directory searches:
**
** 1. If necessary, initialize application specific data structures
** (Our application collects directory objects in *pserver_list).
** 2. Save the old directory callback and install our own (the
** directory_cb function, found below).
** 3. (Optional -- Network based directories only)
** Set the base node in the directory to search beneath
** (CS_DS_DITBASE property).
** 4. Call ct_ds_lookup to begin the search, passing
** any application specific data structures as the userdata
** argument.
** 5. Client-Library invokes our callback once for each
** found object. directory_cb() inserts each directory
** object to the list of servers.
** 6. Check the return status of ct_ds_lookup.
** 7. Restore callbacks and properties
** that we changed.
*/
/*
** Step 1. Initialize the data structure (*pserver_list).
*/
ret = sil_init_list(pserver_list);
if (ret != CS_SUCCEED || (*pserver_list) == NULL)
{
ex_error("get_servers: Could not initialize list.");
return CS_FAIL;
}
/*
** Step 2. Save the old directory callback and install our own
** callback, directory_cb(), to receive the found objects.
*/
ret = ct_callback(NULL, conn, CS_GET,
CS_DS_LOOKUP_CB, &oldcallback);
if (ret == CS_SUCCEED)
{
ret = ct_callback(NULL, conn, CS_SET,
CS_DS_LOOKUP_CB, (CS_VOID *)directory_cb);
}
if (ret != CS_SUCCEED)
{
ex_error("get_servers: Could not install directory callback.");
return CS_FAIL;
}
/*
** Step 3. Set the base node in the directory to search beneath
** (the CS_DS_DITBASE connection property).
*/
ret = provider_setup(conn);
if (ret != CS_SUCCEED)
{
ex_error("get_servers: Provider-specific setup failed.");
return CS_FAIL;
}
/*
** Step 4. Call ct_ds_lookup to begin the search, passing the
** server list pointer as userdata. Step 5. Client-Library invokes
** our callback once for each found object (or once to report that
** no objects were found). Our callback, directory_cb, will
** receives a pointer to each found server object and appends it
** to the list. Step 6. Check the return status of ct_ds_lookup.
*/
/*
** Set the CS_DS_LOOKUP_INFO structure fields.
*/
lookup_info.path = NULL;
lookup_info.pathlen = 0;
lookup_info.attrfilter = NULL;
lookup_info.attrselect = NULL;
strcpy(oid.oid_buffer, CS_OID_OBJSERVER);
oid.oid_length = STRLEN(oid.oid_buffer);
lookup_info.objclass = &oid;
/*
** Begin the search.
*/
ret = ct_ds_lookup(conn, CS_SET, &reqid,
&lookup_info, (CS_VOID *)pserver_list);
if (ret != CS_SUCCEED)
{
ex_error("get_servers: Could not run search.");
return CS_FAIL;
}
/*
** Step 7. Restore callbacks and properties that we changed.
*/
ret = ct_callback(NULL, conn, CS_SET,
CS_DS_LOOKUP_CB, oldcallback);
if (ret != CS_SUCCEED)
{
ex_error("get_servers: Could not restore directory callback.");
return CS_FAIL;
}
return CS_SUCCEED;
} /* get_servers() */
/*
** directory_cb() -- Directory callback to install in Client-Library.
** When we call ct_ds_lookup(), Client-Library calls this function
** once for each object that is found in the search.
**
** This particular callback collects the objects in
** the SERVER_INFO_LIST that is received as userdata.
**
** Parameters
** conn -- The connection handle passed to ct_ds_lookup() to
** begin the search.
** reqid -- The request id for the operation (assigned by Client-Library).
** status -- CS_SUCCEED when search succeeded (ds_object is valid).
** CS_FAIL if the search failed (ds_object is not valid).
** numentries -- The count of objects to be returned for the
** search. Includes the current object. Can be 0 if search
** failed.
** ds_object -- Pointer to a CS_DS_OBJECT structure. Will
** be NULL if the search failed.
** userdata -- The address of user-allocated data that was
** passed to ct_ds_lookup().
**
** This particular callback requires userdata to be the
** address of a valid, initialized SERVER_INFO_LIST pointer.
** (SERVER_INFO_LIST is an application data structure defined
** by this sample).
**
** Returns
** CS_CONTINUE unless the SERVER_INFO_LIST pointed at by userdata fills
** up, then CS_SUCCEED to truncate the search results.
*/
CS_RETCODE CS_PUBLIC
directory_cb(conn, reqid, status, numentries, ds_object, userdata)
CS_CONNECTION *conn;
CS_INT reqid;
CS_RETCODE status;
CS_INT numentries;
CS_DS_OBJECT *ds_object;
CS_VOID *userdata;
{
CS_RETCODE ret;
SERVER_INFO_LIST *server_list;
if (status != CS_SUCCEED
|| numentries <= 0
|| ds_object == (CS_DS_OBJECT *)NULL)
{
return CS_SUCCEED;
}
/*
** Append the object to the list of servers.
*/
server_list = *((SERVER_INFO_LIST **)userdata);
ret = sil_add_object(server_list, ds_object);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -