/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: main.cpp Abstract: User space log viewer Author: Rajesh Sundaram (1st Aug, 1998) Revision History: --*/ #define UNICODE #define INITGUID #include "precomp.h" void ClNotifyHandler( HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event, HANDLE SubCode, ULONG BufSize, PVOID Buffer ) { } static PCHAR SendRecvActions[] = { "", "ENTER", "NO_RESOURCES", "LOW_RESOURCES", "INDICATING", "RETURNED", "NOT_OURS", "OURS", "RETURNING", "TRANSFERRING", "NOT READY"}; #define FILE 1 #define CONFIG 2 #define LEVEL 4 #define MASK 8 VOID ParseOidRecord( CHAR * DataStart, ULONG *Size ) { static PCHAR OIDActions[] = { "", "MpSetInformation", "MpQueryInformation", "SetRequestComplete", "QueryRequestComplete" }; TRACE_RECORD_OID *record = (TRACE_RECORD_OID *)DataStart; *Size = sizeof(TRACE_RECORD_OID); if(record->Now.QuadPart){ printf("[%I64u]: OID: %5s:%9s:(%d:%d):%p:%08X:%08X\n", record->Now.QuadPart, OIDActions[record->Action], record->Local == TRUE?"Local":"Non Local", record->PTState, record->MPState, record->Adapter, record->Oid, record->Status); } else { printf("OID: %5s:%9s:(%d:%d):%p:%08X:%08X\n", OIDActions[record->Action], record->Local == TRUE?"Local":"Non Local", record->PTState, record->MPState, record->Adapter, record->Oid, record->Status); } } VOID ParseStringRecord( CHAR * DataStart, ULONG *Size ) { TRACE_RECORD_STRING *record = (TRACE_RECORD_STRING *) DataStart; *Size = sizeof(TRACE_RECORD_STRING); if(record->Now.QuadPart){ printf("%I64u:%s", record->Now.QuadPart, record->StringStart); } else{ printf("%s", record->StringStart); } } VOID ParseSchedRecord( CHAR * DataStart, ULONG *Size ) { TRACE_RECORD_SCHED * record = (TRACE_RECORD_SCHED *)DataStart; static PCHAR SchedModules[] = { "NOP", "TB CONFORMER", "SHAPER", "DRR SEQ", "CBQ"}; static PCHAR SchedActions[] = { "NOP", "ENQUEUE", "DEQUEUE", "CONFORMANCE", "DISCARD"}; LARGE_INTEGER ArrivalTime, ConformanceTime; ConformanceTime.QuadPart = record->ConformanceTime; ArrivalTime.QuadPart = record->ArrivalTime; printf("SCHED:%s:VC %p:%p:%u:%s:%d:%I64u:[%u,%u]:%I64u:[%u,%u]:%u\n", SchedModules[record->SchedulerComponent], record->VC, record->Packet, record->PacketLength, SchedActions[record->Action], record->Priority, ArrivalTime.QuadPart, ArrivalTime.HighPart, ArrivalTime.LowPart, ConformanceTime.QuadPart, ConformanceTime.HighPart, ConformanceTime.LowPart, record->PacketsInComponent); *Size = sizeof(TRACE_RECORD_SCHED); } VOID ParseRecvRecord( CHAR * DataStart, PULONG size ) { static PCHAR RecvEvents[] = { "", "CL_RECV_PACKET", "MP_RETURN_PACKET", "CL_RECV_INDICATION", "CL_RECV_COMPLETE", "MP_TRANSFER_DATA", "CL_TRANSFER_COMPLETE"}; TRACE_RECORD_RECV *record = (TRACE_RECORD_RECV*)DataStart; *size = sizeof(TRACE_RECORD_RECV); printf("%I64u:Adapter %p:%s:%s:%p:%p \n", record->Now.QuadPart, record->Adapter, RecvEvents[record->Event], SendRecvActions[record->Action], record->Packet1, record->Packet2); } VOID ParseSendRecord( CHAR * DataStart, PULONG Size ) { TRACE_RECORD_SEND* record = (TRACE_RECORD_SEND *)DataStart; static PCHAR SendEvents[] = { "", "MP_SEND", "MP_CO_SEND", "DUP_PACKET", "DROP_PACKET", "CL_SEND_COMPLETE" }; *Size = sizeof(TRACE_RECORD_SEND); printf("%I64u:Adapter %p:%s:%s:%p:%p:%p\n", record->Now.QuadPart, record->Adapter, SendEvents[record->Event], SendRecvActions[record->Action], record->Vc, record->Packet1, record->Packet2); } VOID ParseBuffer( CHAR * DataStart, ULONG Size ) { CHAR * recordEnd; LONG records; BOOLEAN success; CHAR hold; ULONG bytesread; ULONG TotalValidBytesRead = 0; records = 0; while(TRUE) { hold = *(DataStart+4); switch(hold) { case RECORD_TSTRING: ParseStringRecord(DataStart, &bytesread); break; case RECORD_OID: ParseOidRecord(DataStart, &bytesread); break; case RECORD_SCHED: ParseSchedRecord(DataStart, &bytesread); break; case RECORD_RECV: ParseRecvRecord(DataStart, &bytesread); break; case RECORD_SEND: ParseSendRecord(DataStart, &bytesread); break; default: printf("Unrecognized record type!\n"); // // we cannot proceed - we don't know how much to advance it by. // return; } records++; TotalValidBytesRead += bytesread; if(TotalValidBytesRead >= Size){ printf("\nDONE:Completed parsing trace buffer. %d records found.\n", records); break; } DataStart += bytesread; } } BOOLEAN TcDone( HANDLE ClientHandle, HANDLE InterfaceHandle ) { ULONG Status; Status = TcCloseInterface(InterfaceHandle); if(!NT_SUCCESS(Status)) { printf("TcCloseInterface failed : Status = %d \n", Status); } Status = TcDeregisterClient(ClientHandle); if(!NT_SUCCESS(Status)) { printf("TcDeregisterClient failed : Status = %d \n", Status); } return TRUE; } BOOLEAN TcInit( PHANDLE ClientHandle, PHANDLE InterfaceHandle ) { TCI_CLIENT_FUNC_LIST ClientHandlerList; ULONG Size = 100 * sizeof(TC_IFC_DESCRIPTOR); PTC_IFC_DESCRIPTOR InterfaceBuffer; ULONG x, Status; memset( &ClientHandlerList, 0, sizeof(ClientHandlerList) ); ClientHandlerList.ClNotifyHandler = ClNotifyHandler; InterfaceBuffer = (PTC_IFC_DESCRIPTOR) malloc(Size); if(!InterfaceBuffer) return FALSE; // // Register the TC client. // Status = TcRegisterClient(CURRENT_TCI_VERSION, NULL, &ClientHandlerList, ClientHandle); if(!NT_SUCCESS(Status)) { printf("Cannot register as TC client \n"); free(InterfaceBuffer); return FALSE; } // // Enumerate interfaces. // Status = TcEnumerateInterfaces( *ClientHandle, &Size, InterfaceBuffer); if(ERROR_INSUFFICIENT_BUFFER == Status) { free(InterfaceBuffer); InterfaceBuffer = (PTC_IFC_DESCRIPTOR) malloc(Size); if ( !InterfaceBuffer ) { TcDeregisterClient(*ClientHandle); printf("Unable to allocate memory to call TcEnumerateInterfaces\n"); return FALSE; } Status = TcEnumerateInterfaces( *ClientHandle, &Size, InterfaceBuffer); if(!NT_SUCCESS(Status)) { TcDeregisterClient(*ClientHandle); free(InterfaceBuffer); printf("TcEnumerateInterfaces failed with error %d \n", Status); return FALSE; } } else { if(!NT_SUCCESS(Status)) { TcDeregisterClient(*ClientHandle); free(InterfaceBuffer); printf("TcEnumerateInterfaces failed with error %d \n", Status); return FALSE; } } if(Size) { Status = TcOpenInterface( InterfaceBuffer->pInterfaceName, *ClientHandle, NULL, InterfaceHandle); if(!NT_SUCCESS(Status)) { // printf("TcOpenInterface failed for interface %ws with Status %d \n", InterfaceBuffer->pInterfaceName, Status); TcDeregisterClient(*ClientHandle); free(InterfaceBuffer); return FALSE; } } else { printf("No Traffic Interfaces \n"); return FALSE; } return TRUE; } int __cdecl main(int argc, char **argv) { HANDLE ClientHandle, InterfaceHandle; BOOLEAN flags = 0; ULONG mask, level; ULONG DataSize; CHAR *Buffer; if (argc < 2) goto usage; argv++; argc--; while( argc>0 && argv[0][0] == '-' ) { switch (argv[0][1]) { case 'F': case 'f': flags |= FILE; break; case 'c': case 'C': flags |= CONFIG; break; case 'l': case 'L': if(sscanf(&argv[0][2], "%d", &level) == 1) { if((ULONG)level > 10) { goto usage; } flags |= LEVEL; } else { goto usage; } break; case 'm': case 'M': if(argv[0][2]!='0' && argv[0][3]!='x') { goto usage; } if(sscanf(&argv[0][2], "%x", &mask) == 1) { flags |= MASK; } else goto usage; break; default: goto usage; } argv++; argc--; } if((flags & CONFIG) && (flags & (FILE|LEVEL|MASK))) { goto usage; } if(TcInit(&ClientHandle, &InterfaceHandle)) { ULONG size = sizeof(ULONG); ULONG chk; if(TcQueryInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_MASK, FALSE, &size, &chk) != STATUS_SUCCESS) { printf("Does not work on free bits \n"); } if(flags & LEVEL) { TcSetInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_LEVEL, sizeof(level), &level); } if(flags & MASK) { printf("Setting Mask to 0x%x \n", mask); TcSetInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_MASK, sizeof(mask), &mask); } if(flags & CONFIG) { TcQueryInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_MASK, FALSE, &size, &mask); TcQueryInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_LEVEL, FALSE, &size, &level); printf("Masks supported\n"); printf(" DBG_INIT 0x00000001 \n"); printf(" DBG_MINIPORT 0x00000002 \n"); printf(" DBG_PROTOCOL 0x00000004 \n"); printf(" DBG_SEND 0x00000008 \n"); printf(" DBG_RECEIVE 0x00000010 \n"); printf(" DBG_IO 0x00000020 \n"); printf(" DBG_MEMORY 0x00000040 \n"); printf(" DBG_CM 0x00000080 \n"); printf(" DBG_REFCNTS 0x00000100 \n"); printf(" DBG_VC 0x00000200 \n"); printf(" DBG_GPC_QOS 0x00000400 \n"); printf(" DBG_WAN 0x00000800 \n"); printf(" DBG_STATE 0x00001000 \n"); printf(" DBG_ROUTINEOIDS 0x00002000 \n"); printf(" DBG_SCHED_TBC 0x00004000 \n"); printf(" DBG_SCHED_SHAPER 0x00008000 \n"); printf(" DBG_SCHED_DRR 0x00010000 \n"); printf(" DBG_WMI 0x00020000 \n"); printf("\nLevels supported\n"); printf(" DBG_DEATH 1\n"); printf(" DBG_CRITICAL_ERROR 2\n"); printf(" DBG_FAILURE 4\n"); printf(" DBG_INFO 6\n"); printf(" DBG_TRACE 8\n"); printf(" DBG_VERBOSE 10\n"); printf("\n Current Level is %d, Current Mask is 0x%x \n", level, mask); } if(flags & FILE) { ULONG Status; Status = TcQueryInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_THRESHOLD, FALSE, &size, &DataSize); DataSize *= 2; if(NT_SUCCESS(Status)) { if(DataSize != 0) { Buffer = (PCHAR) malloc(DataSize); Status = TcQueryInterface(InterfaceHandle, (LPGUID)&GUID_QOS_LOG_DATA, FALSE, &DataSize, Buffer); if(NT_SUCCESS(Status)) { ParseBuffer(Buffer, DataSize); } else { printf("Query for the data buffer failed with status %d \n", Status); } free(Buffer); } else { printf("No Data in buffer. \n"); } } else { printf("Failed to read the sched bytes unread \n"); } } TcDone(InterfaceHandle, ClientHandle); } return 0; usage: printf("Usage %s [-f | -c | -m<0xmask> | -l ] \n", argv[0]); printf(" -f : dump the tt log on screen. \n"); printf(" -c : Print the current value of the mask and level \n"); printf(" -m<0xvalue> : Set the mask to this value \n"); printf(" -l : Set the level to this value (0-10) \n"); return 1; }