dataconn.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:14k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #include "connect.h"
  35. #include "dataconn.h"
  36. #include "ctrlconn.h"
  37. #include "servimpl.h"
  38. #include "serv.h"
  39. #include "ssmerrs.h"
  40. #define SSMCONNECTION(p) (&(p)->super)
  41. #define SSMRESOURCE(p) (&(p)->super.super)
  42. /* How many milliseconds to wait for client input */
  43. #define SSM_READCLIENT_POKE_INTERVAL 30000
  44. /* keep track of the number of data connections pending. used to throttle cpu usage */
  45. static int gNumDataConnections = 0;
  46. PRBool AreConnectionsActive(void)
  47. {
  48. return gNumDataConnections > 0;
  49. }
  50. SSMStatus SSMDataConnection_Create(void *arg, SSMControlConnection * connection,
  51.                                   SSMResource **res)
  52. {
  53.     SSMStatus rv = PR_SUCCESS;
  54.     SSMDataConnection *conn;
  55.     *res = NULL; /* in case we fail */
  56.     
  57.     conn = (SSMDataConnection *) PR_CALLOC(sizeof(SSMDataConnection));
  58.     if (!conn) goto loser;
  59.     rv = SSMDataConnection_Init(conn, (SSMControlConnection *) arg, 
  60.                             SSM_RESTYPE_DATA_CONNECTION);
  61.     if (rv != PR_SUCCESS) goto loser;
  62.     SSMDataConnection_Invariant(conn);
  63.     
  64.     *res = SSMRESOURCE(conn);
  65.     return PR_SUCCESS;
  66.  loser:
  67.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  68.     if (conn) 
  69.     {
  70. SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  71.         SSM_FreeResource(SSMRESOURCE(conn));
  72.     }
  73.         
  74.     return rv;
  75. }
  76. SSMStatus SSMDataConnection_Init(SSMDataConnection *conn, 
  77.                                 SSMControlConnection *parent, 
  78.                                 SSMResourceType type)
  79. {
  80.     SSMStatus rv = PR_SUCCESS;
  81.     SSMResourceType parentType = RESOURCE_CLASS(parent);
  82.     PR_ASSERT(parent != NULL);
  83.     PR_ASSERT((parentType == SSM_RESTYPE_CONTROL_CONNECTION) || (parentType == SSM_RESTYPE_CONNECTION));
  84.     if (!parent) goto loser;
  85.     rv = SSMConnection_Init(parent, SSMCONNECTION(conn), type);
  86.     if (rv != PR_SUCCESS) goto loser;
  87.     /* Initialize data shutdown queue. */
  88.     conn->m_shutdownQ = SSM_NewCollection();
  89.     if (conn->m_shutdownQ == NULL) {
  90.         goto loser;
  91.     }
  92.     /* keep track of the number of data connections pending. */
  93.     gNumDataConnections++;
  94.     /* Hang our shutdown func. */
  95.     SSMCONNECTION(conn)->m_auth_func = SSMDataConnection_Authenticate;
  96.     return PR_SUCCESS;
  97.  loser:
  98.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  99.     return rv;
  100. }
  101. SSMStatus SSMDataConnection_Destroy(SSMResource *res, PRBool doFree)
  102. {
  103.     SSMDataConnection *conn = (SSMDataConnection *) res;
  104.     /* We should be shut down. */
  105.     PR_ASSERT(res->m_threadCount == 0);
  106.     /* Drain and destroy the queue. */
  107.     if (conn->m_shutdownQ) {
  108.         ssm_DrainAndDestroyQueue(&(conn->m_shutdownQ));
  109.     }
  110.     /* Destroy superclass fields. */
  111.     SSMConnection_Destroy(&(conn->super.super), PR_FALSE);
  112.     /* Free the connection object if asked. */
  113.     if (doFree)
  114.         PR_DELETE(conn);
  115.     return PR_SUCCESS;
  116. }
  117. void
  118. SSMDataConnection_Invariant(SSMDataConnection *conn)
  119. {
  120.     if (conn)
  121.     {
  122.         SSMConnection_Invariant(&conn->super);
  123.         SSM_LockResource(SSMRESOURCE(conn));
  124.         PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), SSM_RESTYPE_DATA_CONNECTION));
  125.         PR_ASSERT(conn->m_shutdownQ != NULL);
  126.         SSM_UnlockResource(SSMRESOURCE(conn));
  127.     }
  128. }
  129. SSMStatus
  130. SSMDataConnection_GetAttrIDs(SSMResource *res,
  131.                              SSMAttributeID **ids,
  132.                              PRIntn *count)
  133. {
  134.     SSMStatus rv;
  135.     rv = SSMConnection_GetAttrIDs(res, ids, count);
  136.     if (rv != PR_SUCCESS)
  137.         goto loser;
  138.     *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 1) * sizeof(SSMAttributeID));
  139.     if (! *ids) goto loser;
  140.     (*ids)[*count++] = SSM_FID_CONN_DATA_PENDING;
  141.     goto done;
  142.  loser:
  143.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  144.  done:
  145.     return rv;
  146. }
  147. SSMStatus
  148. SSMDataConnection_GetAttr(SSMResource *res,
  149.                           SSMAttributeID attrID,
  150.                           SSMResourceAttrType attrType,
  151.                           SSMAttributeValue *value)
  152. {
  153.     SSMStatus rv = PR_SUCCESS;
  154.     /* see what it is */
  155.     switch(attrID)
  156.     {
  157.     case SSM_FID_CONN_DATA_PENDING:
  158.         /* this is not used: will set it to zero for now */
  159.         *(PRUint32*)value->u.numeric = (PRUint32)0;
  160.         value->type = SSM_NUMERIC_ATTRIBUTE;
  161.         break;
  162.     default:
  163.         rv = SSMConnection_GetAttr(res,attrID,attrType,value);
  164.         if (rv != PR_SUCCESS) goto loser;
  165.     }
  166.     goto done;
  167.  loser:
  168.     value->type = SSM_NO_ATTRIBUTE;
  169.  done:
  170.     return rv;
  171. }
  172. SSMStatus SSMDataConnection_SetupClientSocket(SSMDataConnection* conn)
  173. {
  174.     SSMControlConnection* parent = NULL;
  175.     char* pNonce;
  176.     char* temp = NULL;    /* for nonce verification */
  177.     PRFileDesc* socket = NULL;    /* client socket */
  178.     PRNetAddr clientAddr;
  179.     SSMStatus status = PR_FAILURE;
  180.     PRIntn read;
  181.     PR_ASSERT(conn != NULL);
  182.     /* Allocate a nonce-sized chunk of memory to read into.
  183.        (See below.) */
  184.     parent = (SSMControlConnection*)(conn->super.m_parent);
  185.     PR_ASSERT(parent != NULL);
  186.     pNonce = parent->m_nonce;
  187.     PR_ASSERT(pNonce != NULL);
  188.     SSM_DEBUG("I think my parent's nonce is `%s'.n", pNonce);
  189.     temp = (char*)PORT_ZAlloc(strlen(pNonce));
  190.     while ((socket == NULL) && (SSMRESOURCE(conn)->m_status == PR_SUCCESS)) {
  191.         SSM_DEBUG("accepting next connect.n");
  192.         /* Wait forever for a connection. (for now) */
  193.         socket = PR_Accept(SSMRESOURCE(conn)->m_connection->m_dataSocket,
  194.                            &clientAddr, PR_INTERVAL_NO_TIMEOUT);
  195.         SSM_DEBUG("accepted connection.n");
  196.         if ((SSMRESOURCE(conn)->m_status != PR_SUCCESS) && socket) {
  197.             /* May have gotten a socket, but we're shutting down.
  198.                Close and zero out the socket. */
  199.             PR_Close(socket);
  200.             SSM_LockResource(SSMRESOURCE(conn));
  201.             socket = conn->m_clientSocket = NULL;
  202.             SSM_UnlockResource(SSMRESOURCE(conn));
  203.         }
  204.         
  205.         if (socket && !SSM_SocketPeerCheck(socket, PR_FALSE))
  206.         {
  207.             /* 
  208.                Failed peer check. Close socket and listen again. 
  209.                ### mwelch - Could have a denial of service attack here if
  210.                someone keeps trying to connect to this port.
  211.             */
  212.             PR_Close(socket);
  213.             socket = NULL;
  214.             continue;
  215.         }
  216.         if (socket) {
  217.             SSM_LockResource(SSMRESOURCE(conn));
  218.             conn->m_clientSocket = socket;
  219.             SSM_UnlockResource(SSMRESOURCE(conn));
  220.             SSM_DEBUG("reading/verifying nonce.n");
  221.             status = PR_SUCCESS;
  222.             /* Read the nonce from the client.  If we didn't get the right
  223.                nonce, reject the connection. */
  224.             if ((temp) && (pNonce != NULL)) {
  225.                 read = SSM_ReadThisMany(socket, temp, strlen(pNonce));
  226.                 if ((unsigned int)read != strlen(pNonce)) {
  227.                     status = PR_GetError();
  228.                 }
  229.             }
  230.             if ((status != PR_SUCCESS) || (memcmp(temp, pNonce,
  231.                                                   strlen(pNonce)))) {
  232. #ifdef DEBUG
  233.                 char thing1[255];
  234.                 char thing2[255];
  235.                 
  236.                 strncpy(thing1, temp, strlen(pNonce));
  237.                 strncpy(thing2, temp, strlen(pNonce));
  238.                 /* Bad nonce, no biscuit!  Shut down connection
  239.                    and wait for another on the data port. */
  240.                 SSM_DEBUG("Bad nonce, no biscuit!n");
  241.                 SSM_DEBUG("(`%s' != `%s')n", thing1, thing2);
  242. #endif
  243.                 SSM_LockResource(SSMRESOURCE(conn));
  244.                 PR_Close(conn->m_clientSocket);
  245.                 conn->m_clientSocket = socket = NULL;
  246.                 SSM_UnlockResource(SSMRESOURCE(conn));
  247.             }
  248.         }
  249.         else {
  250.             /* Tear everything down, didn't get a connection. */
  251.             SSM_DEBUG("Shutdown during connection setup.n");
  252.             goto loser;
  253.         }
  254.     }
  255.     SSM_DEBUG("Nonce is valid.n");
  256.     /* We have a socket.  Close the data port. */
  257.     SSM_LockResource(SSMRESOURCE(conn));
  258.     SSM_DEBUG("Socket is %ld.n", socket);
  259.     SSM_UnlockResource(SSMRESOURCE(conn));
  260. loser:
  261.     if (temp != NULL) {
  262.         PR_Free(temp);
  263.     }
  264.     return status;
  265. }
  266. SSMStatus SSMDataConnection_ReadFromSocket(SSMDataConnection* conn,
  267.                                           PRInt32* read,
  268.                                           char* buffer)
  269. {
  270.     SSMStatus status;
  271. #if 0
  272.     SSMStatus osStat;
  273.     char statBuf[256];
  274. #endif
  275.     PR_ASSERT(conn != NULL);
  276.     PR_ASSERT(buffer != NULL);
  277.     /* Attempt to read LINESIZE bytes from the socket. */
  278.     do {
  279.         SSM_DEBUG("Attempting to read %ld bytes.n", *read);
  280.         *read = PR_Recv(conn->m_clientSocket, buffer, *read, 0,
  281.                         PR_MillisecondsToInterval(SSM_READCLIENT_POKE_INTERVAL));
  282.         if (*read < 0) {
  283.             status = PR_GetError();    /* save status for later use */
  284. #if 0
  285.             osStat = PR_GetOSError();    /* just for fun */
  286.             PR_GetErrorText(statBuf);
  287. #endif
  288.         }
  289.         SSM_DEBUG("Got %ld bytes of data, status == %ld.n", (long)(*read),
  290.                   (long)status);
  291.     }
  292.     while ((*read == -1) && (status == PR_IO_TIMEOUT_ERROR) &&
  293.            SSMRESOURCE(conn)->m_status == PR_SUCCESS);
  294.     /* Don't mask an error if we got one, but set it if we didn't get any
  295.      * data (because that indicates a socket closure).
  296.      */
  297.     if ((*read < 0) && (status == PR_SUCCESS)) {
  298.         status = PR_FAILURE;
  299.     }
  300.     else if (*read >= 0) {
  301.         status = PR_SUCCESS;    /* clear the error from when we waited */
  302.     }
  303. #if 0
  304.     /* Null terminate the buffer so that we can dump it. */
  305.     if (*read >= 0) {
  306.         buffer[*read] = '';
  307.     }
  308. #endif
  309.     if (*read > 0) {
  310.         SSM_DEBUG("got %ld bytes of data: <%s>n", *read, buffer);
  311.     }
  312.     return status;
  313. }
  314. SSMStatus
  315. SSMDataConnection_Shutdown(SSMResource *res, SSMStatus status)
  316. {
  317.     SSMStatus rv, trv;
  318.     PRThread *closer = PR_GetCurrentThread();
  319.     SSMDataConnection *conn = (SSMDataConnection *) res;
  320.     /* SSMDataConnection_Invariant(conn); -- could be called from loser */
  321.     /* Lock down the resource before shutting it down */
  322.     SSM_LockResource(SSMRESOURCE(conn));
  323.     
  324.     /* If we're called from a service thread, clear that thread's
  325.        place in the connection object so it doesn't get interrupted */
  326.     if ((closer == conn->m_dataServiceThread) && (closer != NULL)) {
  327.         conn->m_dataServiceThread = NULL;
  328.         /* Decrement living thread counter */
  329.         SSMRESOURCE(conn)->m_threadCount--;
  330.     }
  331.     /* shut down base class */
  332.     rv = SSMConnection_Shutdown(res, status);
  333.     if ((SSMRESOURCE(conn)->m_status != PR_SUCCESS) &&
  334.         (rv != SSM_ERR_ALREADY_SHUT_DOWN) &&
  335.         (conn->m_clientSocket != NULL))
  336.     {
  337. SSM_DEBUG("Shutting down data connection abnormally (rv == %d).n",
  338.                   SSMRESOURCE(conn)->m_status);
  339.         SSM_DEBUG("shutting down client socket.n");
  340.         PR_Shutdown(conn->m_clientSocket, PR_SHUTDOWN_SEND);
  341.         /* if this is called by a control thread, send a message to the
  342.          * data service thread to shut down
  343.          */
  344.         if ((closer != conn->m_dataServiceThread) && 
  345.             (conn->m_shutdownQ != NULL)) {
  346.             SSM_DEBUG("Send shutdown msg to data Q.n");
  347.             trv = SSM_SendQMessage(conn->m_shutdownQ, SSM_PRIORITY_SHUTDOWN,
  348.                                    SSM_DATA_PROVIDER_SHUTDOWN, 0, NULL,
  349.                                    PR_TRUE);
  350.         }
  351.         if (conn->m_dataServiceThread) {
  352.             PR_Interrupt(conn->m_dataServiceThread);
  353.         }
  354.     }
  355.     
  356.     /* If the client sockets is/are now unused, close them. */
  357.     if (SSMRESOURCE(conn)->m_threadCount == 0)
  358.     {
  359.         /* Close the client socket with linger */
  360.         if (conn->m_clientSocket)
  361.         {
  362.             SSM_DEBUG("Close data socket.n");
  363.             trv = PR_Close(conn->m_clientSocket);
  364.             conn->m_clientSocket = NULL;
  365.             SSM_DEBUG("Closed client socket (rv == %d).n",trv);
  366.             /* keep track of the number of data connections pending. */
  367.             gNumDataConnections--;
  368.             PR_ASSERT(gNumDataConnections >= 0);
  369.         }
  370.     }
  371.     SSM_UnlockResource(SSMRESOURCE(conn));
  372.     return rv; /* so that subclasses know to perform shutdown */
  373. }
  374. SSMStatus 
  375. SSMDataConnection_Authenticate(SSMConnection *arg, char *nonce)
  376. {
  377. SSMStatus rv = SSM_FAILURE;
  378.     SSMConnection *parent = arg->m_parent;
  379. /* Parent has the nonce, so authenticate there. */
  380. if (parent &&
  381. SSM_IsAKindOf(&(parent->super), SSM_RESTYPE_CONTROL_CONNECTION))
  382. rv = SSMControlConnection_Authenticate(parent, nonce);
  383. return rv;
  384. }