1130 // Multiple-completion malarky. |
1185 // Multiple-completion malarky. |
1131 // Don't copy data across to other buffers and complete their reqs if TSY knows about |
1186 // Don't copy data across to other buffers and complete their reqs if TSY knows about |
1132 // each client that has called it. In that case, |
1187 // each client that has called it. In that case, |
1133 // TSY will fill in the appropriate client's buffer and complete each separately. |
1188 // TSY will fill in the appropriate client's buffer and complete each separately. |
1134 if (reqMode&KReqModeMultipleCompletionEnabled) |
1189 if (reqMode&KReqModeMultipleCompletionEnabled) |
|
1190 { |
|
1191 |
1135 PhoneOwner()->CheckAndCompleteAllActive(updatedReqEntry,reqMode,ipc,aError); |
1192 PhoneOwner()->CheckAndCompleteAllActive(updatedReqEntry,reqMode,ipc,aError); |
1136 |
1193 } |
|
1194 else if (reqMode&KReqModeMultipleCompletionWithInterestLevel && error ==KErrNone) |
|
1195 { |
|
1196 // TODO if delivery is active for this req then return |
|
1197 // KErrInUse / KErrServerBusy? |
|
1198 // TODO what if one CTelObject has multiple requests which are |
|
1199 // KReqModeMultipleCompletionWithInterestLevel. Would we need multiple |
|
1200 // delivery managers? |
|
1201 if (!IsSessionInProgress()) |
|
1202 { |
|
1203 // Find an owner for the new session by offering it to the |
|
1204 // interested clients one by one. |
|
1205 DeliverReqL(updatedReqEntry,reqMode, ipc, aError); |
|
1206 } |
|
1207 else |
|
1208 { |
|
1209 // Route response direct to session owner |
|
1210 FindReq(updatedReqEntry, reqMode, ipc, aError); |
|
1211 } |
|
1212 |
|
1213 } |
|
1214 |
1137 if (reqMode&KReqModeRePostImmediately && error==KErrNone) |
1215 if (reqMode&KReqModeRePostImmediately && error==KErrNone) |
1138 nextPostedReqEntry = updatedReqEntry; |
1216 nextPostedReqEntry = updatedReqEntry; |
1139 updatedReqEntry->iBuffer->IncWrite(); |
1217 updatedReqEntry->iBuffer->IncWrite(); |
1140 } |
1218 } |
1141 else // if a cancel comes from the TSY, then if it is a notification |
1219 else // if a cancel comes from the TSY, then if it is a notification |
1142 // there may be other clients who have also called the notification and who |
1220 // there may be other clients who have also called the notification and who |
1143 // have entries in active list, so one of these must be re-posted. |
1221 // have entries in active list, so one of these must be re-posted. |
1144 { |
1222 { |
1145 if (reqMode&KReqModeMultipleCompletionEnabled) |
1223 |
1146 nextPostedReqEntry = PhoneOwner()->FindThisReqByAnotherClient(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc,updatedReqEntry->iBuffer->Size(),this); |
1224 if ( reqMode&KReqModeMultipleCompletionEnabled || reqMode&KReqModeMultipleCompletionWithInterestLevel) |
|
1225 { |
|
1226 nextPostedReqEntry = PhoneOwner()->FindThisReqByAnotherClient(updatedReqEntry->iSession, |
|
1227 updatedReqEntry->iMessage.Int3(),ipc,updatedReqEntry->iBuffer->Size(),this); |
|
1228 } |
|
1229 |
1147 if (!nextPostedReqEntry) |
1230 if (!nextPostedReqEntry) |
1148 // then we don't want to post any other client's requests in place of this one |
1231 // then we don't want to post any other client's requests in place of this one |
1149 { |
1232 { |
1150 nextPostedReqEntry = PhoneOwner()->FindNonCancelledClientReq(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc); |
1233 nextPostedReqEntry = PhoneOwner()->FindNonCancelledClientReq(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc); |
1151 __ASSERT_DEBUG(updatedReqEntry!=nextPostedReqEntry, Fault(EEtelFaultCancelErrorWithoutCancelled)); |
1234 __ASSERT_DEBUG(updatedReqEntry!=nextPostedReqEntry, Fault(EEtelFaultCancelErrorWithoutCancelled)); |
1156 if (ret!=KErrNone) |
1239 if (ret!=KErrNone) |
1157 error=ret; // so the KErrCancel wouldn't reach the client |
1240 error=ret; // so the KErrCancel wouldn't reach the client |
1158 } |
1241 } |
1159 } |
1242 } |
1160 } |
1243 } |
|
1244 |
|
1245 if (error && reqMode&KReqModeMultipleCompletionWithInterestLevel && iDeliveryObject) |
|
1246 { |
|
1247 // We need to do this before the updatedReqEntry is destroyed |
|
1248 iDeliveryObject->DeletedReqEntry(updatedReqEntry); |
|
1249 } |
|
1250 |
1161 if (reqMode & KReqModeRePostImmediately) |
1251 if (reqMode & KReqModeRePostImmediately) |
1162 UpdateAndCompleteIfNecessary(updatedReqEntry,error); // this will destroy the reqEntry |
1252 { |
1163 // if an error occurred. |
1253 // this will destroy the reqEntry if an error occurred. |
|
1254 UpdateAndCompleteIfNecessary(updatedReqEntry,error); |
|
1255 } |
1164 else |
1256 else |
|
1257 { |
1165 WriteBackAndCompleteReq(updatedReqEntry,error); |
1258 WriteBackAndCompleteReq(updatedReqEntry,error); |
|
1259 } |
|
1260 |
1166 if (nextPostedReqEntry) // will be NULL if no following request for TSY |
1261 if (nextPostedReqEntry) // will be NULL if no following request for TSY |
1167 { |
1262 { |
1168 if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed) |
1263 if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed && |
|
1264 !(nextPostedReqEntry->iReqMode&KReqModeMultipleCompletionWithInterestLevel)) |
1169 { // since the request mode is flow control obeyed, increment the flow control counter |
1265 { // since the request mode is flow control obeyed, increment the flow control counter |
1170 FlowControlSuspend(); |
1266 FlowControlSuspend(); |
1171 } |
1267 } |
1172 Service(nextPostedReqEntry->iMessage,nextPostedReqEntry); |
1268 Service(nextPostedReqEntry->iMessage,nextPostedReqEntry); |
1173 } |
1269 } |
1174 |
1270 |
1175 |
1271 |
1176 if (!(reqMode&KReqModeFlowControlObeyed)) // If flow control not enabled, go home |
1272 if (!(reqMode&KReqModeFlowControlObeyed)) // If flow control not enabled, go home |
|
1273 { |
1177 ret=ETrue; |
1274 ret=ETrue; |
1178 |
1275 } |
|
1276 |
1179 // So everything below assumes it obeyed flow control |
1277 // So everything below assumes it obeyed flow control |
1180 // Resume Flow control ... |
1278 // Resume Flow control ... |
1181 if (!ret) |
1279 if (!ret) |
|
1280 { |
1182 FlowControlResume(); |
1281 FlowControlResume(); |
|
1282 } |
1183 // |
1283 // |
1184 // Check and destroying the dummy session |
1284 // Check and destroying the dummy session |
1185 // |
1285 // |
1186 CheckAndDestroyDummySubSession(); |
1286 CheckAndDestroyDummySubSession(); |
1187 } |
1287 } |
|
1288 |
|
1289 TInt CTelObject::DeliverReqL(CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aIpc, const TInt aError) |
|
1290 { |
|
1291 // There is no active session therefore we have to work out who to deliver it to. |
|
1292 if (!iDeliveryObject) |
|
1293 { |
|
1294 iDeliveryObject = CMmDeliveryObject::NewL(*this); |
|
1295 } |
|
1296 |
|
1297 if (iDeliveryObject->DeliveryInProgress()) |
|
1298 { |
|
1299 // Session in progress. |
|
1300 return KErrPermissionDenied; |
|
1301 } |
|
1302 |
|
1303 return iDeliveryObject->DeliverReqL(PhoneOwner()->ReqActiveList(), aUpdatedReqEntry, aReqMode, aIpc, aError); |
|
1304 } |
|
1305 |
|
1306 void CTelObject::FindReq(CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aIpc,const TInt aError) |
|
1307 { |
|
1308 CReqEntry* reqEntry; |
|
1309 TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList()); |
|
1310 while(reqEntry = iter++, reqEntry!=NULL) |
|
1311 { |
|
1312 if(reqEntry->iFunction==aIpc |
|
1313 && reqEntry->iTelObject==aUpdatedReqEntry->iTelObject |
|
1314 && reqEntry->iBuffer->Size()==aUpdatedReqEntry->iBuffer->Size() |
|
1315 /*&& IsSessionOwner(reqEntry)*/) |
|
1316 { |
|
1317 if (aUpdatedReqEntry != reqEntry) |
|
1318 { |
|
1319 // Copy data from the 'placed' request to the one |
|
1320 // that is owned by the client. |
|
1321 PhoneOwner()->UpdateBuffer(aUpdatedReqEntry,reqEntry); |
|
1322 } |
|
1323 OfferToClient(reqEntry, aUpdatedReqEntry, aReqMode, aError); |
|
1324 RepostRequest(aUpdatedReqEntry, aError); |
|
1325 } |
|
1326 } |
|
1327 } |
|
1328 |
|
1329 void CTelObject::OfferToClient(CReqEntry* aReqEntry,CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aError) |
|
1330 { |
|
1331 if (aReqEntry == aUpdatedReqEntry) |
|
1332 { |
|
1333 aUpdatedReqEntry->iBuffer->IncWrite(); |
|
1334 if (aReqMode&KReqModeRePostImmediately) |
|
1335 { |
|
1336 // this will destroy the reqEntry if an error occurred. |
|
1337 UpdateAndCompleteIfNecessary(aUpdatedReqEntry,aError); |
|
1338 } |
|
1339 else |
|
1340 { |
|
1341 WriteBackAndCompleteReq(aUpdatedReqEntry,aError); |
|
1342 } |
|
1343 } |
|
1344 else |
|
1345 { |
|
1346 TInt error = ResolveError(aReqEntry->iSession,aError); // set error as either low or high byte |
|
1347 if (aReqMode&KReqModeRePostImmediately) |
|
1348 { |
|
1349 UpdateAndCompleteIfNecessary(aReqEntry,error); |
|
1350 } |
|
1351 else |
|
1352 { |
|
1353 WriteBackAndCompleteReq(aReqEntry,error); |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 CheckAndDestroyDummySubSession(); //TODO |
|
1358 } |
|
1359 |
|
1360 void CTelObject::RepostRequest(CReqEntry* aUpdatedReqEntry, const TInt aError) |
|
1361 { |
|
1362 TReqMode reqMode = aUpdatedReqEntry->iReqMode; |
|
1363 TBool ret=EFalse; |
|
1364 |
|
1365 CReqEntry* nextPostedReqEntry = NULL; |
|
1366 if (reqMode&KReqModeRePostImmediately && aError==KErrNone) |
|
1367 { |
|
1368 nextPostedReqEntry = aUpdatedReqEntry; |
|
1369 } |
|
1370 |
|
1371 if (nextPostedReqEntry) // will be NULL if no following request for TSY |
|
1372 { |
|
1373 if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed) |
|
1374 { // since the request mode is flow control obeyed, increment the flow control counter |
|
1375 FlowControlSuspend(); |
|
1376 } |
|
1377 Service(nextPostedReqEntry->iMessage,nextPostedReqEntry); |
|
1378 } |
|
1379 |
|
1380 if (!(reqMode&KReqModeFlowControlObeyed && aError == KErrNone)) // If flow control not enabled, go home |
|
1381 ret=ETrue; |
|
1382 |
|
1383 // So everything below assumes it obeyed flow control |
|
1384 // Resume Flow control ... |
|
1385 if (!ret) |
|
1386 FlowControlResume(); |
|
1387 } |
|
1388 |
|
1389 void CTelObject::SetSessionOwner(TInt aSessionHandle, TInt aSubSessionHandle) |
|
1390 { |
|
1391 iDeliveryObject->iSessionOwner = TPhoneClientId(aSessionHandle, aSubSessionHandle); |
|
1392 // TODO notify TSY that the session owner has changed |
|
1393 } |
|
1394 |
|
1395 // TODO can be used by the TSY to set the session owner to the current request. |
|
1396 // For each request the CTSY is given a TsyReqHandle so this is a sensible thing |
|
1397 // for it to be dealing with. |
|
1398 // TODO note that once a session has an owner the reserved state is irrelevant. |
|
1399 |
|
1400 EXPORT_C void CTelObject::SetSessionOwnerByTsyHandle(const TTsyReqHandle aTsyReqHandle) |
|
1401 { |
|
1402 // const TInt owningsession = PhoneOwner()->FindSessionByTsyHandle( aTsyReqHandle ); |
|
1403 // const TInt owningsubsession = PhoneOwner()->FindSubSessionByTsyHandle( aTsyReqHandle ); |
|
1404 |
|
1405 // iSessionOwner = TPhoneClientId(owningsession, owningsubsession); |
|
1406 // TODO notify TSY that the session owner has changed |
|
1407 } |
|
1408 |
|
1409 |
|
1410 TBool CTelObject::IsSessionOwner(CReqEntry* aReqEntry) const |
|
1411 { |
|
1412 // TODO Neil's experimental update |
|
1413 TPhoneClientId clientId(reinterpret_cast<TInt>(aReqEntry->iSession),aReqEntry->iMessage.Int3()); |
|
1414 return (clientId == iDeliveryObject->iSessionOwner); |
|
1415 } |
|
1416 |
|
1417 TInterestCategory CTelObject::FindInterestCategory( const TSecureId aSid) |
|
1418 { |
|
1419 if (aSid == KUssdPriorityClientSid) |
|
1420 { |
|
1421 return EInterestCategoryPriority; |
|
1422 } |
|
1423 else if(aSid == KUssdDefaultClientSid) |
|
1424 { |
|
1425 return EInterestCategoryDefault; |
|
1426 } |
|
1427 else |
|
1428 return EInterestCategoryStandard; |
|
1429 } |
|
1430 |
|
1431 EXPORT_C TBool CTelObject::IsSessionInProgress() const |
|
1432 { |
|
1433 // TODO Neil's experimental update |
|
1434 if (iDeliveryObject) |
|
1435 { |
|
1436 return iDeliveryObject->iSessionOwner != TPhoneClientId(); |
|
1437 } |
|
1438 return EFalse; |
|
1439 } |
|
1440 |
|
1441 EXPORT_C TInt CTelObject::ReserveSession() |
|
1442 { |
|
1443 // TODO Neil's experimental update |
|
1444 ASSERT(iDeliveryObject); |
|
1445 if (iDeliveryObject->iSessionReserved) |
|
1446 { |
|
1447 return KErrInUse; |
|
1448 } |
|
1449 iDeliveryObject->iSessionReserved = ETrue; |
|
1450 return KErrNone; |
|
1451 } |
|
1452 |
|
1453 EXPORT_C TBool CTelObject::IsSessionReserved() const |
|
1454 { |
|
1455 // TODO Neil's experimental update |
|
1456 return iDeliveryObject->iSessionReserved; |
|
1457 } |
|
1458 |
|
1459 EXPORT_C void CTelObject::CancelReserveSession() |
|
1460 { |
|
1461 // TODO Neil's experimental update |
|
1462 iDeliveryObject->iSessionReserved = EFalse; |
|
1463 } |
|
1464 |
|
1465 EXPORT_C void CTelObject::EndSession() |
|
1466 { |
|
1467 // TODO Neil's experimental update |
|
1468 iDeliveryObject->iSessionOwner = TPhoneClientId(); |
|
1469 iDeliveryObject->iSessionReserved = EFalse; |
|
1470 } |
1188 |
1471 |
1189 TInt CTelObject::ResolveError(CTelSession* aSession, const TInt aError) const |
1472 TInt CTelObject::ResolveError(CTelSession* aSession, const TInt aError) const |
1190 /** |
1473 /** |
1191 * Converts a coded error into the correct error to return. The coded error value |
1474 * Converts a coded error into the correct error to return. The coded error value |
1192 * allows an extended error code to be present allong with a basic error code. If |
1475 * allows an extended error code to be present allong with a basic error code. If |