VirtualBox

Changeset 1958 in vbox for trunk


Ignore:
Timestamp:
Apr 5, 2007 4:19:01 PM (18 years ago)
Author:
vboxsync
Message:

XPCOM/IPC/DConnect: Implemented nsIException caching and serialization to ensure the calling party will be able to access primitive nsIException data (such as error message and line number) even if the called party terminates immediately after returning an exception.

Location:
trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp

    r118 r1958  
    2121 * Contributor(s):
    2222 *   Darin Fisher <[email protected]>
     23 *   Dmitry A. Kuminov <[email protected]>
    2324 *
    2425 * Alternatively, the contents of this file may be used under the terms of
     
    4546#include "nsIInterfaceInfoManager.h"
    4647#include "nsIExceptionService.h"
    47 #include "nsAutoPtr.h"
    4848#include "nsString.h"
    4949#include "nsVoidArray.h"
     
    158158  DConAddr instance;
    159159  nsresult status;
     160  // followed by a specially serialized nsIException instance if
     161  // NS_FAILED(status) (see ipcDConnectService::SerializeException)
    160162};
    161163
     
    181183{
    182184  nsresult result;
    183   // followed by an array of out-param blobs if NS_SUCCEEDED (result)
    184   // or by an nsIException instance if NS_FAILED (result) and the called
    185   // method has set an exception for the current thread using nsIExceptionManager
     185  // followed by an array of out-param blobs if NS_SUCCEEDED(result), or by a
     186  // specially serialized nsIException instance if NS_FAILED(result)
     187  // (see ipcDConnectService::SerializeException)
    186188};
    187189
     
    11161118}
    11171119
     1120//-----------------------------------------------------------------------------
     1121
     1122#define EXCEPTION_STUB_ID                          \
     1123{ /* 70578d68-b25e-4370-a70c-89bbe56e6699 */       \
     1124  0x70578d68,                                      \
     1125  0xb25e,                                          \
     1126  0x4370,                                          \
     1127  {0xa7, 0x0c, 0x89, 0xbb, 0xe5, 0x6e, 0x66, 0x99} \
     1128}
     1129static NS_DEFINE_IID(kExceptionStubID, EXCEPTION_STUB_ID);
     1130
     1131// ExceptionStub is used to cache all primitive-typed bits of a remote nsIException
     1132// instance (such as the error message or line number) to:
     1133//
     1134// a) reduce the number of IPC calls;
     1135// b) make sure exception information is available to the calling party even if
     1136//    the called party terminates immediately after returning an exception.
     1137//    To achieve this, all cacheable information is serialized together with
     1138//    the instance wrapper itself.
     1139
     1140class ExceptionStub : public nsIException
     1141{
     1142public:
     1143
     1144  NS_DECL_ISUPPORTS
     1145  NS_DECL_NSIEXCEPTION
     1146
     1147  ExceptionStub(const nsACString &aMessage, nsresult aResult,
     1148                const nsACString &aName, const nsACString &aFilename,
     1149                PRUint32 aLineNumber, PRUint32 aColumnNumber,
     1150                DConnectStub *aXcptStub)
     1151    : mMessage(aMessage), mResult(aResult)
     1152    , mName(aName), mFilename(aFilename)
     1153    , mLineNumber (aLineNumber), mColumnNumber (aColumnNumber)
     1154    , mXcptStub (aXcptStub) { NS_ASSERTION(aXcptStub, "NULL"); }
     1155
     1156  ~ExceptionStub() {}
     1157
     1158  nsIException *Exception() { return (nsIException *)(nsISupports *) mXcptStub; }
     1159  DConnectStub *Stub() { return mXcptStub; }
     1160
     1161private:
     1162
     1163  nsCString mMessage;
     1164  nsresult mResult;
     1165  nsCString mName;
     1166  nsCString mFilename;
     1167  PRUint32 mLineNumber;
     1168  PRUint32 mColumnNumber;
     1169  nsRefPtr<DConnectStub> mXcptStub;
     1170};
     1171
     1172NS_IMPL_ADDREF(ExceptionStub)
     1173NS_IMPL_RELEASE(ExceptionStub)
     1174
     1175NS_IMETHODIMP
     1176ExceptionStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
     1177{
     1178  NS_ASSERTION(aInstancePtr,
     1179               "QueryInterface requires a non-NULL destination!");
     1180
     1181  // used to discover if this is an ExceptionStub instance.
     1182  if (aIID.Equals(kExceptionStubID))
     1183  {
     1184    *aInstancePtr = this;
     1185    NS_ADDREF_THIS();
     1186    return NS_OK;
     1187  }
     1188
     1189  // regular NS_IMPL_QUERY_INTERFACE1 sequence
     1190
     1191  nsISupports* foundInterface = 0;
     1192
     1193  if (aIID.Equals(NS_GET_IID(nsIException)))
     1194    foundInterface = NS_STATIC_CAST(nsIException*, this);
     1195  else
     1196  if (aIID.Equals(NS_GET_IID(nsISupports)))
     1197    foundInterface = NS_STATIC_CAST(nsISupports*,
     1198                                    NS_STATIC_CAST(nsIException *, this));
     1199  else
     1200  if (mXcptStub)
     1201  {
     1202    // ask the real nsIException object
     1203    return mXcptStub->QueryInterface(aIID, aInstancePtr);
     1204  }
     1205
     1206  nsresult status;
     1207  if (!foundInterface)
     1208    status = NS_NOINTERFACE;
     1209  else
     1210  {
     1211    NS_ADDREF(foundInterface);
     1212    status = NS_OK;
     1213  }
     1214  *aInstancePtr = foundInterface;
     1215  return status;
     1216}
     1217
     1218/* readonly attribute string message; */
     1219NS_IMETHODIMP ExceptionStub::GetMessage(char **aMessage)
     1220{
     1221  if (!aMessage)
     1222    return NS_ERROR_INVALID_POINTER;
     1223  *aMessage = ToNewCString(mMessage);
     1224  return NS_OK;
     1225}
     1226
     1227/* readonly attribute nsresult result; */
     1228NS_IMETHODIMP ExceptionStub::GetResult(nsresult *aResult)
     1229{
     1230  if (!aResult)
     1231    return NS_ERROR_INVALID_POINTER;
     1232  *aResult = mResult;
     1233  return NS_OK;
     1234}
     1235
     1236/* readonly attribute string name; */
     1237NS_IMETHODIMP ExceptionStub::GetName(char **aName)
     1238{
     1239  if (!aName)
     1240    return NS_ERROR_INVALID_POINTER;
     1241  *aName = ToNewCString(mName);
     1242  return NS_OK;
     1243}
     1244
     1245/* readonly attribute string filename; */
     1246NS_IMETHODIMP ExceptionStub::GetFilename(char **aFilename)
     1247{
     1248  if (!aFilename)
     1249    return NS_ERROR_INVALID_POINTER;
     1250  *aFilename = ToNewCString(mFilename);
     1251  return NS_OK;
     1252}
     1253
     1254/* readonly attribute PRUint32 lineNumber; */
     1255NS_IMETHODIMP ExceptionStub::GetLineNumber(PRUint32 *aLineNumber)
     1256{
     1257  if (!aLineNumber)
     1258    return NS_ERROR_INVALID_POINTER;
     1259  *aLineNumber = mLineNumber;
     1260  return NS_OK;
     1261}
     1262
     1263/* readonly attribute PRUint32 columnNumber; */
     1264NS_IMETHODIMP ExceptionStub::GetColumnNumber(PRUint32 *aColumnNumber)
     1265{
     1266  if (!aColumnNumber)
     1267    return NS_ERROR_INVALID_POINTER;
     1268  *aColumnNumber = mColumnNumber;
     1269  return NS_OK;
     1270}
     1271
     1272/* readonly attribute nsIStackFrame location; */
     1273NS_IMETHODIMP ExceptionStub::GetLocation(nsIStackFrame **aLocation)
     1274{
     1275  if (Exception())
     1276    return Exception()->GetLocation (aLocation);
     1277  return NS_ERROR_UNEXPECTED;
     1278}
     1279
     1280/* readonly attribute nsIException inner; */
     1281NS_IMETHODIMP ExceptionStub::GetInner(nsIException **aInner)
     1282{
     1283  if (Exception())
     1284    return Exception()->GetInner (aInner);
     1285  return NS_ERROR_UNEXPECTED;
     1286}
     1287
     1288/* readonly attribute nsISupports data; */
     1289NS_IMETHODIMP ExceptionStub::GetData(nsISupports * *aData)
     1290{
     1291  if (Exception())
     1292    return Exception()->GetData (aData);
     1293  return NS_ERROR_UNEXPECTED;
     1294}
     1295
     1296/* string toString (); */
     1297NS_IMETHODIMP ExceptionStub::ToString(char **_retval)
     1298{
     1299  if (Exception())
     1300    return Exception()->ToString (_retval);
     1301  return NS_ERROR_UNEXPECTED;
     1302}
     1303
     1304nsresult
     1305ipcDConnectService::SerializeException(ipcMessageWriter &writer,
     1306                                       PRUint32 peer, nsIException *xcpt,
     1307                                       nsVoidArray &wrappers)
     1308{
     1309  PRBool cache_fields = PR_FALSE;
     1310
     1311  // first, seralize the nsIException pointer.  The code is merely the same as
     1312  // in SerializeInterfaceParam() except that when the exception to serialize
     1313  // is an ExceptionStub instance and the real instance it stores as mXcpt
     1314  // is a DConnectStub corresponding to an object in the address space of the
     1315  // peer, we simply pass that object back instead of creating a new wrapper.
     1316
     1317  {
     1318    nsAutoLock lock (mLock);
     1319
     1320    if (mDisconnected)
     1321      return NS_ERROR_NOT_INITIALIZED;
     1322
     1323    if (!xcpt)
     1324    {
     1325      // write null address
     1326      writer.PutBytes(&xcpt, sizeof(xcpt));
     1327    }
     1328    else
     1329    {
     1330      ExceptionStub *stub = nsnull;
     1331      nsresult rv = xcpt->QueryInterface(kExceptionStubID, (void **) &stub);
     1332      if (NS_SUCCEEDED(rv) && (stub->Stub()->PeerID() == peer))
     1333      {
     1334        // send the wrapper instance back to the peer
     1335        void *p = stub->Stub()->Instance();
     1336        writer.PutBytes(&p, sizeof(p));
     1337      }
     1338      else
     1339      {
     1340        // create instance wrapper
     1341
     1342        const nsID &iid = nsIException::GetIID();
     1343        nsCOMPtr<nsIInterfaceInfo> iinfo;
     1344        rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo));
     1345        if (NS_FAILED(rv))
     1346          return rv;
     1347
     1348        DConnectInstance *wrapper = nsnull;
     1349
     1350        // first try to find an existing wrapper for the given object
     1351        if (!FindInstanceAndAddRef(peer, xcpt, &iid, &wrapper))
     1352        {
     1353          wrapper = new DConnectInstance(peer, iinfo, xcpt);
     1354          if (!wrapper)
     1355            return NS_ERROR_OUT_OF_MEMORY;
     1356
     1357          rv = StoreInstance(wrapper);
     1358          if (NS_FAILED(rv))
     1359          {
     1360            delete wrapper;
     1361            return rv;
     1362          }
     1363
     1364          // reference the newly created wrapper
     1365          wrapper->AddRef();
     1366        }
     1367       
     1368        if (!wrappers.AppendElement(wrapper))
     1369        {
     1370          wrapper->Release();
     1371          return NS_ERROR_OUT_OF_MEMORY;
     1372        }
     1373
     1374        // wrapper remains referenced when passing it to the client
     1375        // (will be released upon DCON_OP_RELEASE)
     1376     
     1377        // send address of the instance wrapper, and set the low bit
     1378        // to indicate that this is an instance wrapper.
     1379        PtrBits bits = ((PtrBits) wrapper) | 0x1;
     1380        writer.PutBytes(&bits, sizeof(bits));
     1381
     1382        // we want to cache fields to minimize the number of IPC calls when
     1383        // accessing exception data on the peer side
     1384        cache_fields = PR_TRUE;
     1385      }
     1386      NS_IF_RELEASE(stub);
     1387    }
     1388  }
     1389
     1390  if (!cache_fields)
     1391    return NS_OK;
     1392
     1393  nsresult rv;
     1394  nsXPIDLCString str;
     1395  PRUint32 num;
     1396
     1397  // message
     1398  rv = xcpt->GetMessage(getter_Copies(str));
     1399  if (NS_SUCCEEDED (rv))
     1400  {
     1401    PRUint32 len = str.Length();
     1402    nsACString::const_iterator begin;
     1403    const char *data = str.BeginReading(begin).get();
     1404    writer.PutInt32(len);
     1405    writer.PutBytes(data, len);
     1406  }
     1407  else
     1408    writer.PutInt32(0);
     1409
     1410  // result
     1411  nsresult res = 0;
     1412  xcpt->GetResult(&res);
     1413  writer.PutInt32(res);
     1414
     1415  // name
     1416  rv = xcpt->GetName(getter_Copies(str));
     1417  if (NS_SUCCEEDED (rv))
     1418  {
     1419    PRUint32 len = str.Length();
     1420    nsACString::const_iterator begin;
     1421    const char *data = str.BeginReading(begin).get();
     1422    writer.PutInt32(len);
     1423    writer.PutBytes(data, len);
     1424  }
     1425  else
     1426    writer.PutInt32(0);
     1427
     1428  // filename
     1429  rv = xcpt->GetFilename(getter_Copies(str));
     1430  if (NS_SUCCEEDED (rv))
     1431  {
     1432    PRUint32 len = str.Length();
     1433    nsACString::const_iterator begin;
     1434    const char *data = str.BeginReading(begin).get();
     1435    writer.PutInt32(len);
     1436    writer.PutBytes(data, len);
     1437  }
     1438  else
     1439    writer.PutInt32(0);
     1440
     1441  // lineNumber
     1442  num = 0;
     1443  xcpt->GetLineNumber(&num);
     1444  writer.PutInt32(num);
     1445
     1446  // columnNumber
     1447  num = 0;
     1448  xcpt->GetColumnNumber(&num);
     1449  writer.PutInt32(num);
     1450
     1451  return writer.HasError() ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
     1452}
     1453
     1454nsresult
     1455ipcDConnectService::DeserializeException(const PRUint8 *data,
     1456                                         PRUint32 dataLen,
     1457                                         PRUint32 peer,
     1458                                         nsIException **xcpt)
     1459{
     1460  NS_ASSERTION (xcpt, "NULL");
     1461  if (!xcpt)
     1462    return NS_ERROR_INVALID_POINTER;
     1463
     1464  ipcMessageReader reader(data, dataLen);
     1465
     1466  nsresult rv;
     1467  PRUint32 len;
     1468
     1469  void *instance = 0;
     1470  reader.GetBytes(&instance, sizeof(void *));
     1471  if (reader.HasError())
     1472    return NS_ERROR_INVALID_ARG;
     1473
     1474  PtrBits bits = (PtrBits) (instance);
     1475
     1476  if (bits & 0x1)
     1477  {
     1478    // pointer is a peer-side exception instance wrapper,
     1479    // read cahced exception data and create a stub for it.
     1480
     1481    nsCAutoString message;
     1482    len = reader.GetInt32();
     1483    if (len)
     1484    {
     1485      message.SetLength(len);
     1486      char *buf = message.BeginWriting();
     1487      reader.GetBytes(buf, len);
     1488    }
     1489
     1490    nsresult result = reader.GetInt32();
     1491
     1492    nsCAutoString name;
     1493    len = reader.GetInt32();
     1494    if (len)
     1495    {
     1496      name.SetLength(len);
     1497      char *buf = name.BeginWriting();
     1498      reader.GetBytes(buf, len);
     1499    }
     1500
     1501    nsCAutoString filename;
     1502    len = reader.GetInt32();
     1503    if (len)
     1504    {
     1505      filename.SetLength(len);
     1506      char *buf = filename.BeginWriting();
     1507      reader.GetBytes(buf, len);
     1508    }
     1509
     1510    PRUint32 lineNumber = reader.GetInt32();
     1511    PRUint32 columnNumber = reader.GetInt32();
     1512
     1513    if (reader.HasError())
     1514      rv = NS_ERROR_INVALID_ARG;
     1515    else
     1516    {
     1517      DConAddr addr = (DConAddr) (bits & ~0x1);
     1518      nsRefPtr<DConnectStub> stub;
     1519      rv = CreateStub(nsIException::GetIID(), peer, addr,
     1520                      getter_AddRefs(stub));
     1521      if (NS_SUCCEEDED(rv))
     1522      {
     1523        // create a special exception "stub" with cached error info
     1524        ExceptionStub *xcptStub =
     1525          new ExceptionStub (message, result,
     1526                             name, filename,
     1527                             lineNumber, columnNumber,
     1528                             stub);
     1529        if (xcptStub)
     1530        {
     1531          *xcpt = xcptStub;
     1532          NS_ADDREF(xcptStub);
     1533        }
     1534        else
     1535          rv = NS_ERROR_OUT_OF_MEMORY;
     1536      }
     1537    }
     1538  }
     1539  else if (bits)
     1540  {
     1541    // pointer is to our instance wrapper for nsIException we've sent before
     1542    // (the remote method we've called had called us back and got an exception
     1543    // from us that it decided to return as its own result). Replace it with
     1544    // the real instance.
     1545    DConnectInstance *wrapper = (DConnectInstance *) bits;
     1546    if (CheckInstanceAndAddRef(wrapper))
     1547    {
     1548      *xcpt = (nsIException *) wrapper->RealInstance();
     1549      NS_ADDREF(wrapper->RealInstance());
     1550      wrapper->Release();
     1551    }
     1552    else
     1553    {
     1554      NS_NOTREACHED("instance wrapper not found");
     1555      rv = NS_ERROR_INVALID_ARG;
     1556    }
     1557  }
     1558  else
     1559  {
     1560    // the peer explicitly passed us a NULL exception to indicate that the
     1561    // exception on the current thread should be reset
     1562    *xcpt = NULL;
     1563    return NS_OK;
     1564  }
     1565
     1566
     1567  return rv;
     1568}
     1569
     1570//-----------------------------------------------------------------------------
     1571
    11181572DConnectStub::~DConnectStub()
    11191573{
     
    12781732
    12791733  // reset the exception early.  this is necessary because we may return a
    1280   // failure from here without setting an exception (which might be expected by
    1281   // the caller because the interface we are stubbing may indicate in some way
    1282   // that it always sets the exception info on failure).  besides that, resetting
    1283   // the excetion before every IPC call is exactly the same thing as Win32 RPC
    1284   // does, so doing this is useful for getting similarity in behaviors.
     1734  // failure from here without setting an exception (which might be expected
     1735  // by the caller to detect the error origin: the interface we are stubbing
     1736  // may indicate in some way that it always sets the exception info on
     1737  // failure, therefore an "infoless" failure means the origin is RPC).
     1738  // besides that, resetting the excetion before every IPC call is exactly the
     1739  // same thing as Win32 RPC does, so doing this is useful for getting
     1740  // similarity in behaviors.
    12851741
    12861742  nsCOMPtr <nsIExceptionService> es;
     
    13991855  if (NS_FAILED(rv))
    14001856  {
    1401     if (completion.ParamsLen() > 0)
    1402     {
    1403       // we've got an nsIException instance, deserialize it and set in the
    1404       // current thread
    1405       nsresult invoke_rv = rv;
    1406       PtrBits bits = (PtrBits) *((void **) completion.Params());
    1407 
    1408       LOG(("got nsIException instance (%p), will create a stub\n", bits));
    1409 
    1410       NS_ASSERTION(completion.ParamsLen() == sizeof(void*),
    1411                    "wrong nsIException serialization");
    1412 
    1413       if (bits & 0x1)
    1414       {
    1415         DConAddr addr = (DConAddr) (bits & ~0x1);
    1416         nsRefPtr<DConnectStub> stub;
    1417         rv = dConnect->CreateStub(nsIException::GetIID(), mPeerID, addr,
    1418                                   getter_AddRefs(stub));
    1419         if (NS_SUCCEEDED(rv))
    1420         {
    1421           rv = em->SetCurrentException((nsIException *)(nsISupports *) stub);
    1422           // restore the method's result
    1423           rv = invoke_rv;
    1424         }
    1425       }
    1426       else if (bits)
    1427       {
    1428         // pointer is to our instance wrapper for nsIException we've set
    1429         // before (the remote method we've just called had called us back
    1430         // and got an exception from us that it decided to return as its
    1431         // own result). Replace it with the real instance.
    1432         DConnectInstance *wrapper = (DConnectInstance *) bits;
    1433         if (dConnect->CheckInstanceAndAddRef(wrapper))
    1434         {
    1435           rv = em->SetCurrentException((nsIException *) wrapper->RealInstance());
    1436           // restore the method's result
    1437           rv = invoke_rv;
    1438           wrapper->Release();
    1439         }
    1440         else
    1441         {
    1442           NS_NOTREACHED("instance wrapper not found");
    1443           rv = NS_ERROR_INVALID_ARG;
    1444         }
    1445       }
    1446       else
    1447       {
    1448         // reset the exception (as requested by the peer)
    1449         // (it doesn't seem to be really necessary since we always reset it at
    1450         // the beginning, but leave it here for clarity)
    1451         rv = em->SetCurrentException(NULL);
    1452         // restore the method's result
    1453         rv = invoke_rv;
    1454       }
     1857    NS_ASSERTION(completion.ParamsLen() >= sizeof(void*),
     1858                 "invalid nsIException serialization length");
     1859    if (completion.ParamsLen() >= sizeof(void*))
     1860    {
     1861      LOG(("got nsIException instance (%p), will create a stub\n",
     1862           *((void **) completion.Params())));
     1863
     1864      nsIException *xcpt = nsnull;
     1865      rv = dConnect->DeserializeException (completion.Params(),
     1866                                           completion.ParamsLen(),
     1867                                           mPeerID, &xcpt);
     1868      if (NS_SUCCEEDED(rv))
     1869      {
     1870        rv = em->SetCurrentException(xcpt);
     1871        NS_IF_RELEASE(xcpt);
     1872      }
     1873      NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
    14551874    }
    14561875  }
     
    15461965    }
    15471966
     1967    if (opLen < sizeof(DConnectSetupReply))
     1968    {
     1969      NS_NOTREACHED("unexpected response size");
     1970      mStatus = NS_ERROR_UNEXPECTED;
     1971      return;
     1972    }
     1973
    15481974    const DConnectSetupReply *reply = (const DConnectSetupReply *) op;
    15491975
     
    15541980      mStatus = reply->status;
    15551981
    1556       // we've been sent an nsIException (that can be null) in case of any error,
    1557       // set it in the current thread
    1558       LOG(("got nsIException instance (%p), will create a stub\n", reply->instance));
    1559 
    1560       nsresult rv;
    1561       nsCOMPtr <nsIExceptionService> es;
    1562       es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
    1563       if (NS_SUCCEEDED(rv))
    1564       {
    1565         nsCOMPtr <nsIExceptionManager> em;
    1566         rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
     1982      const PRUint8 *params = ((const PRUint8 *) op) + sizeof (DConnectSetupReply);
     1983      const PRUint32 paramsLen = opLen - sizeof (DConnectSetupReply);
     1984
     1985      NS_ASSERTION(paramsLen >= sizeof(void*),
     1986                   "invalid nsIException serialization length");
     1987      if (paramsLen >= sizeof(void*))
     1988      {
     1989        LOG(("got nsIException instance (%p), will create a stub\n",
     1990             *((void **) params)));
     1991
     1992        nsresult rv;
     1993        nsCOMPtr <nsIExceptionService> es;
     1994        es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
    15671995        if (NS_SUCCEEDED(rv))
    15681996        {
    1569           if (reply->instance)
     1997          nsCOMPtr <nsIExceptionManager> em;
     1998          rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
     1999          if (NS_SUCCEEDED(rv))
    15702000          {
    15712001            // ensure ipcDConnectService is not deleted before we finish
    15722002            nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    15732003            if (dConnect)
    1574               rv = dConnect->CreateStub(nsIException::GetIID(), sender, reply->instance,
    1575                                         getter_AddRefs(mStub));
     2004            {
     2005              nsIException *xcpt = nsnull;
     2006              rv = dConnect->DeserializeException (params, paramsLen,
     2007                                                   sender, &xcpt);
     2008              if (NS_SUCCEEDED(rv))
     2009              {
     2010                rv = em->SetCurrentException(xcpt);
     2011                NS_IF_RELEASE(xcpt);
     2012              }
     2013            }
    15762014            else
    1577               rv = NS_ERROR_FAILURE;
    1578             if (NS_SUCCEEDED(rv))
    1579             {
    1580               rv = em->SetCurrentException((nsIException *)(nsISupports *) mStub);
    1581             }
    1582           }
    1583           else
    1584           {
    1585             // reset the exception (as requested by the peer)
    1586             rv = em->SetCurrentException(NULL);
     2015              rv = NS_ERROR_UNEXPECTED;
    15872016          }
    15882017        }
    1589       }
    1590 
    1591       if (NS_FAILED(rv))
    1592         mStatus = rv;
     2018        NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
     2019      }
    15932020    }
    15942021    else
     
    23392766      break;
    23402767  }
     2768
     2769  nsVoidArray wrappers;
    23412770
    23422771  // now, create instance wrapper, and store it in our instances set.
     
    23712800            // reference the newly created wrapper
    23722801            wrapper->AddRef();
     2802
     2803            if (!wrappers.AppendElement(wrapper))
     2804            {
     2805              NS_RELEASE(wrapper);
     2806              rv = NS_ERROR_OUT_OF_MEMORY;
     2807            }
    23732808          }
    23742809        }
     
    23792814    }
    23802815  }
    2381   else
     2816
     2817  NS_IF_RELEASE(instance);
     2818
     2819  ipcMessageWriter writer(64);
     2820
     2821  DConnectSetupReply msg;
     2822  msg.opcode_major = DCON_OP_SETUP_REPLY;
     2823  msg.opcode_minor = 0;
     2824  msg.request_index = setup->request_index;
     2825  msg.instance = wrapper;
     2826  msg.status = rv;
     2827
     2828  writer.PutBytes(&msg, sizeof(msg));
     2829
     2830  if (NS_FAILED(rv))
    23822831  {
    23832832    // try to fetch an nsIException possibly set by one of the setup methods
    23842833    // and send it instead of the failed instance (even if it is null)
    2385     nsresult setup_rv = rv;
    23862834    nsCOMPtr <nsIExceptionService> es;
    23872835    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
     
    23992847               (nsIException *)exception));
    24002848
    2401           if (exception)
    2402           {
    2403             nsCOMPtr<nsIInterfaceInfo> iinfo;
    2404             rv = GetInterfaceInfo(nsIException::GetIID(), getter_AddRefs(iinfo));
    2405             if (NS_SUCCEEDED(rv))
    2406             {
    2407               nsAutoLock lock (mLock);
    2408 
    2409               // first try to find an existing wrapper for the given object
    2410               if (!FindInstanceAndAddRef(peer, exception,
    2411                                          &nsIException::GetIID(), &wrapper))
    2412               {
    2413                 wrapper = new DConnectInstance(peer, iinfo, exception);
    2414                 if (!wrapper)
    2415                   rv = NS_ERROR_OUT_OF_MEMORY;
    2416                 else
    2417                 {
    2418                   rv = StoreInstance(wrapper);
    2419                   if (NS_FAILED(rv))
    2420                   {
    2421                     delete wrapper;
    2422                     wrapper = nsnull;
    2423                   }
    2424                   else
    2425                   {
    2426                     // reference the newly created wrapper
    2427                     wrapper->AddRef();
    2428                   }
    2429                 }
    2430               }
    2431 
    2432               // wrapper remains referenced when passing it to the client
    2433               // (will be released upon DCON_OP_RELEASE)
    2434             }
    2435           }
    2436           // otherwise, wrapper = nsnull, which will indicate a null nsIException
    2437 
    2438           // restore the setup result
    2439           if (NS_SUCCEEDED(rv))
    2440             rv = setup_rv;
     2849          rv = SerializeException(writer, peer, exception, wrappers);
    24412850        }
    24422851      }
    24432852    }
    2444   }
    2445 
    2446   NS_IF_RELEASE(instance);
    2447 
    2448   DConnectSetupReply msg;
    2449   msg.opcode_major = DCON_OP_SETUP_REPLY;
    2450   msg.opcode_minor = 0;
    2451   msg.request_index = setup->request_index;
    2452   msg.instance = wrapper;
    2453   msg.status = rv;
     2853    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialze exception");
     2854  }
    24542855
    24552856  // fire off SETUP_REPLY, don't wait for a response
    2456   IPC_SendMessage(peer, kDConnectTargetID,
    2457                   (const PRUint8 *) &msg, sizeof(msg));
     2857  if (NS_FAILED(rv))
     2858    rv = IPC_SendMessage(peer, kDConnectTargetID,
     2859                         (const PRUint8 *) &msg, sizeof(msg));
     2860  else
     2861    rv = IPC_SendMessage(peer, kDConnectTargetID,
     2862                         writer.GetBuffer(), writer.GetSize());
     2863
     2864  if (NS_FAILED(rv))
     2865  {
     2866    LOG(("unable to send SETUP_REPLY: rv=%x\n", rv));
     2867    ReleaseWrappers(wrappers);
     2868  }
    24582869}
    24592870
     
    26503061  if (got_exception)
    26513062  {
    2652     // serialize the exception
    2653     rv = SerializeInterfaceParam(writer, peer, nsIException::GetIID(),
    2654                                  exception, wrappers);
     3063    rv = SerializeException(writer, peer, exception, wrappers);
     3064    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialze exception");
    26553065  }
    26563066  else if (NS_SUCCEEDED(rv) && params)
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h

    r1 r1958  
    2121 * Contributor(s):
    2222 *   Darin Fisher <[email protected]>
     23 *   Dmitry A. Kuminov <[email protected]>
    2324 *
    2425 * Alternatively, the contents of this file may be used under the terms of
     
    7980};
    8081
    81 #endif
    82 
     82#endif // DCONNECT_MULTITHREADED
     83
     84class nsIException;
    8385class ipcMessageWriter;
    8486
     
    216218                                               nsISupports *obj,
    217219                                               nsVoidArray &wrappers);
     220
     221  NS_HIDDEN_(nsresult) SerializeException(ipcMessageWriter &writer,
     222                                          PRUint32 peer, nsIException *xcpt,
     223                                          nsVoidArray &wrappers);
     224  NS_HIDDEN_(nsresult) DeserializeException(const PRUint8 *data, PRUint32 dataLen,
     225                                            PRUint32 peer, nsIException **xcpt);
    218226
    219227  NS_HIDDEN_(void)     ReleaseWrappers(nsVoidArray &wrappers);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette