sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Test code for interrupted IO operations sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include // for RDebug sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include // for E32IOSELECT sl@0: #include sl@0: #include sl@0: sl@0: extern "C" { sl@0: #include "CTEST.H" sl@0: } sl@0: test_Data; sl@0: sl@0: #include // for multi-threading control sl@0: sl@0: int testFid; sl@0: struct sockaddr_in testAddr; sl@0: RSemaphore semaphores[2]; sl@0: sl@0: void init_test() sl@0: { sl@0: // We need a datagram socket that we can send to sl@0: sl@0: test_Next("Create datagram socket"); sl@0: testFid=socket(PF_INET, SOCK_DGRAM, 0); sl@0: test_ok(testFid>=0); sl@0: sl@0: test_Next("Bind to local address"); sl@0: IN_SET_LOOPBACK_ADDR(&testAddr); sl@0: testAddr.sin_port=0; sl@0: sl@0: size_t len=sizeof(testAddr); sl@0: int err=bind(testFid, (struct sockaddr*)&testAddr, len); sl@0: test_ok(err==0); sl@0: sl@0: err=getsockname(testFid, (struct sockaddr*)&testAddr, &len); sl@0: test_ok(err==0); sl@0: sl@0: // We now have a datagram socket with a known address sl@0: sl@0: test_Next("Create semaphores for test synchronisation"); sl@0: for (int i=0; i<2; i++) sl@0: { sl@0: err=semaphores[i].CreateLocal(0); sl@0: test(err==KErrNone); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Test of the asynchronous ioctl & cancel code sl@0: sl@0: @SYMTestCaseID SYSLIB-STDLIB-CT-1044 sl@0: @SYMTestCaseDesc Tests for the asynchronous ioctl & cancel code sl@0: @SYMTestPriority High sl@0: @SYMTestActions Tests that E32IOSELECT ioctl is working sl@0: Tests for asynchronous IOCTL. sl@0: Setup asynchronous IOCTL which won't complete, then cancel.Check for cancel status sl@0: Cancel a completed asynchronous IOCTL,and check for no error sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ0000 sl@0: */ sl@0: void test_ioctl() sl@0: { sl@0: // confirm that the E32IOSELECT ioctl is working sl@0: test_Next("Check synchronous IOCTL"); sl@0: int mask=E32SELECT_READ|E32SELECT_WRITE|E32SELECT_EXCEPT; sl@0: int err=ioctl(testFid,E32IOSELECT,&mask); sl@0: test_ok(err==0); sl@0: test(mask==E32SELECT_WRITE); sl@0: sl@0: test_Next("Check asynchronous IOCTL"); sl@0: TRequestStatus status; sl@0: mask=E32SELECT_READ|E32SELECT_WRITE|E32SELECT_EXCEPT; sl@0: err=ioctl(testFid,E32IOSELECT,&mask,status); sl@0: test_ok(err==0); sl@0: User::WaitForRequest(status); sl@0: test(status.Int()==KErrNone); sl@0: err=ioctl_complete(testFid,E32IOSELECT,&mask,status); sl@0: test_ok(err==0); sl@0: test(mask==E32SELECT_WRITE); sl@0: sl@0: test_Next("Setup asynchronous IOCTL which won't complete, then cancel"); sl@0: mask=E32SELECT_READ; sl@0: err=ioctl(testFid,E32IOSELECT,&mask,status); sl@0: test_ok(err==0); sl@0: test(status.Int()==KRequestPending); // i.e. waiting for input to arrive sl@0: sl@0: // test_Next("Cancel the pending IOCTL"); sl@0: // Sadly this will do write() which will get a KErrInUse and then panic... sl@0: err=ioctl_cancel(testFid); sl@0: test_ok(err==0); sl@0: User::WaitForRequest(status); sl@0: test_Next("Check that ioctl_cancel worked"); sl@0: test(status.Int()==KErrCancel); // i.e. it was cancelled sl@0: sl@0: test_Next("Cancel a completed asynchronous IOCTL"); sl@0: mask=E32SELECT_WRITE; sl@0: err=ioctl(testFid,E32IOSELECT,&mask,status); sl@0: test_ok(err==0); sl@0: sl@0: while (status.Int() == KRequestPending) sl@0: User::After(5000); sl@0: sl@0: test(status.Int()!=KRequestPending); // i.e. select has completed sl@0: sl@0: // test_Next("Cancel the pending IOCTL"); sl@0: // Sadly this will do write() which will get a KErrInUse and then panic... sl@0: err=ioctl_cancel(testFid); sl@0: test_ok(err==0); sl@0: User::WaitForRequest(status); sl@0: test(status.Int()==KErrNone); // i.e. it was cancelled sl@0: sl@0: } sl@0: sl@0: // Thread functions which will block accessing the socket sl@0: sl@0: TInt ioctl_block(TAny* aSemIndex) sl@0: { sl@0: semaphores[(TInt)aSemIndex].Wait(); // block until the test is ready sl@0: sl@0: int mask=E32SELECT_READ; sl@0: int err=ioctl(testFid,E32IOSELECT,&mask); sl@0: test_ok(err==0); sl@0: test(mask==E32SELECT_READ); sl@0: return 1; sl@0: } sl@0: sl@0: TInt recv_block(TAny* aSemIndex) sl@0: { sl@0: semaphores[(TInt)aSemIndex].Wait(); // block until the test is ready sl@0: sl@0: char buf[256]; sl@0: // Problem in recvfrom: int err=recvfrom(testFid,buf,MSG_PEEK,sizeof(buf),0,0); sl@0: struct sockaddr_in junk; sl@0: size_t junklen=sizeof(junk); sl@0: // Problem in esock/tcpip: int err=recvfrom(testFid,buf,sizeof(buf),MSG_PEEK,(struct sockaddr*)&junk,&junklen); sl@0: int err=recvfrom(testFid,buf,sizeof(buf),0,(struct sockaddr*)&junk,&junklen); sl@0: // Problem in recfrom: test_ok(err>0); sl@0: test_ok(err>=0); sl@0: return 1; sl@0: } sl@0: sl@0: void kill_and_check(RThread& aVictim, TRequestStatus& aVictimStatus, TRequestStatus& aSurvivorStatus) sl@0: { sl@0: test(aVictimStatus.Int()==KRequestPending); sl@0: test(aSurvivorStatus.Int()==KRequestPending); sl@0: aVictim.Kill(666); sl@0: char* KDatagram="Mine is the last voice you will ever hear"; sl@0: int length=strlen(KDatagram)+1; sl@0: sl@0: test_Next("Send datagram"); sl@0: int err=sendto(testFid,KDatagram, length,0,(struct sockaddr*)&testAddr,sizeof(testAddr)); sl@0: test_ok(err==length); sl@0: User::After(1); sl@0: sl@0: test_Next("Check the victim status"); sl@0: User::WaitForRequest(aVictimStatus); sl@0: test(aVictimStatus.Int()==666); sl@0: sl@0: test_Next("Check the survivor status"); sl@0: User::WaitForRequest(aSurvivorStatus); sl@0: test(aSurvivorStatus.Int()==1); sl@0: sl@0: // Check to see if the datagram has been swallowed sl@0: int mask=E32SELECT_READ|E32SELECT_WRITE|E32SELECT_EXCEPT; sl@0: err=ioctl(testFid,E32IOSELECT,&mask); sl@0: test_ok(err==0); sl@0: if ((mask&E32SELECT_READ)==0) sl@0: return; // yes - nothing to read sl@0: sl@0: test_Next("Consume the datagram"); sl@0: char buf[256]; sl@0: // Problem in recvfrom: err=recvfrom(testFid,buf,sizeof(buf),0,0,0); sl@0: struct sockaddr_in junk; sl@0: size_t junklen=sizeof(junk); sl@0: err=recvfrom(testFid,buf,sizeof(buf),0,(struct sockaddr*)&junk,&junklen); sl@0: // Problem in recfrom: test_ok(err==length); sl@0: test_ok(err>=0); sl@0: } sl@0: /** sl@0: @SYMTestCaseID SYSLIB-STDLIB-CT-1045 sl@0: @SYMTestCaseDesc Tests for killing an ioctl sl@0: @SYMTestPriority High sl@0: @SYMTestActions Create two threads which will block on the socket sl@0: then kill one of them and send a datagram sl@0: check the exit status of both threads sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ0000 sl@0: */ sl@0: void test_killing(TInt aThread, TThreadFunction aFunction, char* aTitle) sl@0: { sl@0: _LIT(KThreadName, "TCancel Test Thread %d"); sl@0: TBuf<80> threadName; sl@0: static TInt threadNumber=0; sl@0: sl@0: test_Next(aTitle); sl@0: // test_Next("Create test thread A"); sl@0: RThread thread1; sl@0: TRequestStatus status1; sl@0: threadName.Format(KThreadName,++threadNumber); sl@0: TInt err=thread1.Create(threadName,aFunction,0x10000,NULL,(TAny*)0); sl@0: test(err==KErrNone); sl@0: thread1.Logon(status1); sl@0: thread1.Resume(); sl@0: sl@0: // test_Next("Create test thread B"); sl@0: RThread thread2; sl@0: TRequestStatus status2; sl@0: threadName.Format(KThreadName,++threadNumber); sl@0: err=thread2.Create(threadName,aFunction,0x10000,NULL,(TAny*)1); sl@0: test(err==KErrNone); sl@0: thread2.Logon(status2); sl@0: thread2.Resume(); sl@0: sl@0: test_Next("Start thread A, then thread B..."); sl@0: semaphores[0].Signal(); sl@0: User::After(1); sl@0: semaphores[1].Signal(); sl@0: User::After(1); sl@0: sl@0: if (aThread==1) sl@0: { sl@0: test_Next("Kill thread A"); sl@0: kill_and_check(thread1, status1, status2); sl@0: } sl@0: else sl@0: { sl@0: test_Next("Kill thread B"); sl@0: kill_and_check(thread2, status2, status1); sl@0: } sl@0: sl@0: thread1.Close(); sl@0: thread2.Close(); sl@0: } sl@0: sl@0: int main() sl@0: { sl@0: sl@0: start_redirection_server(); sl@0: sl@0: test_Title("TCANCEL"); sl@0: init_test(); sl@0: test_ioctl(); // explicit cancellation sl@0: test_killing(1,ioctl_block, "Cancellation of active ioctl"); sl@0: test_killing(2,ioctl_block, "Cancellation of queued ioctl"); sl@0: test_killing(1,recv_block, "Cancellation of active recvfrom"); sl@0: test_killing(2,recv_block, "Cancellation of queued recvfrom"); sl@0: test_Close(); sl@0: return KErrNone; sl@0: }