Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
emulab
emulab-devel
Commits
42bfa924
Commit
42bfa924
authored
Mar 11, 2006
by
David Johnson
Browse files
Most of the rest of the app code for logging packets. Still have to write
a bit more, then hack it into the testbed.
parent
c94fe76c
Changes
4
Hide whitespace changes
Inline
Side-by-side
mote/motelog/LogPacket.java
View file @
42bfa924
import
java.util.*
;
//
import net.tinyos.message.Message;
import
net.tinyos.message.Message
;
public
class
LogPacket
{
...
...
@@ -8,9 +8,12 @@ public class LogPacket {
private
byte
[]
data
;
private
int
packetType
;
private
int
crc
;
//private Message msg;
private
Object
msg
;
private
String
srcVnodeName
;
public
LogPacket
(
Date
time
,
byte
[]
data
,
int
packetType
,
int
crc
)
{
public
LogPacket
(
String
srcVnodeName
,
Date
time
,
byte
[]
data
,
int
packetType
,
int
crc
)
{
this
.
srcVnodeName
=
srcVnodeName
;
this
.
timeStamp
=
time
;
this
.
data
=
data
;
this
.
packetType
=
packetType
;
...
...
@@ -34,4 +37,16 @@ public class LogPacket {
return
this
.
crc
;
}
public
String
getSrcVnodeName
()
{
return
this
.
srcVnodeName
;
}
public
void
setMsgObject
(
Object
obj
)
{
this
.
msg
=
obj
;
}
public
Object
getMsgObject
()
{
return
this
.
msg
;
}
}
mote/motelog/MoteLogger.java
View file @
42bfa924
...
...
@@ -9,6 +9,7 @@ public class MoteLogger {
private
int
debug
;
private
File
classDir
;
private
String
[]
classNames
;
private
File
aclDir
;
private
String
logTag
;
private
String
pid
;
...
...
@@ -18,6 +19,7 @@ public class MoteLogger {
private
String
dbURL
=
"jdbc.DriverMysql"
;
private
String
dbUser
=
"root"
;
private
String
dbPass
=
""
;
private
Hashtable
classes
;
public
static
void
main
(
String
args
[])
{
//
...
...
@@ -35,6 +37,7 @@ public class MoteLogger {
public
static
void
parseArgsAndRun
(
String
args
[])
{
File
classDir
=
null
;
String
[]
classNames
=
null
;
String
tag
=
null
;
String
pid
=
null
;
String
eid
=
null
;
...
...
@@ -44,12 +47,21 @@ public class MoteLogger {
int
i
;
for
(
i
=
0
;
i
<
args
.
length
;
++
i
)
{
if
(
args
[
i
].
equals
(
"-
c
"
))
{
if
(
args
[
i
].
equals
(
"-
C
"
))
{
if
(++
i
<
args
.
length
&&
!
args
[
i
].
startsWith
(
"-"
))
{
classDir
=
new
File
(
args
[
i
]);
}
else
{
System
.
err
.
println
(
"option '-c' must have an argument!"
);
System
.
err
.
println
(
"option '-C' must have an argument!"
);
usage
();
}
}
else
if
(
args
[
i
].
equals
(
"-c"
))
{
if
(++
i
<
args
.
length
&&
!
args
[
i
].
startsWith
(
"-"
))
{
classNames
=
args
[
i
].
split
(
","
);
}
else
{
System
.
err
.
println
(
"option -c must have an argument!"
);
usage
();
}
}
...
...
@@ -113,7 +125,7 @@ public class MoteLogger {
//this.motes = motes;
// startup
MoteLogger
ml
=
new
MoteLogger
(
classDir
,
aclDir
,
motes
,
MoteLogger
ml
=
new
MoteLogger
(
classDir
,
classNames
,
aclDir
,
motes
,
pid
,
eid
,
tag
,
debug
);
ml
.
run
();
}
...
...
@@ -122,8 +134,10 @@ public class MoteLogger {
String
usage
=
""
+
"Usage: java MoteLogger -cipMd \n"
+
"Options:\n"
+
"\t-
c
<classdir> Directory containing packet-matching "
+
"\t-
C
<classdir> Directory containing packet-matching "
+
"classfiles \n"
+
"\t-c <classfile list> Comma-separated list of fully-qualified "
+
"classnames. \n"
+
"\t-i <idtag> Alphanumeric tag for this logging set \n"
+
"\t-p pid,eid \n"
+
//"\t-m <vname,vname,...> (list of vnames present in acl dir) \n"+
...
...
@@ -135,15 +149,18 @@ public class MoteLogger {
System
.
exit
(-
1
);
}
public
MoteLogger
(
File
classDir
,
File
aclDir
,
String
[]
motes
,
String
pid
,
public
MoteLogger
(
File
classDir
,
String
[]
classNames
,
File
aclDir
,
String
[]
motes
,
String
pid
,
String
eid
,
String
tag
,
int
debug
)
{
this
.
classDir
=
classDir
;
this
.
classNames
=
classNames
;
this
.
aclDir
=
aclDir
;
this
.
pid
=
pid
;
this
.
eid
=
eid
;
this
.
logTag
=
tag
;
this
.
debug
=
debug
;
this
.
motes
=
motes
;
this
.
classes
=
new
Hashtable
();
}
// I know, not a thread, but who cares
...
...
@@ -177,6 +194,55 @@ public class MoteLogger {
System
.
exit
(
0
);
}
// load classfiles and create Class objs so we can do instance objs
// on incoming packet data
// first, have to discover the classfiles, if they weren't specified.
if
(
this
.
classNames
==
null
||
classNames
.
length
==
0
)
{
// try to read the classFile directory and use the XXX.class
// names as the classes -- will fail if classes are in package.
File
[]
classFiles
=
classDir
.
listFiles
(
new
FilenameFilter
()
{
public
boolean
accept
(
File
dir
,
String
name
)
{
if
(
name
!=
null
&&
name
.
endsWith
(
".class"
))
{
return
true
;
}
else
{
return
false
;
}
}
});
if
(
classFiles
!=
null
)
{
this
.
classNames
=
new
String
[
classFiles
.
length
];
for
(
int
i
=
0
;
i
<
classFiles
.
length
;
++
i
)
{
String
[]
sa
=
classFiles
[
i
].
getName
().
split
(
"\\.class"
);
this
.
classNames
[
i
]
=
sa
[
0
];
}
}
}
if
(
classFiles
==
null
||
classFiles
.
length
==
0
)
{
System
.
out
.
println
(
"Could not find any classfiles; exiting."
);
System
.
exit
(
0
);
}
// second, actually load them.
for
(
int
i
=
0
;
i
<
classNames
.
length
;
++
i
)
{
try
{
Class
c
=
Class
.
forName
(
classNames
[
i
]);
// this call does the class.forName, redundant i know.
classes
.
put
(
c
,
new
SQLGenerator
(
classNames
[
i
],
null
,
this
.
logTag
));
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"Problem loading class "
+
classNames
[
i
]
+
":"
);
e
.
printStackTrace
();
}
}
// get capture keys
Hashtable
acls
=
new
Hashtable
();
for
(
int
i
=
0
;
i
<
motes
.
length
;
++
i
)
{
...
...
@@ -194,22 +260,114 @@ public class MoteLogger {
packetQueue
=
new
SynchQueue
();
// connect to the database
;
Connection
conn
=
null
;
try
{
Class
.
forName
(
"com.mysql.jdbc.Driver"
);
conn
=
DriverManager
.
getConnection
(
"jdbc:mysql:"
+
"//localhost/test?user=root"
);
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"FATAL -- couldn't connect to the database: "
+
e
.
getMessage
());
e
.
printStackTrace
();
System
.
exit
(-
2
);
}
// spawn connection threads
for
(
Enumeration
e1
=
acls
.
keys
();
e1
.
hasMoreElements
();
)
{
String
vNN
=
(
String
)
e1
.
nextElement
();
ElabACL
acl
=
(
ElabACL
)
acls
.
get
(
vNN
);
(
new
Mote
Log
Thread
(
acl
,
packetQueue
)).
start
();
(
new
MoteThread
(
acl
,
packetQueue
)).
start
();
}
// now, process the packet queue forever.
while
(
true
)
{
LogPacket
lp
=
null
;
synchronized
(
packetQueue
)
{
while
(
packetQueue
.
peek
()
==
null
)
{
try
{
packetQueue
.
wait
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
// once we get a packet...
lp
=
packetQueue
.
queueRemove
();
}
// dump it out to database:
// this is the real work:
try
{
// first match the packet:
SQLGenerator
sq
=
null
;
boolean
foundMatch
=
false
;
for
(
Enumeration
e1
=
classes
.
keys
();
!
foundMatch
&&
e1
.
hasMoreElements
();
)
{
Class
cc
=
(
Class
)
e1
.
nextElement
();
sq
=
(
SQLGenerator
)
classes
.
get
(
cc
);
// Need to create a BaseTOSMsg
// and extract the 'type' field... which is the am type
// ... and then match this with the amType() method of the
// invoked class.
// XXX: note that this must be changed depending on the
// architecture of the motes we're connecting to, in order
// to decode using the correct host byte order assumption.
// i.e., net.tinyos.message.telos.*
//
if
(
true
)
{
net
.
tinyos
.
message
.
avrmote
.
BaseTOSMsg
btm
=
new
net
.
tinyos
.
message
.
avrmote
.
BaseTOSMsg
(
lp
.
getData
());
if
(
lp
.
amType
()
==
sq
.
getAMType
())
{
// class match
// invoke the byte[] data constructor on the data
// from the basetosmsg:
Constructor
ccc
=
cc
.
getConstructor
(
new
Class
[]
{
byte
[].
class
}
);
Object
msgObj
=
ccc
.
newInstance
(
new
Object
[]
{
btm
.
get_data
()
}
);
lp
.
setMsgObject
(
msgObj
);
// ready to log!!!
foundMatch
=
true
;
}
}
}
// do the db insert:
sq
.
storeMessage
(
msgObj
,
conn
);
// that's all, folks!
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"Error while logging packet: "
);
e
.
printStackTrace
();
}
}
}
class
MoteLogThread
extends
Thread
{
class
MoteThread
extends
Thread
{
private
String
vNodeName
;
private
ElabACL
acl
;
private
SynchQueue
q
;
private
Socket
sock
;
public
MoteLogThread
(
ElabACL
acl
,
SynchQueue
packetQueue
)
{
public
MoteLogThread
(
String
vNodeName
,
ElabACL
acl
,
SynchQueue
packetQueue
)
{
this
.
vNodeName
=
vNodeName
;
this
.
acl
=
acl
;
this
.
q
=
packetQueue
;
}
...
...
@@ -313,7 +471,7 @@ public class MoteLogger {
PacketReader
pr
=
null
;
try
{
pr
=
new
PacketReader
(
sock
.
getInputStream
());
pr
=
new
PacketReader
(
vNodeName
,
sock
.
getInputStream
());
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
...
...
@@ -324,6 +482,11 @@ public class MoteLogger {
lp
=
null
;
try
{
lp
=
pr
.
readPacket
();
synchronized
(
packetQueue
)
{
packetQueue
.
queueAdd
(
lp
);
packetQueue
.
notifyAll
();
}
}
catch
(
Exception
e
)
{
System
.
err
.
println
(
"Problem while reading from "
+
...
...
mote/motelog/PacketReader.java
View file @
42bfa924
...
...
@@ -64,8 +64,10 @@ public final class PacketReader {
final
static
int
P_UNKNOWN
=
255
;
private
InputStream
in
;
private
String
vNodeName
;
public
PacketReader
(
InputStream
in
)
{
public
PacketReader
(
String
vNodeName
,
InputStream
in
)
{
this
.
vNodeName
=
vNodeName
;
this
.
in
=
in
;
}
...
...
@@ -148,13 +150,13 @@ public final class PacketReader {
retval
=
new
byte
[
buf
.
length
-
3
];
System
.
arraycopy
(
buf
,
1
,
retval
,
0
,
retval
.
length
);
return
new
LogPacket
(
t
,
retval
,
packetType
,
crc
);
return
new
LogPacket
(
vNodeName
,
t
,
retval
,
packetType
,
crc
);
}
else
if
(
buf
[
0
]
==
P_PACKET_ACK
)
{
retval
=
new
byte
[
buf
.
length
-
4
];
System
.
arraycopy
(
buf
,
2
,
retval
,
0
,
retval
.
length
);
return
new
LogPacket
(
t
,
retval
,
packetType
,
crc
);
return
new
LogPacket
(
vNodeName
,
t
,
retval
,
packetType
,
crc
);
}
else
if
(
buf
[
0
]
==
P_ACK
||
buf
[
0
]
==
P_UNKNOWN
)
{
// do nothing for now; this is only sent by receiver on
...
...
@@ -165,7 +167,7 @@ public final class PacketReader {
// XXX: might want to log these in the future...
}
return
l
p
;
return
nul
l
;
}
}
...
...
mote/motelog/SQLGenerator.java
0 → 100644
View file @
42bfa924
import
net.tinyos.message.*
;
import
java.sql.*
;
import
java.util.*
;
import
java.lang.reflect.*
;
public
class
SQLGenerator
{
//private Message m;
// every message should have these fields...
private
Method
[]
tosMsgFields
;
// for now, even structures will be completely flattened out
private
Method
[]
simpleFields
;
// arrays are the only thing we will distinguish...
// and heaven help us if there's a multidimensional one!
// there could be more than one, hence the hash
// keys:
//private Hashtable arrayFields;
private
Method
[]
arrayFields
;
// table creation statements
private
String
[]
tableCreates
;
// view creates... reduces number of tables and data dup.
private
String
[]
viewCreates
;
// data insert preparedStatement strings
private
String
[]
inserts
;
// first dimension i is how to perform inserts[i];
// each element in the arrayList is a String[] with the following data:
// [ getMethodName, returnType, SQLType ]
private
ArrayList
[]
insertInfo
;
private
String
className
;
private
String
msgSpec
;
private
String
tag
;
private
int
amType
;
private
boolean
tablesCreated
;
public
SQLGenerator
(
String
name
,
String
[]
spec
,
String
tag
)
throws
ClassNotFoundException
,
Exception
{
// need to parse the methods via reflection:
this
.
className
=
name
;
this
.
msgSpec
=
spec
;
this
.
tag
=
tag
;
Class
c
=
Class
.
forName
(
className
);
// grab the am type first!
Object
msgObj
=
c
.
newInstance
();
Method
am
=
c
.
getMethod
(
"amType"
,
null
);
Integer
amt
=
(
Integer
)
am
.
invoke
(
msgObj
,
null
);
this
.
amType
=
amt
.
intValue
();
// now figure out the methods. Basically, we figure out which
// get_* methods correspond to which arrays by finding the longest
// common substring following the get_ part of the string.
Methods
[]
m
=
c
.
getMethods
();
Vector
flatFieldMethods
=
new
Vector
();
Vector
arrayFieldMethods
=
new
Vector
();
for
(
int
i
=
0
;
i
<
m
.
length
;
++
i
)
{
String
ms
=
m
[
i
].
getName
();
String
rts
=
m
[
i
].
getReturnType
().
getName
();
if
(
ms
.
startsWith
(
"get_"
))
{
if
(
rts
.
startsWith
(
"[["
))
{
// MULTIDIMENSIONAL ARRAYS NOT SUPPORTED YET
throw
new
Exception
(
"multidimensional arrays unsupported"
);
}
else
if
(
rts
.
startsWith
(
"["
))
{
arrayFieldMethods
.
add
(
m
[
i
]);
}
else
{
flatFieldMethods
.
add
(
m
[
i
]);
}
}
}
simpleFields
=
new
Method
[
flatFieldMethods
.
size
()];
arrayFields
=
new
Method
[
arrayFieldMethods
.
size
()];
int
elm
=
0
;
for
(
Enumeration
e1
=
flatFieldMethods
.
elements
();
e1
.
hasMoreElements
();
)
{
simpleFields
[
elm
++]
=
(
Method
)
e1
.
nextElement
();
}
elm
=
0
;
for
(
Enumeration
e1
=
arrayFieldMethods
.
elements
();
e1
.
hasMoreElements
();
)
{
arrayFields
[
elm
++]
=
(
Method
)
e1
.
nextElement
();
}
// so for now, we're just going to have to accept the reality of
// flattened everything. The best we can do is create the main table,
// with blobs for array data, and a secondary table, in which we change
// the blobs to string representation of the array.
// not true -- by asking for a bit more MIG output, we can do
// infinitely better -- because the whole type definition is right
// there, along with variable names. Just have to read the MIG src,
// write a parser... then generate much, much more complex sql.
// for now, just a few tables -- a main data table,
// then several tables for array info.
if
(
spec
!=
null
)
{
// do the complex stuff...
;
}
else
{
// simple, one-table layout with two views.
int
numTables
=
1
+
arrayFields
.
length
;
int
tableIndex
=
1
;
tableCreates
=
new
String
[
numTables
];
inserts
=
new
String
[
numTables
];
insertInfo
=
new
ArrayList
[
numTables
];
viewCreates
=
new
String
[
1
];
// main table
String
tableName
=
className
+
"__data_"
+
tag
;
parentTableName
=
tableName
;
tableCreates
[
0
]
=
""
+
"CREATE TABLE "
+
tableName
+
" "
+
"("
+
"id INT PRIMARY KEY AUTO_INCREMENT, "
+
"time DATETIME, "
+
"amType INT, "
+
"srcMote VARCHAR(32)"
;
inserts
[
0
]
=
"insert into "
+
tableName
+
" values (NULL,?,"
+
this
.
amType
+
",?"
;
insertInfo
[
0
]
=
new
ArrayList
();
insertInfo
[
0
].
add
(
new
String
[]
{
"date"
,
null
,
null
}
);
// now get this statically.
//insertInfo[0].add( new String[] { "amType","I","INT" } );
insertInfo
[
0
].
add
(
new
String
[]
{
"srcMote"
,
null
,
null
}
);
// now the msg-specific stuff:
// we do this again here because we'd prefer the correct order...
Method
ma
[]
=
c
.
getMethods
();
for
(
int
i
=
0
;
i
<
ma
.
length
;
++
i
)
{
String
mn
=
ma
[
i
].
getName
();
if
(
mn
.
startsWith
(
"get_"
))
{
String
mnSansGet
=
mn
.
subString
(
4
,
mnSansGet
.
length
());
Method
signMethod
=
null
;
try
{
signMethod
=
c
.
getMethod
(
"isSigned_"
+
mnSansGet
);
}
catch
(
Exception
e
)
{
// no big deal
;
}
boolean
isArr
=
false
;
String
internalArraySQLType
=
""
;
if
(
ma
[
i
].
getReturnType
().
getName
().
startsWith
(
"["
))
{
isArr
=
true
;
internalArraySQLType
=
getSQLTypeStr
(
ma
[
i
],
signMethod
,
true
);
}
if
(!
isArr
)
{
tableCreates
[
0
]
+=
", "
+
mnSansGet
+
" "
+
getSQLTypeStr
(
ma
[
i
],
signMethod
,
false
);
// add to the insert & insertInfo
inserts
[
0
]
+=
",?"
;
insertInfo
[
0
].
add
(
new
String
[]
{
ma
[
i
].
getName
(),
ma
[
i
].
getReturnType
().
getName
(),
getSQLTypeStr
(
ma
[
i
],
signMethod
,
false
)
}
);
}
else
{
// now, IF we have an array, we create a separate
// table. we only do this for arrays! We let the
// structs get flattened out for now; we solve the
// hierarchy problem as best we can via views.
// we add the table now:
String
aTableName
=
mnSansGet
+
"__data_"
+
tag
;
tableCreates
[
tableIdx
]
=
""
+
"CREATE TABLE "
+
aTableName
+
" ("
+
"ppid INT PRIMARY KEY NOT NULL, "
+
"idx INT NOT NULL, "
+
""
+
mnSansGet
+
" "
+
internalArraySQLType
+
")"
;
inserts
[
tableIdx
]
=
""
+
"insert into "
+
aTableName
+
"values ("
+
"?,?,?)"
;
insertInfo
[
tableIdx
]
=
new
ArrayList
();
// [ getMethodName, returnType, SQLType ]
insertInfo
[
tableIdx
].
add
(
new
String
[]
{
"ppid"
,
null
,
null
}
);
insertInfo
[
tableIdx
].
add
(
new
String
[]
{
"idx"
,
null
,
null
}
);
insertInfo
[
tableIdx
].
add
(
new
String
[]
{
ma
[
i
].
getName
(),
ma
[
i
].
getReturnType
().
getName
(),
internalArraySQLType
}
);
++
tableIdx
;
// also add the field as a blob column, just in case
tableCreates
[
0
]
+=
", "
+
mnSansGet
+
" "
+
getSQLTypeStr
(
ma
[
i
],
signMethod
,
false
);
;
}
}
}
// finish off the table create and insert:
tableCreates
[
0
]
+=
")"
;
inserts
[
0
]
+=
")"
;
}
tablesCreated
=
false
;
}
public
String
[]
getTableCreates
()
{
return
tableCreates
;
}
public
String
[]
getViewCreates
()
{
return
viewCreates
;
}
//
public
boolean
storeMessage
(
LogPacket
lp
,
Connection
conn
)
throws
SQLException
{
// check if the tables are there; if not, create them.
if
(!
tablesCreated
)
{
try
{
Statement
s
=
conn
.
createStatement
();
for
(
int
i
=
0
;
i
<
tableCreates
.
length
;
++
i
)
{
s
.
execute
(
tableCreates
[
i
]);
}
tablesCreated
=
true
;
}
catch
(
SQLException
e
)
{
System
.
err
.
println
(
"Problem while creating tables for "
+
this
.
className
+
"!"
);
e
.
printStackTrace
();
}
}
// run the inserts:
int
errors
=
0
;