553 lines
16 KiB
HTML
553 lines
16 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<meta name="Copyright" content="Copyright (c) 2006 by IBM Corporation">
|
||
|
<title>gsk_secure_soc_startSend()--Start asynchronous send operation on a
|
||
|
secure session</title>
|
||
|
<!-- Begin Header Records -->
|
||
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
||
|
<!-- US Government Users Restricted Rights -->
|
||
|
<!-- Use, duplication or disclosure restricted by -->
|
||
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
||
|
<!-- Change History: -->
|
||
|
<!-- Created for V5R1 -->
|
||
|
<link rel="stylesheet" type="text/css" href="../rzahg/ic.css">
|
||
|
</head>
|
||
|
<body>
|
||
|
<!-- End Header Records -->
|
||
|
<!--Java sync-link-->
|
||
|
<script type="text/javascript" language="Javascript" src="../rzahg/synch.js">
|
||
|
</script>
|
||
|
|
||
|
<a name="Top_Of_Page"></a>
|
||
|
|
||
|
<h2>gsk_secure_soc_startSend()--Start asynchronous send operation on a secure
|
||
|
session</h2>
|
||
|
|
||
|
<div class="box" style="width: 80%;">
|
||
|
<br>
|
||
|
Syntax
|
||
|
|
||
|
<pre>
|
||
|
#include <gskssl.h>
|
||
|
#include <qsoasync.h>
|
||
|
|
||
|
int gsk_secure_soc_startSend (gsk_handle my_session_handle,
|
||
|
int IOCompletionPort,
|
||
|
Qso_OverlappedIO_t * communicationsArea)
|
||
|
|
||
|
</pre>
|
||
|
|
||
|
Service Program Name: QSYS/QSOSSLSR<br>
|
||
|
<!-- iddvc RMBR -->
|
||
|
<br>
|
||
|
Default Public Authority: *USE<br>
|
||
|
<!-- iddvc RMBR -->
|
||
|
<br>
|
||
|
Threadsafe: Yes<br>
|
||
|
<!-- iddvc RMBR -->
|
||
|
<br>
|
||
|
</div>
|
||
|
|
||
|
<p>The <strong>gsk_secure_soc_startSend()</strong> function is used to initiate
|
||
|
an asynchronous send operation on a secure session. The supplied send buffer
|
||
|
cannot be reused by the calling application until the send is complete or the
|
||
|
I/O completion port specified on the
|
||
|
<strong>gsk_secure_soc_startSend()</strong> has been destroyed. This API
|
||
|
supports sockets with an address family of AF_INET or AF_INET6 and type SOCK_STREAM only.</p>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Parameters</h3>
|
||
|
|
||
|
<dl>
|
||
|
<dt><em><strong>my_session_handle</strong></em> (Input)</dt>
|
||
|
|
||
|
<dd>The handle, returned from <strong>gsk_secure_soc_open()</strong> and used
|
||
|
on the <strong>gsk_secure_soc_init()</strong> API call that initialized the
|
||
|
secure session over which data is to be written.<br>
|
||
|
<br>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em><strong>int IOCompletionPort</strong></em> (Input)</dt>
|
||
|
|
||
|
<dd>The I/O completion port that should be posted when the operation
|
||
|
completes.<br>
|
||
|
<br>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em><strong>Qso_OverlappedIO_t</strong> *
|
||
|
communicationsArea</em> (Input/Output)</dt>
|
||
|
|
||
|
<dd>A pointer to a structure that contains the following information:<br>
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<table cellpadding="5">
|
||
|
<!-- cols="25 75" -->
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>descriptorHandle</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - The descriptor handle is
|
||
|
application-specific and is never used by the system. This field is intended to
|
||
|
make it easier for the application to keep track of information regarding a
|
||
|
given socket connection.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>buffer</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - A pointer to a buffer of data that
|
||
|
should be sent over the socket.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>bufferLength</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - The length of the data to be sent.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>postFlag</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - The postFlag indicates if this
|
||
|
operation should be posted to the I/O completion port even if it completes
|
||
|
immediately.
|
||
|
|
||
|
<ul>
|
||
|
<li>A value of 0 indicates that if the operation is already complete upon
|
||
|
return to the application, then do not post to the I/O completion port.</li>
|
||
|
|
||
|
<li>A value of 1 indicates that even if the operation completes immediately
|
||
|
upon return to the application, the result should still be posted to the I/O
|
||
|
completion port.</li>
|
||
|
</ul>
|
||
|
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>postFlagResult</em></strong> </td>
|
||
|
<td align="left" valign="top">(Output) - This field is valid if
|
||
|
gsk_secure_soc_startSend() returns with 1 and postFlag was set to 1. In this
|
||
|
scenario, postFlagResult set to 1 denotes the operation completed and been
|
||
|
posted to the I/O completion port specified. A value of 0 denotes the operation
|
||
|
could not be completed immediately, but will be handled asynchronously.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>fillBuffer</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - Only used on
|
||
|
<strong>gsk_secure_soc_startRecv()</strong> or <strong>QsoStartRecv()</strong>.
|
||
|
Ignored on <strong>gsk_secure_soc_startSend()</strong>.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>returnValue</em></strong> </td>
|
||
|
<td align="left" valign="top">(Output) - If gsk_secure_soc_startSend()
|
||
|
completes synchronously (return value equals GSK_OK), then this field is set to
|
||
|
GSK_OK and field secureDataTransferSize indicates number of bytes sent.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><em><strong>errnoValue</strong></em> </td>
|
||
|
<td align="left" valign="top">(Output) - When the operation has completed
|
||
|
asynchronously and returnValue is GSK_ERROR_IO, this field will contain an
|
||
|
errno further defining the failure.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>operationCompleted</em></strong>
|
||
|
</td>
|
||
|
<td align="left" valign="top">(Output) - If the operation is posted to the I/O
|
||
|
completion port, this field is updated to indicate that the operation was a
|
||
|
GSKSECURESOCSTARTSEND.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>secureDataTransferSize</em></strong>
|
||
|
</td>
|
||
|
<td align="left" valign="top">(Ouput) - Number of bytes sent when
|
||
|
<strong>gsk_secure_soc_startSend()</strong> completes synchronously (function
|
||
|
return value equals GSK_OK).<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>bytesAvailable</em></strong> </td>
|
||
|
<td align="left" valign="top">Not used. </td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>operationWaitTime</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - A timeval structure which specifies the
|
||
|
maximum time allowed for this operation to complete asynchronously.
|
||
|
|
||
|
<pre>
|
||
|
struct timeval {
|
||
|
long tv_sec; /* second */
|
||
|
long tv_usec; /* microseconds */
|
||
|
};
|
||
|
</pre>
|
||
|
|
||
|
If this timer expires, the operation will be posted to the I/O completion port
|
||
|
with <em>errnoValue</em> set to EAGAIN.<br>
|
||
|
<br>
|
||
|
If this field is set to zero, the operation's asynchronous completion will not
|
||
|
be timed.<br>
|
||
|
<br>
|
||
|
If socketDescriptor is closed before the operation completes or times out, the
|
||
|
operation will be posted to the I/O completion port with <em>errnoValue</em>
|
||
|
set to ECLOSED.<br>
|
||
|
<br>
|
||
|
The minimum operationWaitTime is 1 second. The microseconds field (tv_usec) in
|
||
|
the timeval is not used and must be set to zero. </td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>postedDescriptor</em></strong> </td>
|
||
|
<td align="left" valign="top">Not used - Must be set to zero. </td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>reserved1</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - Must be set to hex zeroes.<br>
|
||
|
<br>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top"><strong><em>reserved2</em></strong> </td>
|
||
|
<td align="left" valign="top">(Input) - Must be set to hex zeroes. </td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</dd>
|
||
|
</dl>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Authorities</h3>
|
||
|
|
||
|
<p>No authorization is required.</p>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Return Values</h3>
|
||
|
|
||
|
<p><strong>gsk_secure_soc_startSend()</strong> returns an integer. Possible
|
||
|
values are:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li>GSK_OK- The function has completed synchronously. The Qso_OverlappedIO_t
|
||
|
communications structure has been updated but nothing has nor will be posted to
|
||
|
the I/O completion port for this operation. Inspect field
|
||
|
secureDataTransferSize in the Qso_OverlappedIO_t communications structure to
|
||
|
determine the number of bytes sent.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>GSK_AS400_ASYNCHRONOUS_SEND - The function has been started. When the
|
||
|
function completes (or times
|
||
|
out if operationWaitTime was specified), the Qso_OverlappedIO_t communications structure will be
|
||
|
updated with the results and the I/O completion port will be posted.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>If the function fails, possible values are:<br>
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<dl>
|
||
|
<dt>[GSK_INVALID_HANDLE]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The handle specified was not valid.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_INVALID_STATE]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The handle is not in the correct state for this operation.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_INVALID_BUFFER SIZE]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The bufferLength field located in the Qso_OverLappedIO_t communications area
|
||
|
is less than 1.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_ERROR_SOCKET_CLOSED]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>A <strong>close()</strong> was done on the socket descriptor for this secure
|
||
|
session.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_ AS400_ERROR_INVALID_POINTER]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The buffer pointer located in Qso_OverlappedIO_t communications area is not
|
||
|
valid.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_INTERNAL_ERROR]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>An unexpected error occurred during SSL processing.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_AS400_ERROR_INVALID_ OVERLAPPEDIO_T]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The Qso_OverLappedIO_t specified was not valid.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_AS400_ERROR_INVALID_ IOCOMPLETIONPORT]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The I/O completion port specified was not valid.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>[GSK_AS400_ERROR_BAD_SOCKET_DESCRIPTOR]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The socket descriptor specified within the gsk_handle was not valid.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt>GSK_ERROR_IO]</dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>An error occured in SSL processing; check the <strong>errno</strong>
|
||
|
value.</p>
|
||
|
</dd>
|
||
|
</dl>
|
||
|
</li>
|
||
|
</ul>
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Error Conditions</h3>
|
||
|
|
||
|
<p>When <strong>gsk_secure_soc_startSend()</strong> API fails with return code
|
||
|
[GSK_ERROR_IO], <em>errno</em> can be set to:</p>
|
||
|
|
||
|
<dl>
|
||
|
<dt><em>[EINVAL]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The field operationWaitTime.tv_sec was negative or operationWaitTime.tv_usec
|
||
|
was not zero or postedDescriptor was not zero.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em>[EIO]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>Input/output error.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em>[ENOTCONN]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>Requested operation requires a connection.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em>[ENOTSOCK]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The specified descriptor does not reference a socket.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em>[EPIPE]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>Broken pipe.</p>
|
||
|
</dd>
|
||
|
|
||
|
<dt><em>[EUNATCH]</em></dt>
|
||
|
|
||
|
<dd>
|
||
|
<p>The protocol required to support the specified address family is not
|
||
|
available at this time.</p>
|
||
|
</dd>
|
||
|
</dl>
|
||
|
<p>If an <em>errno</em> is returned that is not in this list, see <a href=
|
||
|
"unix14.htm">Errno Values for UNIX-Type Functions</a> for a description of the
|
||
|
<em>errno</em>.</p>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Error Messages</h3>
|
||
|
|
||
|
<table width="100%" cellpadding="5">
|
||
|
<!-- cols="15 85" -->
|
||
|
<tr>
|
||
|
<th align="left" valign="top">Message ID</th>
|
||
|
<th align="left" valign="top">Error Message Text</th>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td width="15%" valign="top">CPE3418 E</td>
|
||
|
<td width="85%" valign="top">Possible APAR condition or hardware failure.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top">CPF9872 E</td>
|
||
|
<td align="left" valign="top">Program or service program &1 in library &2 ended.
|
||
|
Reason code &3.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td align="left" valign="top">CPFA081 E</td>
|
||
|
<td align="left" valign="top">Unable to set return value or error code.</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Usage Notes</h3>
|
||
|
|
||
|
<ol>
|
||
|
<li>Since <strong>gsk_secure_soc_startSend()</strong> is asynchronous, care
|
||
|
should be used to control how many of these functions are outstanding. When a
|
||
|
TCP socket becomes flow control blocked such that the
|
||
|
<strong>gsk_secure_soc_startSend()</strong> is not able to pass the data to the
|
||
|
TCP socket immediately, the return value will be GSK_AS400_ASYNCHRONOUS_SEND.
|
||
|
Applications that send large amounts of data should have the postFlag set to 0.
|
||
|
This allows the application to use a return value of
|
||
|
GSK_AS400_ASYNCHRONOUS_SEND as an indication that the socket has become flow
|
||
|
control blocked. The application should then wait for the outstanding operation
|
||
|
to complete before issuing another <strong>gsk_secure_soc_startSend()</strong>.
|
||
|
This will ensure that the application does not exhaust system buffer
|
||
|
resources.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>A buffer that is given to <strong>gsk_secure_soc_startSend()</strong> must
|
||
|
not be used by the application again until either it is returned by
|
||
|
QsoWaitForIOCompletion() or is reclaimed by issuing a close() on the socket
|
||
|
descriptor or issuing a QsoDestroyIOCompletionPort() on the I/O completion
|
||
|
port. If a buffer is given to <strong>gsk_secure_soc_startSend()</strong> to be
|
||
|
sent, and it is later detected during
|
||
|
<strong>gsk_secure_soc_startSend()</strong> processing that the buffer has been
|
||
|
freed, it may produce an unrecoverable condition on the socket for which the
|
||
|
<strong>gsk_secure_soc_startSend()</strong> was issued. If this occurs, an
|
||
|
ECONNABORTED error value will be returned.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>There is no maximum length of data that can be written.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>It is not recommended to intermix
|
||
|
<strong>gsk_secure_soc_startSend()</strong> and blocking I/O (ie, send() or
|
||
|
gsk_secure_soc_send()) on the same socket. If one does, then pending
|
||
|
asynchronous send I/O will be serviced before blocking I/O once data can be
|
||
|
sent.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
<li>It is strongly suggested that you do not mix the
|
||
|
<strong>gsk_secure_soc_write()</strong> nor
|
||
|
<strong>gsk_secure_soc_startSend()</strong> APIs with any of the sockets write
|
||
|
functions. However, SSL and socket reads and writes can be mixed, but they must
|
||
|
be performed in matched sets. If a client application writes 100 bytes of data
|
||
|
using one or more of the socket send() calls, then the server application must
|
||
|
read exactly 100 bytes of data using one or more of the socket recv() calls.
|
||
|
This is also true for <strong>gsk_secure_soc_write()</strong> and
|
||
|
<strong>gsk_secure_soc_startSend()</strong>APIs.</li>
|
||
|
|
||
|
<li>Socket option SO_SNDTIMEO
|
||
|
is not supported by this API. Semantics similar to SO_SNDTIMEO can be obtained
|
||
|
using the operationWaitTime field in the Qso_OverLappedIO_t structure.<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
</ol>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Related Information</h3>
|
||
|
|
||
|
<ul>
|
||
|
<li><a href="gsk_secure_soc_init.htm">gsk_secure_soc_init()</a>--Negotiate a secure
|
||
|
session<br><br></li>
|
||
|
|
||
|
<li><a href="gsk_secure_soc_misc.htm">gsk_secure_soc_misc()</a>--Perform
|
||
|
miscellaneous functions for a secure session<br><br></li>
|
||
|
|
||
|
<li><a href="gsk_secure_soc_open.htm">gsk_secure_soc_open()</a>--Get a handle for a
|
||
|
secure session<br><br></li>
|
||
|
|
||
|
<li><a href="gsk_secure_soc_read.htm">gsk_secure_soc_read()</a>--Receive data on a
|
||
|
secure session<br><br></li>
|
||
|
|
||
|
|
||
|
<li><a href="gskstartinit.htm">gsk_secure_soc_startInit()</a>--Start asynchronous
|
||
|
operation to negotiate a secure session<br>
|
||
|
<br>
|
||
|
</li>
|
||
|
|
||
|
|
||
|
<li><a href="gskstartrecv.htm">gsk_secure_soc_startRecv()</a>--Start Asynchronous
|
||
|
Receive Operation on a Secure Session<br><br></li>
|
||
|
|
||
|
<li><a href="postiocompletion.htm">QsoPostIOCompletionPort()</a>--Post Request on
|
||
|
I/O Completion Port<br><br></li>
|
||
|
|
||
|
<li><a href="createiocompletionport.htm">QsoCreateIOCompletionPort()</a>--Create
|
||
|
I/O Completion Port<br><br></li>
|
||
|
|
||
|
<li><a href="destroyiocompletionport.htm">QsoDestroyIOCompletionPort()</a>--Destroy
|
||
|
I/O Completion Port<br><br></li>
|
||
|
|
||
|
<li><a href="startrecv.htm">QsoStartRecv</a>--Start Asynchronous Recv
|
||
|
Operation<br><br></li>
|
||
|
|
||
|
<li><a href="startsend.htm">QsoStartSend</a>--Start Asynchronous Send
|
||
|
Operation<br><br></li>
|
||
|
|
||
|
<li><a href="waitforiocompletion.htm">QsoWaitForIOCompletion()</a>--Wait for I/O
|
||
|
Completion Operation<br><br></li>
|
||
|
|
||
|
<li><a href="send.htm">send()</a>--Send Data</li>
|
||
|
</ul>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<hr>
|
||
|
API introduced: V5R1
|
||
|
|
||
|
<hr>
|
||
|
<center>
|
||
|
<table cellpadding="2" cellspacing="2">
|
||
|
<tr align="center">
|
||
|
<td valign="middle" align="center"><a href="#Top_Of_Page">Top</a> | <a href=
|
||
|
"unix.htm">UNIX-Type APIs</a> | <a href="aplist.htm">APIs by category</a> </td>
|
||
|
</tr>
|
||
|
</table></center>
|
||
|
</body>
|
||
|
</html>
|
||
|
|