$Header: /cvsroot/aolserver/aolserver.com/docs/devel/c/index.html,v 1.1 2002/03/07 19:15:35 kriston Exp $
int Ns_BindSock (
struct sockaddr_in* saPtr
);
char *Ns_ConnAuthPasswd(
Ns_Conn *conn
);
/* PassTrace - A server trace to log users and passwords. */
void
PassTrace(void *ctx, Ns_Conn *conn)
{
char *user;
char *pass;
user = Ns_ConnAuthUser(conn);
pass = Ns_ConnAuthPasswd(conn);
if (user != NULL && pass != NULL) {
Ns_Log(Notice, "User: %s Password: %s", user, pass);
}
}
char *Ns_ConnAuthUser(
Ns_Conn *conn
);
See the example for Ns_ConnAuthPasswd.
int Ns_ConnClose(
Ns_Conn *conn
);
This function is called by AOLserver before running any registered traces. You do not normally need to call it.
void Ns_ConnCondSetHeaders(
Ns_Conn *conn,
char *field,
char *value
);
/* Set a Cookie header if not already set. */
Ns_ConnCondSetHeaders(conn, "Cookie", "randomStuff");
void Ns_ConnConstructHeaders(
Ns_Conn *conn,
Ns_DString *dsPtr
);
int Ns_ConnContentLength(
Ns_Conn *conn
);
/* Copy the content from the browser to a DString. */
Ns_DString ds;
int len;
Ns_DStringInit(&ds);
len = Ns_ConnContentLength(conn);
Ns_ConnCopyToDString(conn, len, &ds);
int Ns_ConnContentSent (
Ns_Conn* conn
);
int Ns_ConnCopyToChannel (
Ns_Conn* conn,
size_t iToCopy,
Tcl_Channel chan
);
int Ns_ConnCopyToDString(
Ns_Conn *conn,
size_t iToCopy,
Ns_DString *pds
);
See the example for Ns_ConnContentLength.
int Ns_ConnCopyToFd (
Ns_Conn* conn,
size_t iToCopy,
int fd
);
int Ns_ConnCopyToFile(
Ns_Conn *conn,
size_t iToCopy,
FILE *fp
);
/* Copy the content from the browser to a file. */
FILE *fp;
int len;
fp = fopen("content.out", "w");
len = Ns_ConnContentLength(conn);
Ns_ConnCopyToFile(conn, len, fp);
fclose(fp);
void *Ns_ConnDriverContext(
Ns_Conn *conn
);
char *Ns_ConnDriverName(
Ns_Conn *conn
);
int Ns_ConnFlushContent (
Ns_Conn* conn
);
int Ns_ConnFlushHeaders(
Ns_Conn *conn,
int status
);
The status is a standard error code such as 403 for access denied or 200 for OK. Returns NS_OK or NS_ERROR.
This function is normally required just before sending content to the client.
/* A simple Hello request function. */
int
MyHello(Ns_Conn *conn, void *ctx)
{
char hello[] = "hello";
int len;
len = strlen(hello);
Ns_ConnSetRequiredHeaders(conn, "text/plain", len);
Ns_ConnFlushHeaders(conn, 200);
return Ns_ConnWrite(conn, hello, len);
}
Ns_Set *Ns_ConnGetQuery(
Ns_Conn *conn
);
Note that you must not call Ns_SetFree on the result of this function.
/* Get the value from an form tag. */
Ns_Set *set;
char *value;
set = Ns_ConnGetQuery(conn);
if (set != NULL) {
value = Ns_SetGetValue(set, "mydata");
}
char *Ns_ConnGets(
char *buf,
size_t sz,
Ns_Conn *conn
);
Ns_Set *Ns_ConnHeaders(
Ns_Conn *conn
);
/* Log the Referer header. */
Ns_Set *headers;
char *refer;
headers = Ns_ConnHeaders(conn);
if (headers != NULL) {
refer = Ns_SetGet(headers, "Referer");
if (refer != NULL) {
Ns_Log(Notice, "Referer: %s", refer);
}
}
char *Ns_ConnHost(
Ns_Conn *conn
);
int Ns_ConnInit (
Ns_Conn* connPtr
);
char *Ns_ConnLocation(
Ns_Conn *conn
);
Multiple communications drivers can be loaded into a single server. This means a server may have more than one location. For example, if the nsssl module is loaded and bound to port 8000 and the nssock module is loaded and bound to port 9000, the server would have the following two locations: http://www.avalon.com:9000 https://www.avalon.com:8000 For this reason it is important to use the Ns_ConnLocation function to determine the driver location at run time.
int Ns_ConnModifiedSince(
Ns_Conn *conn,
time_t mtime
);
Ns_Set * Ns_ConnOutputHeaders(
Ns_Conn *conn
);
char *Ns_ConnPeer(
Ns_Conn *conn
);
The peer address is determined by the communications driver in use by the connection. Typically it is a dotted IP address, for example, 199.221.53.205, but this is not guaranteed.
int Ns_ConnPeerPort (
Ns_Conn* conn
);
int Ns_ConnPort(
Ns_Conn *conn
);
int Ns_ConnPrintfHeader(
Ns_Conn *conn,
char *fmt,
...
);
int Ns_ConnPuts(
Ns_Conn *conn,
char *string
);
int Ns_ConnRead(
Ns_Conn *conn,
void *pvBuf,
int iToRead
);
/* Read content from the browser into buf. */
char buf[1024];
Ns_ConnRead(conn, buf, sizeof(buf));
int Ns_ConnReadHeaders (
Ns_Conn* conn,
Ns_Set* psetHeaders,
int* iRead
);
int Ns_ConnReadLine(
Ns_Conn *conn,
Ns_DString *pdsLine,
int* *iRead
);
int Ns_ConnRedirect (
Ns_Conn* conn,
char* url
);
void Ns_ConnReplaceHeaders(
Ns_Conn *conn,
Ns_Set *newheaders
);
int Ns_ConnResponseLength(
Ns_Conn *conn
);
int Ns_ConnResponseStatus(
Ns_Conn *conn
);
void Ns_ConnReturnAdminNotice(
Ns_Conn *conn,
int status,
char *notice,
char *html
);
int Ns_ConnReturnBadRequest(
Ns_Conn *conn,
char *reason
);
EXTERN int Ns_ConnReturnData(
Ns_Conn *conn,
int status,
char *html,
int len,
char *type
);
int Ns_ConnReturnFile(
Ns_Conn *conn,
int status,
char *type,
char *file
);
int Ns_ConnReturnForbidden(
Ns_Conn *conn
);
int Ns_ConnReturnHtml(
Ns_Conn *conn,
int status,
char *html,
int len
);
int Ns_ConnReturnInternalError(
Ns_Conn *conn
);
int Ns_ConnReturnNoResponse(
Ns_Conn *conn
);
int Ns_ConnReturnNotFound(
Ns_Conn *conn
);
int Ns_ConnReturnNotice(
Ns_Conn *conn,
int status,
char *notice,
char *html
);
int Ns_ConnReturnNotImplemented(
Ns_Conn *conn
);
int Ns_ConnReturnNotModified(
Ns_Conn *conn
);
int Ns_ConnReturnOk(
Ns_Conn *conn
);
int Ns_ConnReturnOpenChannel (
Ns_Conn* conn,
int status,
char* type,
Tcl_Channel chan,
int len
);
int Ns_ConnReturnOpenFile(
Ns_Conn *conn,
int status,
char *type,
int fd,
int len
);
int Ns_ConnReturnOpenFile(
Ns_Conn *conn,
int status,
char *type,
FILE *fp,
int len
);
int Ns_ConnReturnRedirect(
Ns_Conn *conn,
char *location
);
int Ns_ConnReturnStatus(
Ns_Conn *conn,
int status
);
The status is a standard error code such as 403 for access denied or 200 for OK. Returns NS_OK or NS_ERROR.
int Ns_ConnReturnUnauthorized(
Ns_Conn *conn
);
int Ns_ConnRunRequest(
Ns_Conn *conn
);
int Ns_ConnSendChannel (
Ns_Conn* conn,
Tcl_Channel chan,
int len
);
int Ns_ConnSendDString(
Ns_Conn *conn,
Ns_DString *dsPtr
);
int Ns_ConnSendFd(
Ns_Conn *conn,
int fd,
int len
);
int Ns_ConnSendFp(
Ns_Conn *conn,
FILE *fp,
int len
);
char *Ns_ConnServer(
Ns_Conn *conn
);
void Ns_ConnSetExpiresHeader(
Ns_Conn *conn,
char *httptime
);
void Ns_ConnSetHeaders(
Ns_Conn *conn,
char *field,
char *value
);
void Ns_ConnSetLastModifiedHeader(
Ns_Conn *conn,
time_t *when
);
void Ns_ConnSetLengthHeader(
Ns_Conn *conn,
int len
);
void Ns_ConnSetRequiredHeaders(
Ns_Conn *conn,
char *contentType,
int contentLength
);
The Ns_ConnReturnStatus function can be used to return a status-only response to the client.
void Ns_ConnSetTypeHeader(
Ns_Conn *conn,
char *type
);
int Ns_ConnWrite(
Ns_Conn *conn,
void *buf,
int len
);
/* Write towrite bytes from buf. */
while (towrite > 0) {
int nwrote;
nwrote = Ns_ConnWrite(conn, buf, towrite);
if (nwrote == -1) {
/* ... handle error ... */
}
buf += nwrote;
towrite -= nwrote;
}
void Ns_DriverEnableKeepalive (
Ns_Driver driver
);
Ns_Driver Ns_GetDriver (
char* hServer,
char* hDriver
);
void* Ns_GetDriverContext (
Ns_Driver drv
);
char* Ns_GetDriverLabel (
Ns_Driver driver
);
char* Ns_GetDriverName (
Ns_Driver driver
);
int Ns_GetDriverProc(
Ns_Driver driver,
Ns_DrvId id,
void **pprocPtrPtr
);
The procPtrPtr will be filled in with the address of a registerd driver function. NS_ERROR will be returned if no registered function could be found. The resulting function is of the type shown in the right column below
ID Value
Resulting Function Type
Ns_DrvIdName
typedef char *(Ns_ConnDriverNameProc) (void *pConnCtx);
Ns_DrvIdStart
typedef int (Ns_DriverStartProc) (char *hServer, char *hDriver, void **ppDriverCtx);
Ns_DrvIdAccept
typedef int (Ns_DriverAcceptProc) (void *pDriverCtx, void **ppConnCtx);
Ns_DrvIdStop
typedef void (Ns_DriverStopProc) (void *pDriverCtx);
Ns_DrvIdInit
typedef int (Ns_ConnInitProc) (void *pConnCtx);
Ns_DrvIdRead
typedef int (Ns_ConnReadProc) (void *pConnCtx, void *pvBuf, int iToRead);
Ns_DrvIdWrite
typedef int (Ns_ConnWriteProc) (void *pConnCtx, void *pvBuf, int iToWrite);
Ns_DrvIdClose
typedef int (Ns_ConnCloseProc) (void *pConnCtx);
Ns_DrvIdFree
typedef void (Ns_ConnFreeProc) (void *pConnCtx);
Ns_DrvIdPeer
typedef char *(Ns_ConnPeerProc) (void *pConnCtx);
Ns_DrvIdLocation
typedef char *(Ns_ConnLocationProc) (void *pConnCtx);
Ns_DrvIdHost
typedef char *(Ns_ConnHostProc) (void *pConnCtx);
Ns_DrvIdPort
typedef int (Ns_ConnPortProc) (void *pConnCtx);
Ns_DrvIdSendFd
typedef int (Ns_ConnSendFdProc) (void *pConnCtx, int fd, int nsend);
Ns_DrvIdSendFile
typedef int (Ns_ConnSendFileProc) (void *pConnCtx, char *file);
Ns_DrvIdDetach
typedef void *(Ns_ConnDetachProc) (void *pConnCtx);
Ns_DrvIdConnectionFd
typedef int (Ns_ConnConnectionFdProc) (void *pConnCtx);
Ns_DrvIdMoveContext
(unsupported)
Ns_DrvIdPeerPort
typedef int (Ns_ConnPeerPortProc) (void *pConnCtx);
Ns_DrvIdSetSSLAuth
typedef int (Ns_SetSSLAuthProc) (void *pCtx, Ns_SSLAuthProc *, void *ctx, Ns_FreeAuthCtxProc *);
Ns_DrvIdSSLHandshake
typedef void *(Ns_SSLHandshakeProc) (void *aCtx, int socket, char *DN, Ns_SSLAuthProc *auth, void *authctx, Ns_FreeAuthCtxProc *pFree);
:
void* Ns_GetFirstDriver (
char* ignored
);
int Ns_GetHostByAddr(
Ns_DString *pds,
char *addrStr
);
void* Ns_GetNextDriver (
Ns_Driver driver
);
int Ns_GetSockAddr (
struct sockaddr_in* saPtr,
char* host,
int port
);
int Ns_QueueConn (
Ns_Driver driver,
void* ctx
);
Ns_Driver Ns_RegisterDriver (
char* hServer,
char* hDriver,
Ns_DrvProc* procs,
void* ctx
);
int Ns_RegisterLocation (
char* name,
char* location,
char* address,
int port
);
SOCKET Ns_SockAsyncConnect (
char *host,
int port
);
SOCKET sock;
fd_set set;
struct timeval tv;
sock = Ns_SockAsyncConnect("mailhost", 25);
... perform some other work while connection is in progress...
... check for connection ...
tv.tv_sec = 2; /* allow 2 more seconds */
tv.tv_usec = 0;
FD_ZERO(&set);
FD_SET(sock, &set);
if (select(sock+1, NULL, &set, NULL, &tv) != 1) {
... timeout - close socket and return error...
Ns_CloseLater(sock);
} else {
... use socket ...
}
int Ns_SockCallback (
SOCKET sock,
Ns_SockProc *proc,
void *ctx,
int when
);
The when argument is a bitmask with one or more of the following options specified:
NS_SOCK_READ:
the socket is readable
NS_SOCK_WRITE:
the socket is writeable
NS_SOCK_EXCEPTION:
the socket has an exceptional condition
NS_SOCK_EXIT:
the server is shutting down
The proc is your socket callback function in the following format: typedef int (Ns_SockProc) (int sock, void *arg, int why); The sock will be a readable, writable socket. The arg is the ctx you passed to Ns_SockCallback. The why argument is the when you passed to Ns_SockCallback.
At startup time, AOLserver creates a single socket service thread dedicated to handling socket callbacks. Since several sockets are needed to listen for connection requests, and because connection requests are handled so quickly, all the socket drivers share a single thread for that purpose.
1. Create a C callback function to handle a request. The callback
function must execute without blocking so that other sockets can
get serviced. Typically, the callback function just performs an
accept() call and queues the request. The prototype is:
typedef int (Ns_SockProc) (SOCKET sock, void *context, int
why);
The parameters are:
sock
the registered socket
context
your context passed to Ns_SockCallback()
why
the reason the function was called, which is one of the following:
NS_SOCK_READ: the socket is readable
NS_SOCK_WRITE: the socket is writeable
NS_SOCK_EXCEPTION: the socket has an exceptional condition
NS_SOCK_EXIT: the server is shutting down
The callback function must return either NS_TRUE to tell the
socket thread to keep watching the socket or NS_FALSE to
tell the socket thread to stop watching the socket.
For example:
int
MySock(SOCKET sock, void *context, int why)
{
if (why == NS_SOCK_READ) {
.. handle read ..
if (error) {
return NS_FALSE;
} else {
return NS_TRUE;
}
} else if (why == NS_SOCK_EXIT) {
.. free(context) ..
return NS_FALSE;
}
}
2. At server startup time, your module must register your callback
function with the server using the Ns_SockCallback() function.
This example specifies that MySock will be called when the socket
is readable or when the server is shutting down:
Ns_SockCallback(sock, MySock, myCtx,
NS_SOCK_READ | NS_SOCK_EXIT);
Remember that there is only one socket service thread, so your
callback function must return immediately without
blocking!
void Ns_SockCancelCallback(
int sock
);
SOCKET Ns_SockConnect (
char *host,
int port
);
sock = Ns_SockConnect("mailhost", 25);
if (sock != INVALID_SOCKET) {
... talk SMTP over sock ...
}
SOCKET Ns_SockListen (
char *host,
int port
);
sock = Ns_SockListen("localhost", 25);
while (1) {
new = accept(sock, NULL, 0);
... communicate with client on new ...
}
int Ns_SockListenCallback (
char* address,
int port,
Ns_SockProc* proc,
void* ctx
);
The proc is your socket callback function. The ctx argument is your context which will be passed back as the second argument of your callback function.
The when argument is a bitmask with one or more of the following options specified:
NS_SOCK_READ:
the socket is readable
NS_SOCK_EXIT:
the server is shutting down
int Ns_SockPipe (
SOCKET socks[2]
);
SOCKET sockPipe[2];
/* Init - called at startup to create the pipe. */
void Init(void)
{
Ns_SockPipe(sockPipe);
}
/* Wakeup - called by another thread to stop InteruptableIO in
another thread. */
void Wakeup(void)
{
send(sockPipe[1], "w", 1, 0);
}
/* InterruptableIO - called by a thread dedicated to reading from
a remote host. Reading will continue until another thread
calls Wakeup, causing sockPipe to be readable. */
void InteruptableIO(void)
{
SOCKET sock, max;
fd_set set;
char sig;
sock = Ns_SockConnect("slowmachine", 6767);
FD_ZERO(&set);
FD_SET(sock, &set);
FD_SET(sockPipe[0], &set);
max = sockPipe;
if (sock > max) {
max = sock;
}
while (1) {
select(max+1, &set, NULL, NULL, NULL);
if (FD_ISSET(sockPipe[0], &set)) {
/* Another thread called Wakeup().
* Read the signal and return. */
recv(sockPipe[0], &sig, 1, 0);
closesocket(sock);
return;
} else if (FD_ISSET(sock, &set)) {
recv(sock, buf, sizeof(buf), 0);
... process buf ...
}
}
}
Note: Interruptable I/O typically makes use of the alarm() system call
on Unix. The method above, used throughout AOLserver, works on all
platforms and avoids the alarm system call which is inappropriate for
a multithreaded application.
int Ns_SockPortBound (
int port
);
Ns_SockSetBlocking (
SOCKET sock
);
Ns_SockSetNonBlocking (
SOCKET sock
);
SOCKET Ns_SockTimedConnect (
char *host,
int port,
int timeout
);
sock = Ns_SockTimedConnect("mailhost", 25);
if (sock == INVALID_SOCKET) {
... timeout or error connecting ...
} else {
... use socket ...
}
Ns_Conn* Ns_TclGetConn (
Tcl_Interp* interp
);
int Ns_WriteConn(
Ns_Conn *conn,
char *buf,
int len
);