Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
emulab-devel
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
143
Issues
143
List
Boards
Labels
Service Desk
Milestones
Merge Requests
6
Merge Requests
6
Operations
Operations
Incidents
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
emulab
emulab-devel
Commits
42bfa924
Commit
42bfa924
authored
Mar 11, 2006
by
David Johnson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
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
Showing
4 changed files
with
641 additions
and
17 deletions
+641
-17
mote/motelog/LogPacket.java
mote/motelog/LogPacket.java
+18
-3
mote/motelog/MoteLogger.java
mote/motelog/MoteLogger.java
+173
-10
mote/motelog/PacketReader.java
mote/motelog/PacketReader.java
+6
-4
mote/motelog/SQLGenerator.java
mote/motelog/SQLGenerator.java
+444
-0
No files found.
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
lp
;
return
null
;
}
}
...
...
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
;
for
(
int
i
=
0
;
i
<
inserts
.
length
;
++
i
)
{
ArrayList
aInfo
=
insertInfo
[
i
];
// setup the prepared stmt:
try
{
PreparedStatement
ps
=
conn
.
prepareStatement
(
inserts
[
i
]);
int
ppid
=
-
1
;
for
(
int
j
=
0
;
j
<
aInfo
.
length
();
++
j
)
{
String
[]
info
=
(
String
[])
aInfo
.
get
(
j
);
// now perform the ps.set op...
if
(
info
[
0
].
equals
(
"date"
))
{
// insert the date manually
// note that we use j+1 since preparedStatement vars
// start at index 1
ps
.
setDate
(
j
+
1
,
lp
.
getDate
());
}
else
if
(
info
[
0
].
equals
(
"srcMote"
))
{
ps
.
setString
(
j
+
1
,
lp
.
getSrcMote
());
}
else
if
(
info
[
0
].
equals
(
"ppid"
))
{
ps
.
setInt
(
j
+
1
,
ppid
);
}