Net::OBEX - implementation of OBEX protocol
use strict;
use warnings;
use Net::OBEX;
my $obex = Net::OBEX->new;
$obex->connect(
address => '00:17:E3:37:76:BB',
port => 9,
target => 'F9EC7BC4953C11D2984E525400DC9E09', # OBEX FTP UUID
) or die "Failed to connect: " . $obex->error;
$obex->success
or die "Server no liky :( " . $obex->status;
$obex->set_path
or die "Error: " . $obex->error;
$obex->success
die "Server no liky :( " . $obex->status;
# this is an OBEX FTP example, so we'll get the folder listing now
my $response_ref = $obex->get( type => 'x-obex/folder-listing' )
or die "Error: " . $obex->error;
$obex->success
or die "Server no liky :( " . $obes->status;
print "This is folder listing XML: \n$response_ref->{body}\n";
# send Disconnect packet with description header and close the socket
$obex->close('No want you no moar');
WARNING!!! This module is still in its early alpha stage, it is recommended that you use it only for testing. A lot of functionality is still not implemented.
The module is a Perl implementation of IrOBEX protocol.
my $obex = Net::OBEX->new;
Takes no arguments, returns a freshly baked Net::OBEX object ready to use and abuse.
$obex->success
or die 'Error: (code: ' . $obex->code . ') ' . $obex->status;
Must be called after either connect()
, set_path()
, get()
or
put()
method. Returns either true or false value indicating whether
or not the call to last connect()
, set_path()
, get()
or
put()
method ended with a successful response from the server
(code 200). Note: the aforementioned methods returning a non-error
(see descriptions below) does NOT imply that success()
will return
a true value.
$obex->success
or die 'Error: (code: ' . $obex->code . ') ' . $obex->status;
Must be called after either connect()
, set_path()
, get()
or
put()
method. Returns the status code of the last response from the
server.
$obex->success
or die 'Error: (code: ' . $obex->code . ') ' . $obex->status;
Must be called after either connect()
, set_path()
, get()
or
put()
method. Returns the status code description
of the last response from the server (i.e. "Ok, Success" if code()
is 200
)
my $response_ref = $obex->connect(
address => '00:17:E3:37:76:BB',
port => 9,
) or die "Failed to connect: " . $obex->error;
$obex->connect(
address => '00:17:E3:37:76:BB',
port => 9,
version => "\x10",
mtu => 4096,
domain => 'bluetooth',
type => 'stream',
proto => 'rfcomm',
headers => [ $some, $raw, $headers ],
) or die "Failed to connect: " . $obex->error;
Creates a new socket and connects it. Takes a bunch of arguments, two
of which (address
and port
) are mandatory. Net::OBEX uses
Socket::Class as its "horse" but it might be possible to use
a different socket if you want to (see sock()
method). Returns a hashref
which is described below after arguments. Possible arguments are as follows:
->connect( address => '00:17:E3:37:76:BB', ...
Mandatory. Specifies the MAC address of the device to connect to.
->connect( port => 9, ...
Mandatory. Specifies the port of the device to connect to.
->connect( version => "\x10", ...
Optional. Specifies the OBEX protocol version to use, takes a "version"
byte to use in the Connect packet encoded with the major number in the high
order 4 bits, and the minor version in the low order 4 bits. Generally
speaking you won't have to touch this one. Defaults to: 0x10
(version 1.0)
->connect( mtu => 4096, ...
Optional. Specifies the MTU of your device, i.e. the maximum length
of the packet in bytes it can accept. Defaults to: 4096
->connect( domain => 'bluetooth', ...
Optional. Specifies the domain
argument to pass to Socket::Class
constructor. See documentation for Socket::Class for more information.
Defaults to: bluetooth
->connect( type => 'stream', ...
Optional. Specifies the type
argument to pass to Socket::Class
constructor. See documentation for Socket::Class for more information.
Defaults to: stream
->connect( proto => 'rfcomm', ...
Optional. Specifies the proto
argument to pass to Socket::Class
constructor. See documentation for Socket::Class for more information.
Defaults to: rfcomm
->connect( headers => [ $some, $raw, $headers ], ...
Optional. If you want to pass along some additional packet headers
to the Connect packet you can use the headers
argument which takes
an arrayref elements of which are OBEX packet headers. See
Net::OBEX::Packet::Headers for information on how to make them.
Defaults to: []
(no headers)
->connect( target => 'F9EC7BC4953C11D2984E525400DC9E09', ....
Optional. Since it's common that you will need a Target
header
in the Connect packet you can use the target
argument instead of
manually creating the header. Note: the module will automatically
pack()
what you specify in the target
argument, so you can just use
the UUID (without dashes). By default no target
is specified.
$VAR1 = {
'info' => {
'flags' => '00000000',
'packet_length' => 31,
'obex_version' => '00010000',
'response_code' => 200,
'headers_length' => 24,
'response_code_meaning' => 'OK, Success',
'mtu' => 5126
},
'headers' => {
'connection_id' => '�',
'who' => '��{ĕ<�ҘNRTܞ '
},
'raw_packet' => '�����J���{ĕ<�ҘNRTܞ ��'
};
If an error occurred during the request, connect()
will return either
undef
or an empty list, depending on the context and the reason
for the error will be available via error()
method. Otherwise it will
return a hashref presented above. If the
dump above is not self explanatory see Net::OBEX::Response
parse_sock()
method description for the return value when
"is connect packet" option is true.
If the Connection ID
header is present in the Connect response packet
the module will save it and automatically include it in any other
packet as the first header as per specification.
The raw generated Connection ID
header which will be included in all other
packets is accessible via connection_id()
accessor/mutator. If you
want to override the automatic inclusion of the header in all packets
set connection_id('')
after the call to connect()
but generally this
is a BadIdea(tm) and you probably will get a 403 on all the requests.
my $response_ref = $obex->disconnect
or die "Error: " . $obex->error;
my $response_ref = $obex->disconnect(
description => 'die in a fire!',
headers => [ $some, $other, $raw, $headers ],
) or die "Error: " . $obex->error;
Instructs the object to send a Disconnect packet without closing the socket
(whether it will actually stay open is another matter). If you want
to close the socket as well, you probably would want to use the
close()
method instead. Takes two optional arguments:
$obex->disconnect( description => 'die in a fire!' );
Optional. Takes a scalar as an argument which will be passed in the
Description
header in the Disconnect packet. By default no
description is supplied.
$obex->disconnect( headers => [ $some, $raw, $headers ] );
Optional. If you want to pass along some additional packet headers
to the Disconnect packet you can use the headers
argument which takes
an arrayref elements of which are OBEX packet headers. See
Net::OBEX::Packet::Headers for information on how to make them.
Defaults to: []
(no headers)
$VAR1 = {
'info' => {
'packet_length' => 3,
'response_code' => 200,
'headers_length' => 0,
'response_code_meaning' => 'OK, Success'
},
'raw_packet' => '��'
};
If an error occurred during the request, disconnect()
will return either
undef
or an empty list, depending on the context and the reason
for the error will be available via error()
method. Otherwise it will
return a hashref presented above. If the
dump above is not self explanatory see Net::OBEX::Response
parse_sock()
method description for the return value when
"is connect packet" option is false.
my $response_ref = $obex->set_path
or die "Error: " . $obex->error;
my $response_ref = $obex->set_path(
path => 'there_somewhere',
headers => [ $bunch, $of, $raw, $headers ],
) or die "Error: " . $obex->error;
Instructs the object to send a SetPath
packet. Takes four optional
arguments which are as follows:
$obex->set_path( path => 'there_somewhere' );
Optional. Whatever you specify in the path
argument will be sent
out in the packet's Name
header, which is the path to change to.
By default no path is set, meaning set path to "root folder".
$obex->set_path( do_up => 1 );
Optional. Takes either true or false value, indicating whether or
not to set the "backup a level before applying name" flag in the SetPath
packet. Defaults to: 0
$obex->set_path( no_create => 0 );
Optional. Takes either true or false value, indicating whether or not
to set the "don't create directory if it does not exist, return an
error instead." flag in the SetPath packet. Defaults to: 1
$obex->set_path( headers => [ $some, $raw, $headers ] );
Optional. If you want to pass along some additional packet headers
to the SetPath packet you can use the headers
argument which takes
an arrayref elements of which are OBEX packet headers. See
Net::OBEX::Packet::Headers for information on how to make them.
Defaults to: []
(no headers)
$VAR1 = {
'info' => {
'packet_length' => 3,
'response_code' => 200,
'headers_length' => 0,
'response_code_meaning' => 'OK, Success'
},
'raw_packet' => '��'
};
If an error occurred during the request, set_path()
will return either
undef
or an empty list, depending on the context and the reason
for the error will be available via error()
method. Otherwise it will
return a hashref presented above. If the
dump above is not self explanatory see Net::OBEX::Response
parse_sock()
method description for the return value when
"is connect packet" option is false.
$response_ref = $obex->get
or die "Error: " . $obex->error;
$response_ref = $obex->get(
is_final => 1,
headers => [ $bunch, $of, $raw, $headers ],
type => 'x-obex/folder-listing',
name => 'some_file',
no_continue => 1,
file => $fh,
) or die "Error: " . $obex->error;
Instructs the object to send an OBEX Get packet and any number of Get (Continue) packets needed to finish the request (by default). Takes several arguments, all of which are optional. The possible arguments are as follows:
$obex->get( is_final => 1 );
Optional. When set to a true value will instruct the object to set the
high bit of the Get packet on. When set to a false value will set the high
bit off. Defaults to: 1
$obex->get( headers => [ $some, $raw, $headers ] );
Optional. If you want to pass along some additional packet headers
to the Get packet you can use the headers
argument which takes
an arrayref elements of which are OBEX packet headers. See
Net::OBEX::Packet::Headers for information on how to make them.
Defaults to: []
(no headers)
$obex->get( type => 'x-obex/folder-listing' );
Optional. Takes a scalar as value, whatever you specify will be
packed up into a OBEX Type
header and shipped along with your Get packet.
By default type
is not specified.
$obex->get( name => 'some_file' );
Optional. Takes a scalar as value, whatever you specify will be
packed up into a OBEX Name
header and shipped along with your Get packet.
By default name
is not specified.
$obex->get( no_continue => 1 );
Optional. By default the get()
method will automatically send out
any Get (Continue) packets to get the entire data. However, if that's not
what you want set the no_continue
to a true value. When set to a false
value will automatically send as many Get (Continue) packets as needed
to get the entire thing, when set to a true value will send only one
Get packet leaving the rest up to you. Defaults to: 0
$obex->get( file => $file_handle );
Optional. If you are retrieving large quantities of data it is probably
not a good idea to stuff all of it into a hashref. The file
argument
takes an open file handle, and when specified will write the data into
that file instead of storing it in the return hashref. By default
fetched data will be returned in the return hashref.
$VAR1 = {
'body' => '<?xml version="1.0" ?>
<!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd">
<folder-listing>
<parent-folder />
<folder name="audio" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="video" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="picture" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
</folder-listing>
',
'responses' => [
{
'info' => {
'packet_length' => 6,
'response_code' => 100,
'headers_length' => 3,
'response_code_meaning' => 'Continue'
},
'headers' => {
'body' => ''
},
'raw_packet' => '��H�'
},
{
'info' => {
'packet_length' => 413,
'response_code' => 100,
'headers_length' => 410,
'response_code_meaning' => 'Continue'
},
'headers' => {
'body' => '<?xml version="1.0" ?>
<!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd">
<folder-listing>
<parent-folder />
<folder name="audio" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="video" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="picture" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
</folder-listing>
'
},
'raw_packet' => '���H��<?xml version="1.0" ?>
<!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd">
<folder-listing>
<parent-folder />
<folder name="audio" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="video" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
<folder name="picture" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
</folder-listing>
'
},
{
'info' => {
'packet_length' => 6,
'response_code' => 200,
'headers_length' => 3,
'response_code_meaning' => 'OK, Success'
},
'headers' => {
'end_of_body' => ''
},
'raw_packet' => '��I�'
}
],
'response_code' => 100,
'response_code_meaning' => 'Continue'
};
The get()
method returns either undef
or an empty list (depending
on the context) if an error
occurred and the explanation of the error will by available via error()
method. Otherwise it returns a big hashref. As opposed to connect()
,
disconnect()
and set_path()
method
the returned hashref from get()
method is a bit different because
it can send (by default) several Get requests to fetch entire data. The
keys/values of the return are as follows:
The key will contain the entire data that was retrieved (if
no_continue
is false) or the contents of the Body
header of the
packet (if no_continue
is set to a true value). If file
argument
is set, the body
key will be empty.
The response_code
key will contain the response code of the first
received packet, note that if the request requires several Get packets
to be sent out, the response code will be 100
(Continue) not 200.
The response_code_meaning
key will contain the meaning of the response
code of the first received packet.
The responses
key will contain an arrayref elements of which will be
the return values of parse_sock()
method from Net::OBEX::Headers
module. There will be as many elements as many Get packets were sent out
to retrieve entire data; of course, there will be only one if no_continue
argument to get()
is set to a true value. For more information, see
parse_sock()
method in Net::OBEX::Headers with the "is connect packet"
flag set to false. If file
argument is set, responses
arrayref
will be empty.
$obex->put( what => 'some_file' )
or die $obex->error;
my $response_ref = $obex->put(
what => 'some_file',
body_in_first => 0,
length => 12312,
no_name => 1,
name => 'other_file',
time => '20080320T202020Z',
) or die $obex->error;
Instructs the object to send PUT
packet. As of now only sending
of files is supported and due to the limited testing environment this
support may be broken. During my tests (with Motorolla KRZR phone)
doing put
on files which it doesn't seem to allow (text file instead
of pictures) would end up with 200, OK Success
BUT the file would
not be actually uploaded to the device and trying to get()
it would
result in 404
. Not sure if this is a "glitch" with my phone or it is
the way it's supposed to be... silently giving OKs when things are failing.
The data to be sent will be split into packets
of the maximum size the other party can accept, if you want to change the
size call the mtu()
method before calling put()
.
The put()
method takes one mandatory and several optional
arguments which are as follows:
$obex->put( what => 'some_file' );
Mandatory. Specifies the file name of the file to PUT
, later this may
be changed to allow to contain some arbitrary contents.
$obex->put( what => 'some_file', body_in_first => 1 );
Optional. Takes either true or false values. If a true value is specified
will send a Body
header in the first PUT
packet. Otherwise
first Body
header will be sent only after receiving a Continue
response from the party. Defaults to: 0
$obex->put( what => 'some_file', length => 31232 );
Optional. If specified will stuff the PUT
packet with a Length
header containing the value of length
argument (the length of the
contents to PUT
), this header is optional and by default will
not be sent.
$obex->put( what => 'some_file', time => '20080320T202020Z' );
Optional. If specified will stuff the PUT
packet with a Unicode
version of Time
header (date/time of last modification).
Local times should be represented in the format YYYYMMDDTHHMMSS and UTC
time in the format YYYYMMDDTHHMMSSZ. The letter T
delimits the date from
the time. UTC time is identified by concatenating a Z
to the end of the
sequence. By default no Time
headers will be sent.
$obex->put( what => 'some_file', name => 'other_file' );
Optional. If specified will insert a Name
header into the PUT
packet with the value you specify. By default the value of what
argument will be used unless you set the no_name
argument (see
below) to a true value.
$obex->put( what => 'some_file', no_name => 1 );
Optional. By default the object will insert a Name
header into the
packet with value being the name of the file specified in what
argument.
If you want to prevent this set no_name
argument to a true value.
Note: the Name
header WILL be sent if you specify the name
argument irrelevant of the no_name
argument's value. Note 2:
yo do NOT have to specify the no_name
argument if you specified the
name
argument. Defaults to: 0
$obex->put( what => 'file', headers => [ $some, $raw, $headers ] );
Optional. If you want to pass along some additional packet headers
to the SetPath packet you can use the headers
argument which takes
an arrayref elements of which are OBEX packet headers. See
Net::OBEX::Packet::Headers for information on how to make them.
Defaults to: []
(no headers)
$VAR1 = {
'info' => {
'packet_length' => 3,
'response_code' => 200,
'headers_length' => 0,
'response_code_meaning' => 'OK, Success'
},
'raw_packet' => '��'
};
If an error occurred during the request, put()
will return either
undef
or an empty list, depending on the context and the reason
for the error will be available via error()
method. Otherwise it will
return a hashref presented above. If the
dump above is not self explanatory see Net::OBEX::Response
parse_sock()
method description for the return value when
"is connect packet" option is false.
$obex->close;
$obex->close('No want you no moar');
Similar to disconnect()
method, except this one also closes the socket.
Takes one optional argument which is the text to send out in the
Description
header of the Disconnect
packet. Always returns 1
.
my $last_response_ref = $obex->response;
Takes no arguments, returns the return value of the last successful
get()
, put()
, set_path()
, connect()
or disconnect()
method.
my $socket = $obex->sock;
$obex->sock( $new_socket );
Returns a Socket::Class object which is used by the module for communications. Technically you can swap it out to the socket of your choice by giving it as an argument (but should you? :) ).
my $response_ref = $obex->set_path
or die "Error: " . $obex->error;
If any of the connect()
, disconnect()
, set_path
or get()
methods
fail they will return either undef or an empty list depending on the context
and the reason for the failure will be available via error()
method.
Takes no arguments, returns a human readable error message.
my $server_mtu = $obex->mtu;
Takes no arguments, must be called after a successful call to connect()
returns the maximum size of the packet in bytes the device we connected
to can accept (as reported by the device in response to Connect
).
my $raw_connection_id_header = $obex->connection_id;
If Connection ID
header was present in the response to the Connect
packet when calling the connect()
method the Net::OBEX object will
automatically store it and include it in any other packets sent after
connection (as per specs). The connection_id()
method returns a
raw Connection ID header, it may take an argument which will override
the set header, but it's probably a BadIdea(tm).
my $net_obex_response_object = $obex->obj_res;
Takes no arguments, returns a Net::OBEX::Response object used internally.
my $net_obex_packet_headers_object = $obex->obj_head;
Takes no arguments, returns a Net::OBEX::Packet::Headers object used
internally. You can use this object to create any additional headers you'd
want to include in headers
arguments (where applicable).
my $net_obex_packet_request = $obex->obj_req;
Takes no arguments, returns a Net::OBEX::Packet::Request object used internally.
The examples
directory of this distribution contains get.pl
and
put.pl
scripts which work fine for me, note that you'll need to change
address/port as well as filenames for your device.
Fork this module on GitHub: https://github.com/zoffixznet/Net-OBEX
To report bugs or request features, please use https://github.com/zoffixznet/Net-OBEX/issues
If you can't access GitHub, you can email your request
to bug-Net-OBEX at rt.cpan.org
Zoffix Znet (http://zoffix.com/, http://haslayout.net/)
You can use and distribute this module under the same terms as Perl itself.
See the LICENSE
file included in this distribution for complete
details.