#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFSerialize.h>
#include <IOKit/network/IONetworkLib.h>
#include <mach/mach.h>
#include <mach/mach_interface.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/file.h>
#include "kdp_protocol.h"
#include "IrDALog.h"
#pragma mark -- Prototypes
int DumpRemoteLog(int argc, char ** argv);
int DumpLocalLog();
void DumpLog(void); void OutputBuffer(IrDALogHdr *hdr, IrDAEventDesc *events, char *msgs, FILE *out);
Boolean CheckLog(IrDALogHdr *obj);
FILE *CreateLogFile(void);
Boolean SetPeer(char **argv);
Boolean DoRequest(kdp_req_t command, UInt32 length);
Boolean DoConnect(UInt16 localport);
Boolean DoDisconnect(void);
Boolean ReadLog(void *addr); Boolean DoRead(void *remote_addr, void *local_addr, int length);
#if 0
extern "C" kern_return_t io_connect_method_structureI_structureO
(
mach_port_t connection,
int selector,
io_struct_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt
);
#endif
typedef struct IrDACommand
{
unsigned char commandID; char data[1]; } IrDACommand;
typedef IrDACommand *IrDACommandPtr;
kern_return_t doCommand(io_connect_t con, unsigned char commandID,
void *inputData, unsigned long inputDataSize,
void *outputData, size_t *outputDataSize);
kern_return_t openDevice(io_object_t obj, io_connect_t * con);
kern_return_t closeDevice(io_connect_t con);
io_object_t getInterfaceWithName(mach_port_t masterPort, char *className);
#pragma mark -- Globals
char bigbuffer[10*1024*1024]; IrDALogInfo info; UInt32 infoaddr;
int f; struct sockaddr_in peeraddr;
char hostname[100];
UInt8 packet[MAX_KDP_PKT_SIZE];
UInt32 key; UInt8 seq;
#define Punt(x) { fprintf(stderr, "%s: %s\n", argv[0], x); return -1; }
#define PuntErr(x) { fprintf(stderr, "%s: %s [%s]\n", argv[0], x, strerror(errno)); return 1; }
int
main(int argc, char ** argv)
{
if (argc == 1)
return DumpLocalLog();
else if (argc == 3)
return DumpRemoteLog(argc, argv);
printf("usage: %s # to dump irdalog on local machine\n", argv[0]);
printf(" %s hostname 0xLogInfoAddress # remote log\n", argv[0]);
return 1;
}
#pragma mark -- Dump local log
int
DumpLocalLog()
{
mach_port_t masterPort;
kern_return_t kr;
io_object_t netif;
io_connect_t conObj;
kr = IOMasterPort(bootstrap_port, &masterPort);
if (kr != KERN_SUCCESS) {
printf("IOMasterPort() failed: %08lx\n", (unsigned long)kr);
return -1;
}
netif = getInterfaceWithName(masterPort, "AppleIrDA");
if (netif) {
kr = openDevice(netif, &conObj);
if (kr == kIOReturnSuccess) {
UInt32 inbuf[2]; size_t infosize;
inbuf[0] = (UInt32)&bigbuffer[0];
inbuf[1] = sizeof(bigbuffer);
infosize = sizeof(info);
kr = doCommand(conObj, 0x12, &inbuf, sizeof(inbuf), &info, &infosize);
if (kr == kIOReturnSuccess) {
DumpLog();
}
else printf("command/request failed 0x%x\n", kr);
closeDevice(conObj);
}
else printf("open device failed 0x%x\n", kr);
IOObjectRelease(netif);
}
exit(0);
}
kern_return_t
openDevice(io_object_t obj, io_connect_t * con)
{
return IOServiceOpen(obj, mach_task_self(), 123, con);
}
kern_return_t
closeDevice(io_connect_t con)
{
return IOServiceClose(con);
}
io_object_t
getInterfaceWithName(mach_port_t masterPort, char *className)
{
kern_return_t kr;
io_iterator_t ite;
io_object_t obj = 0;
kr = IORegistryCreateIterator(masterPort,
kIOServicePlane,
true,
&ite);
if (kr != kIOReturnSuccess) {
printf("IORegistryCreateIterator() error %08lx\n", (unsigned long)kr);
return 0;
}
while ((obj = IOIteratorNext(ite))) {
if (IOObjectConformsTo(obj, (char *) className)) {
printf("Found IrDA UserClient !!\n");
break;
}
else {
io_name_t name;
kern_return_t rc;
rc = IOObjectGetClass(obj, name);
if (rc == kIOReturnSuccess) {
}
}
IOObjectRelease(obj);
obj = 0;
}
IOObjectRelease(ite);
return obj;
}
kern_return_t
doCommand(io_connect_t con,
unsigned char commandID,
void *inputData, unsigned long inputDataSize,
void *outputData, size_t *outputDataSize)
{
kern_return_t err = KERN_SUCCESS;
IrDACommandPtr command = NULL;
command = (IrDACommandPtr)malloc (inputDataSize + sizeof (unsigned char));
if (!command)
return KERN_FAILURE;
command->commandID = commandID;
if ((inputData != NULL) && (inputDataSize != 0))
memcpy(command->data, inputData, inputDataSize);
err = IOConnectCallStructMethod(
con,
0,
(char *) command,
inputDataSize+sizeof(unsigned char),
(char *) outputData,
outputDataSize);
free (command);
return err;
}
#pragma mark -- Dump remote log
int
DumpRemoteLog(int argc, char ** argv)
{
struct sockaddr_in sin; UInt16 localport; Boolean ok;
int rc;
rc = sscanf(argv[2], "0x%lx", &infoaddr);
if (rc != 1) PuntErr("failed to parse info address");
printf("info address 0x%lx\n", infoaddr);
(void)time((time_t *)&key);
f = socket(AF_INET, SOCK_DGRAM, 0);
if (f < 0) PuntErr("create socket");
rc = fcntl(f, F_SETFL, O_NONBLOCK);
if (rc) PuntErr("failed to set non-blocking io");
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET; rc = bind(f, (struct sockaddr *)&sin, sizeof(sin));
if (rc) PuntErr("failed to bind to local udp port");
if (1) { sockaddr buffer;
socklen_t sz = sizeof(buffer);
rc = getsockname(f, &buffer, &sz); if (rc) PuntErr("Failed to get local udp port number");
localport = (UInt8)buffer.sa_data[0] << 8 | (UInt8)buffer.sa_data[1];
printf("Using local port number %d\n", localport);
}
ok = SetPeer(argv); if (!ok) return -1;
printf("Debugging with %s [%s]\n", hostname, inet_ntoa(peeraddr.sin_addr));
ok = DoConnect(localport);
if (!ok) Punt("Connect failed");
printf("Connected!\n");
ok = ReadLog((void *)infoaddr);
if (!ok) printf("read failed\n");
else DumpLog();
ok = DoDisconnect();
if (!ok) Punt("Disconnect failed");
close(f);
printf("Toodles!\n");
return 0;
}
Boolean
SetPeer(char **argv)
{
struct hostent *host;
host = gethostbyname(argv[1]);
if (host) {
peeraddr.sin_family = host->h_addrtype;
bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
strcpy(hostname, host->h_name);
} else {
peeraddr.sin_family = AF_INET;
peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
if (peeraddr.sin_addr.s_addr == (unsigned)-1) {
printf("%s: unknown host '%s'\n", argv[0], argv[1]);
return false;
}
strcpy(hostname, argv[1]);
}
peeraddr.sin_port = KDP_REMOTE_PORT;
return true;
}
Boolean
DoConnect(UInt16 localport)
{
kdp_connect_req_t *request = (kdp_connect_req_t *)packet;
kdp_connect_reply_t *reply = (kdp_connect_reply_t *)packet;
char *msg = "Boo";
int length;
Boolean ok;
bzero(packet, sizeof(packet));
request->req_reply_port = localport;
request->exc_note_port = localport; strcpy(request->greeting, msg); length = sizeof(kdp_connect_req_t) + strlen(msg) + 1;
ok = DoRequest(KDP_CONNECT, length); if (ok && reply->error == 0)
return true;
return false;
}
Boolean
DoRequest(kdp_req_t command, UInt32 length)
{
socklen_t fromlen;
struct sockaddr_in from;
kdp_hdr_t *hdr = (kdp_hdr_t *)packet;
ssize_t rc;
fd_set fdset;
time_t timeout;
hdr->request = command;
hdr->is_reply = 0;
hdr->seq = seq++;
hdr->len = length;
hdr->key = key;
rc = sendto(f, packet, length, 0,
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
if (rc != (ssize_t)length) return false;
FD_ZERO(&fdset);
FD_SET(f, &fdset); timeout = time(NULL) + 5; while (1) { struct timeval t;
time_t now, delta;
now = time(NULL); delta = timeout - now; if (delta <= 0) return false;
t.tv_sec = delta + 1; t.tv_usec = 0;
rc = select(f+1, &fdset, NULL, NULL, &t);
if (rc <= 0) continue; fromlen = sizeof(from);
rc = recvfrom(f, packet, sizeof(packet), 0,
(struct sockaddr *)&from, &fromlen);
if (rc > 0) {
if (hdr->request == command && hdr->is_reply && hdr->seq == (UInt8)(seq-1) && hdr->key == key) return true; }
}
return false; }
Boolean
DoDisconnect()
{
Boolean ok;
bzero(packet, sizeof(packet));
ok = DoRequest(KDP_DISCONNECT, sizeof(kdp_disconnect_req_t));
return ok; }
Boolean
ReadLog(void *addr)
{
Boolean ok;
char *local = bigbuffer;
ok = DoRead(addr, &info, sizeof(info));
if (!ok) return ok;
printf("hdr at 0x%lx, size %ld\n", (UInt32)info.hdr, info.hdrSize);
printf("log at 0x%lx, size %ld\n", (UInt32)info.eventLog, info.eventLogSize);
printf("msgs at 0x%lx, size %ld\n", (UInt32)info.msgBuffer, info.msgBufferSize);
ok = DoRead(info.hdr, local, info.hdrSize);
if (!ok) return ok;
local += info.hdrSize;
ok = DoRead(info.eventLog, local, info.eventLogSize);
if (!ok) return ok;
local += info.eventLogSize;
ok = DoRead(info.msgBuffer, local, info.msgBufferSize);
return ok;
}
Boolean
DoRead(void *remote_addr, void *local_addr, int length)
{
kdp_readmem_req_t *req = (kdp_readmem_req_t *)packet;
kdp_readmem_reply_t *reply = (kdp_readmem_reply_t *)packet;
Boolean ok;
while (length > MAX_KDP_DATA_SIZE) {
ok = DoRead(remote_addr, local_addr, MAX_KDP_DATA_SIZE);
if (!ok) return ok;
remote_addr = (UInt8 *)remote_addr + MAX_KDP_DATA_SIZE;
local_addr = (UInt8 *)local_addr + MAX_KDP_DATA_SIZE;
length -= MAX_KDP_DATA_SIZE;
}
bzero(packet, sizeof(packet));
req->address = remote_addr;
req->nbytes = length;
ok = DoRequest(KDP_READMEM, sizeof(kdp_readmem_req_t));
if (!ok) return ok;
if (reply->error != 0) {
printf("read error %d\n", reply->error);
return false;
}
bcopy(&reply->data[0], local_addr, length);
return true;
}
#pragma mark -- Common log output routines
void
DumpLog()
{
IrDALogHdr *hdr = (IrDALogHdr *)&bigbuffer[0];
IrDAEventDesc *events = (IrDAEventDescPtr)&bigbuffer[info.hdrSize];
char *msgs = (char *)&bigbuffer[info.hdrSize + info.eventLogSize];
FILE *out;
if (CheckLog(hdr)) { out = CreateLogFile();
if (out) {
OutputBuffer(hdr, events, msgs, out);
fclose(out);
}
printf("Done\n");
}
}
FILE *
CreateLogFile(void)
{
time_t now;
struct tm *lt;
char filename[100];
time(&now);
lt = localtime(&now);
sprintf(filename, "log.%d.%d.%02d%02d.%02d",
lt->tm_mon+1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
printf("Writing log to %s\n", filename);
return fopen(filename, "w");
}
Boolean CheckLog(IrDALogHdr *obj)
{
if (obj->fWrapped == false && obj->fEventIndex == obj->fPrintIndex) { printf("No new log entries\n" );
printf("gIrDALog = 0x%lx\n", (UInt32)obj);
printf("buffer = 0x%lx\n", (UInt32)obj->fEventBuffer);
printf("index = %ld\n", obj->fEventIndex);
printf("prtindex = %ld\n", obj->fPrintIndex);
printf("#entries = %ld\n", obj->fNumEntries);
printf("traceon = %d\n", obj->fTracingOn);
printf("wrapped = %d\n", obj->fWrapped);
return false;
}
return true;
}
void OutputBuffer(IrDALogHdr *obj, IrDAEventDesc *events, char *msgs, FILE *out)
{
UInt16 len;
char buffer[256];
IrDAEventDescPtr eventPtr;
Boolean oldTracingFlag;
if (obj->fWrapped == false && obj->fEventIndex == obj->fPrintIndex) { printf("No new log entries\n" );
printf("gIrDALog = 0x%lx\n", (UInt32)obj);
printf("buffer = 0x%lx\n", (UInt32)obj->fEventBuffer);
printf("index = %ld\n", obj->fEventIndex);
printf("prtindex = %ld\n", obj->fPrintIndex);
printf("#entries = %ld\n", obj->fNumEntries);
printf("traceon = %d\n", obj->fTracingOn);
printf("wrapped = %d\n", obj->fWrapped);
return;
}
oldTracingFlag = obj->fTracingOn; obj->fTracingOn = false;
if (obj->fWrapped) { obj->fPrintIndex = obj->fEventIndex; }
if( obj->fPrintIndex >= obj->fNumEntries ) obj->fPrintIndex = 0;
do{
UInt32 secs, usecs; static UInt32 lasttime = 0;
SInt32 deltaTime;
char *msg;
eventPtr = &obj->fEventBuffer[obj->fPrintIndex];
eventPtr = (eventPtr - info.eventLog) + events; msg = (eventPtr->msg - info.msgBuffer) + msgs;
if (eventPtr->timeStamp) { secs = eventPtr->timeStamp / 1000000;
usecs = eventPtr->timeStamp % 1000000;
deltaTime = eventPtr->timeStamp - lasttime;
lasttime = eventPtr->timeStamp;
if (deltaTime > 999999 || deltaTime < 0) deltaTime = 999999;
len = sprintf( buffer, "%4ld.%06ld [%6ld] D: %04hx,%04hx %s",
secs, usecs,
deltaTime,
eventPtr->data1,
eventPtr->data2,
msg );
}
else len = sprintf( buffer, " x.x [ ] D: %04hx,%04hx %s",
eventPtr->data1,
eventPtr->data2,
msg );
fprintf(out, buffer );
fprintf(out, "\n");
obj->fPrintIndex++;
if( obj->fPrintIndex >= obj->fNumEntries ) obj->fPrintIndex = 0;
} while((obj->fPrintIndex != obj->fEventIndex) );
obj->fPrintIndex = obj->fEventIndex; obj->fWrapped = false; obj->fTracingOn = oldTracingFlag; }