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

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 "hashconn.h"
  35. #include "dataconn.h"
  36. #include "serv.h"
  37. #include "servimpl.h"
  38. #include "ssmerrs.h"
  39. #include "newproto.h"
  40. #include "messages.h"
  41. #include "collectn.h"
  42. /* Shorthand macros for inherited classes */
  43. #define SSMRESOURCE(sslconn) (&(sslconn)->super.super.super)
  44. #define SSMCONNECTION(sslconn) (&(sslconn)->super.super)
  45. #define SSMDATACONNECTION(sslconn) (&(sslconn)->super)
  46. void SSMHashConnection_ServiceThread(void * arg);
  47. SSMStatus SSMHashConnection_StartHashing(SSMHashConnection *conn);
  48. SSMStatus SSMHashConnection_FinishHashing(SSMHashConnection *conn);
  49. SSMStatus SSMHashConnection_Create(void *arg, SSMControlConnection * connection,
  50.                                   SSMResource **res)
  51. {
  52.     SSMStatus rv = PR_SUCCESS;
  53.     SSMHashConnection *conn;
  54.     *res = NULL; /* in case we fail */
  55.     
  56.     conn = (SSMHashConnection *) PR_CALLOC(sizeof(SSMHashConnection));
  57.     if (!conn) goto loser;
  58.     SSMRESOURCE(conn)->m_connection = connection;
  59.     rv = SSMHashConnection_Init(conn, (SSMHashInitializer *) arg, 
  60.                                 SSM_RESTYPE_HASH_CONNECTION);
  61.     if (rv != PR_SUCCESS) goto loser;
  62.     SSMHashConnection_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); /* force destroy */
  71.         SSM_FreeResource(SSMRESOURCE(conn));
  72.     }
  73.         
  74.     return rv;
  75. }
  76. SSMStatus SSMHashConnection_Init(SSMHashConnection *conn,
  77.                                 SSMHashInitializer *init,
  78.                                 SSMResourceType type)
  79. {
  80.     SSMStatus rv = PR_SUCCESS;
  81.     SSMControlConnection *parent = init->m_parent;
  82.  
  83.     rv = SSMDataConnection_Init(SSMDATACONNECTION(conn), parent, type);
  84.     if (rv != PR_SUCCESS) goto loser;
  85.     /* Add the hash type. */
  86.     conn->m_type = init->m_hashtype;
  87.     /* Verify that the hash type is something we can work with. */
  88.     SSMHashConnection_StartHashing(conn);
  89.     rv = (conn->m_context) ? PR_SUCCESS : PR_INVALID_ARGUMENT_ERROR;
  90.     SSMHashConnection_FinishHashing(conn);
  91.     conn->m_resultLen = 0;
  92.     if (rv != PR_SUCCESS) goto loser;
  93.     /* Spin the service thread to set up the SSL connection. */
  94.     SSM_DEBUG("Creating hash service thread.n");
  95.     SSM_GetResourceReference(SSMRESOURCE(conn));
  96.     SSMDATACONNECTION(conn)->m_dataServiceThread =
  97.         SSM_CreateThread(SSMRESOURCE(conn),
  98.                          SSMHashConnection_ServiceThread);
  99.     if (SSMDATACONNECTION(conn)->m_dataServiceThread == NULL) {
  100.         goto loser;
  101.     }
  102.     return PR_SUCCESS;
  103.  loser:
  104.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  105.     return rv;
  106. }
  107. SSMStatus
  108. SSMHashConnection_FinishHashing(SSMHashConnection *conn)
  109. {
  110. SSMStatus rv = SSM_SUCCESS;
  111. SSM_LockResource(SSMRESOURCE(conn));
  112.     /* If we have a context, end the hash. */
  113.     if (conn->m_context)
  114.     {
  115.         HASH_End(conn->m_context, conn->m_result, &conn->m_resultLen,
  116.                  SSM_HASH_RESULT_LEN);
  117.         if (conn->m_resultLen == 0)
  118.             rv = SSM_FAILURE;
  119.         HASH_Destroy(conn->m_context);
  120.         conn->m_context = NULL;
  121.     }
  122. SSM_UnlockResource(SSMRESOURCE(conn));
  123.     return rv;
  124. }
  125. SSMStatus 
  126. SSMHashConnection_StartHashing(SSMHashConnection *conn)
  127. {
  128.     PR_ASSERT(conn->m_context == NULL);
  129.     
  130.     SSM_LockResource(SSMRESOURCE(conn));
  131.     if (conn->m_context)
  132.         SSMHashConnection_FinishHashing(conn);
  133.     conn->m_resultLen = 0;
  134.     conn->m_context = HASH_Create(conn->m_type);
  135.     SSM_UnlockResource(SSMRESOURCE(conn));
  136.     return (conn->m_context ? PR_SUCCESS : PR_FAILURE);
  137. }
  138. SSMStatus SSMHashConnection_Destroy(SSMResource *res, PRBool doFree)
  139. {
  140.     SSMHashConnection *conn = (SSMHashConnection *) res;
  141.     if (doFree)
  142.         SSM_DEBUG("SSMHashConnection_Destroy called.n");
  143.     /* We should be shut down. */
  144.     PR_ASSERT(res->m_threadCount == 0);
  145.     /* Destroy our fields. */
  146.     SSM_LockResource(SSMRESOURCE(conn));
  147.     if (conn->m_context)
  148.         SSMHashConnection_FinishHashing(conn);
  149.     SSM_UnlockResource(SSMRESOURCE(conn));
  150.     
  151.     /* Destroy superclass fields. */
  152.     SSMDataConnection_Destroy(SSMRESOURCE(conn), PR_FALSE);
  153.     /* Free the connection object if asked. */
  154.     if (doFree)
  155.         PR_DELETE(conn);
  156.     return PR_SUCCESS;
  157. }
  158. void
  159. SSMHashConnection_Invariant(SSMHashConnection *conn)
  160. {
  161.     SSMDataConnection_Invariant(SSMDATACONNECTION(conn));
  162.     /* our specific invariants */
  163. SSM_LockResource(SSMRESOURCE(conn));
  164.     /* we should not be simultaneously hashed and hashing */
  165.     if (conn->m_context)
  166.         PR_ASSERT(conn->m_resultLen == 0);
  167. SSM_UnlockResource(SSMRESOURCE(conn));
  168. }
  169. SSMStatus 
  170. SSMHashConnection_Shutdown(SSMResource *arg, SSMStatus status)
  171. {
  172.     SSMStatus rv;
  173.     PR_ASSERT(SSM_IsAKindOf(arg, SSM_RESTYPE_HASH_CONNECTION));
  174.     
  175.     /* Call our superclass shutdown. Thread control is handled there. */
  176.     rv = SSMDataConnection_Shutdown(arg, status);
  177.     return rv;
  178. }
  179. /* 
  180.    Hashing is performed by a single service thread. This thread
  181.    feeds data from the outgoing queue into the hash context.
  182.  */
  183. void SSMHashConnection_ServiceThread(void * arg)
  184. {
  185.     SSMStatus rv = PR_SUCCESS;
  186.     SSMHashConnection * conn;
  187.     SSMControlConnection *ctrl;
  188.     SECItem *msg;
  189.     PRIntn read;
  190.     char buffer[LINESIZE+1] = {0};
  191.     SSM_RegisterNewThread("hash service", (SSMResource *) arg);
  192.     conn = (SSMHashConnection *)arg;
  193.     SSM_DEBUG("initializing.n");
  194.     if (!arg) 
  195.     { 
  196.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  197.         goto loser;
  198.     }
  199.     SSMDATACONNECTION(conn)->m_dataServiceThread = PR_GetCurrentThread();
  200.     /* set up the client data socket and authenticate it with nonce */
  201.     rv = SSMDataConnection_SetupClientSocket(SSMDATACONNECTION(conn));
  202.     if (rv != PR_SUCCESS) {
  203.         goto loser;
  204.     }
  205.     /* Start hashing. */
  206.     SSM_DEBUG("creating hash context.n");
  207.     SSMHashConnection_StartHashing(conn);
  208.     /* Loop for as long as we have data. */
  209.     while ((SSMRESOURCE(conn)->m_status == PR_SUCCESS) && 
  210.            (SSM_Count(SSMDATACONNECTION(conn)->m_shutdownQ) == 0) && 
  211.            (rv == PR_SUCCESS)) {
  212.         read = LINESIZE;    /* set the read size to the default line size */
  213.         rv = SSMDataConnection_ReadFromSocket(SSMDATACONNECTION(conn),
  214.                                               (PRInt32*)&read, buffer);
  215.         if (read > 0) {
  216.             /* there is data, add it to hash */
  217.             SSM_DEBUG("Received %ld bytes of data for hasher.n", read);
  218.             PR_ASSERT(conn->m_context);
  219.             HASH_Update(conn->m_context, (unsigned char *) buffer, (unsigned int)read);
  220.         }
  221.         else {
  222.             /* either EOF or an error condition */
  223.             goto finish;
  224.         }
  225.     }
  226. finish:
  227.     SSM_DEBUG("Got shutdown msg.n");
  228.     
  229.     /* Lock the resource object, so that we know that attribute requests
  230.        won't be pending while we work. */
  231. SSM_LockResource(SSMRESOURCE(conn));
  232.     /*    SSM_ShutdownResource(SSMRESOURCE(conn), PR_SUCCESS);*/
  233.     SSMHashConnection_FinishHashing(conn);
  234.     /* If we've been asked to return the result, do it now. */
  235.     if (SSMDATACONNECTION(conn)->m_sendResult) {
  236.         SSM_DEBUG("Responding to deferred hash result request.n");
  237.         msg = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
  238.         PR_ASSERT(msg != NULL);    /* need to have some preallocated
  239.                                       failure to send */
  240.         if (conn->m_result) {
  241.             SSMAttributeValue value;
  242.             GetAttribReply reply;
  243.             value.type = SSM_STRING_ATTRIBUTE;
  244.             value.u.string.len = conn->m_resultLen;
  245.             value.u.string.data = conn->m_result;
  246.             msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_RESOURCE_ACTION
  247.                 | SSM_GET_ATTRIBUTE | SSM_STRING_ATTRIBUTE);
  248.             reply.result = rv;
  249.             reply.value = value;
  250.             if (CMT_EncodeMessage(GetAttribReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  251.                 goto loser;
  252.             }
  253.             SSM_DEBUG("Generated a reply (t %lx/l %ld/d %lx)n", 
  254.                       msg->type, msg->len, msg->data);
  255.             value.u.string.data = NULL;
  256.             SSM_DestroyAttrValue(&value, PR_FALSE);
  257.         }
  258.         else {
  259.             SingleNumMessage reply;
  260.             msg->type = (SECItemType) (SSM_REPLY_ERR_MESSAGE | SSM_RESOURCE_ACTION
  261.                 | SSM_GET_ATTRIBUTE | SSM_STRING_ATTRIBUTE);
  262.             reply.value = SSM_ERR_ATTRIBUTE_MISSING;
  263.             if (CMT_EncodeMessage(GetAttribReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  264.                 goto loser;
  265.             }
  266.             SSM_DEBUG("Generated error reply (t %lx/l %ld/d %lx)n", 
  267.                       msg->type, msg->len, msg->data);
  268.         }
  269.         /* Post this message to the parent's control queue
  270.            for delivery back to the client. */
  271.         ctrl = (SSMControlConnection*)SSMCONNECTION(conn)->m_parent;
  272.         PR_ASSERT(SSM_IsAKindOf(&ctrl->super.super, SSM_RESTYPE_CONTROL_CONNECTION));
  273.         rv = SSM_SendQMessage(ctrl->m_controlOutQ, 
  274.                               SSM_PRIORITY_NORMAL,
  275.                               msg->type, msg->len,
  276.                               (char*)msg->data, PR_TRUE);
  277.         SSM_FreeMessage(msg);
  278.         if (rv != PR_SUCCESS) goto loser;
  279.     }
  280. SSM_UnlockResource(SSMRESOURCE(conn));
  281. loser:
  282.     SSM_DEBUG("** Thread shutting down ** (%ld)n", rv);
  283.     if (conn != NULL) {
  284.         SSM_ShutdownResource(SSMRESOURCE(conn), rv);
  285.         SSM_FreeResource(SSMRESOURCE(conn));
  286.     }
  287. }
  288. SSMStatus 
  289. SSMHashConnection_GetAttrIDs(SSMResource *res,
  290.                              SSMAttributeID **ids,
  291.                              PRIntn *count)
  292. {
  293.     SSMStatus rv;
  294.     rv = SSMDataConnection_GetAttrIDs(res, ids, count);
  295.     if (rv != PR_SUCCESS)
  296.         goto loser;
  297.     *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 1) * sizeof(SSMAttributeID));
  298.     if (! *ids) goto loser;
  299.     (*ids)[*count++] = SSM_FID_HASHCONN_RESULT;
  300.     goto done;
  301.  loser:
  302.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  303.  done:
  304.     return rv;
  305. }
  306. SSMStatus 
  307. SSMHashConnection_GetAttr(SSMResource *res,
  308.                           SSMAttributeID attrID,
  309.                           SSMResourceAttrType attrType,
  310.                           SSMAttributeValue *value)
  311. {
  312.     SSMStatus rv = PR_SUCCESS;
  313.     SSMHashConnection *hc = (SSMHashConnection *) res;
  314. if (! hc)
  315. return PR_INVALID_ARGUMENT_ERROR;
  316.     SSMHashConnection_Invariant(hc);
  317. SSM_LockResource(SSMRESOURCE(hc));
  318.     /* see what it is */
  319.     switch(attrID)
  320.     {
  321.     case SSM_FID_HASHCONN_RESULT:
  322.         if (hc->m_resultLen == 0)
  323.         {
  324.             /* Still waiting on hashing to finish. 
  325.                Set the flag which tells us to return the attribute
  326.                when we finish. */
  327.             SSMDATACONNECTION(hc)->m_sendResult = PR_TRUE;
  328.             rv = SSM_ERR_DEFER_RESPONSE;
  329.             goto loser;
  330.         }
  331.         
  332.         /* XXX Fix this. Return the hash result in a string. */
  333.         value->type = SSM_STRING_ATTRIBUTE;
  334.         value->u.string.len = hc->m_resultLen;
  335.         value->u.string.data = (unsigned char *) PR_CALLOC(hc->m_resultLen);
  336.         if (value->u.string.data)
  337.             memcpy(value->u.string.data, hc->m_result, hc->m_resultLen);
  338.         else
  339.             value->u.string.len = 0;
  340.         break;
  341.     default:
  342.         rv = SSMDataConnection_GetAttr(res,attrID,attrType,value);
  343.         if (rv != PR_SUCCESS)
  344.             goto loser;
  345.     }
  346.     goto done;
  347.  loser:
  348.     value->type = SSM_NO_ATTRIBUTE;
  349.     if (rv == PR_SUCCESS)
  350.         rv = PR_FAILURE;
  351.  done:
  352. SSM_UnlockResource(SSMRESOURCE(hc));
  353.     return rv;
  354. }