Net-Bluetooth
view release on metacpan or search on metacpan
else if(strlen(uuid_str) == 6) {
// 16-bit reserved UUID with 0x on front
if(uuid_str[0] == '0' && uuid_str[1] == 'x' || uuid_str[1] == 'X') {
// move chars up
uuid_str[0] = uuid_str[2];
uuid_str[1] = uuid_str[3];
uuid_str[2] = uuid_str[4];
uuid_str[3] = uuid_str[5];
uuid_str[4] = '\0';
int i = strtol(uuid_str, &endptr, 16);
if(endptr != uuid_str + 4) return -1;
if(uuid != NULL) sdp_uuid16_create(uuid, i);
}
else return(-1);
}
else if(strlen(uuid_str) == 4) {
// 16-bit reserved UUID
int i = strtol(uuid_str, &endptr, 16);
if(endptr != uuid_str + 4) return -1;
if(uuid != NULL) sdp_uuid16_create(uuid, i);
}
else {
return -1;
}
return 0;
}
MODULE = Net::Bluetooth PACKAGE = Net::Bluetooth
int
_init()
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
int
_deinit()
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
void
_close(sock)
int sock
PPCODE:
close(sock);
InOutStream
_perlfh(fd)
int fd
CODE:
InOutStream fh = PerlIO_fdopen(fd, "r+");
RETVAL = fh;
OUTPUT:
RETVAL
unsigned int
_use_service_handle()
CODE:
// We use a service handle with BlueZ
RETVAL = 1;
OUTPUT:
RETVAL
void
get_remote_devices(...)
PPCODE:
EXTEND(sp, 1);
char addr[19];
char name[248];
char *local_addr;
int len = 8; // 1.28 * len
int max_rsp = 255; // max devices
int flags = IREQ_CACHE_FLUSH; // flush cache of previously discovered devices
int dev_id;
bdaddr_t baddr;
STRLEN n_a;
if(items > 0) {
local_addr = (char *) SvPV(ST(1), n_a);
// str2ba always returns 0
str2ba(local_addr, &baddr);
dev_id = hci_get_route(&baddr);
}
else {
dev_id = hci_get_route(NULL);
}
if(dev_id < 0) {
//croak("Invalid device ID returned\n");
XSRETURN_UNDEF;
}
int sock = hci_open_dev(dev_id);
if(sock < 0) {
//croak("Could not open device socket\n");
XSRETURN_UNDEF;
}
inquiry_info *ii = (inquiry_info*) malloc(max_rsp * sizeof(inquiry_info));
if(ii == NULL) {
croak("malloc failed in get_remote_devices");
}
int num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
// hci_inquiry error or no devices found
if(num_rsp <= 0) {
free(ii);
close(sock);
XSRETURN_UNDEF;
}
HV *return_hash = newHV();
int i;
for(i = 0; i < num_rsp; i++) {
ba2str(&(ii+i)->bdaddr, addr);
if(hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
strcpy(name, "[unknown]");
hv_store(return_hash, addr, strlen(addr), newSVpv(name, 0), 0);
}
free(ii);
PUSHs(sv_2mortal(newRV_inc((SV*) return_hash)));
close(sock);
void
sdp_search(addr, service, name)
char *addr
char *service
char *name
PPCODE:
EXTEND(sp, 1);
uuid_t svc_uuid;
bdaddr_t target;
sdp_list_t *response_list = NULL;
sdp_session_t *session = 0;
unsigned int portnum = 0;
char local_host [] = "FF:FF:FF:00:00:00";
if(strcasecmp(addr, "localhost") == 0 || strcasecmp(addr, "local") == 0)
str2ba(local_host, &target);
else
str2ba(addr, &target);
// connect to remote or local SDP server
session = sdp_connect(BDADDR_ANY, &target, SDP_RETRY_IF_BUSY);
if(session == NULL)
XSRETURN_UNDEF;
// specify the UUID of the application we are searching for
// convert the UUID string into a uuid_t
// if service is not set, search for PUBLIC_BROWSE_GROUP
if(service == NULL || strlen(service) == 0 || strlen(service) == 1 && *service == '0') {
if(str2uuid(BROWSE_GROUP_STRING, &svc_uuid) != 0) {
XSRETURN_UNDEF;
}
}
else {
if(str2uuid(service, &svc_uuid) != 0){
XSRETURN_UNDEF;
}
}
sdp_list_t *search_list = sdp_list_append(NULL, &svc_uuid);
uint32_t range = 0x0000FFFF;
sdp_list_t *attrid_list = sdp_list_append(NULL, &range);
// get a list of service records
if(sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list) != 0) {
sdp_list_free(search_list, 0);
sdp_list_free(attrid_list, 0);
XSRETURN_UNDEF;
}
sdp_list_t *r = response_list;
// go through each of the service records
// create a hash for each record that matches
for(; r; r = r->next) {
sdp_record_t *rec = (sdp_record_t*) r->data;
sdp_list_t *proto_list;
HV *return_hash = NULL;
// get service name
char buf[256];
if(sdp_get_service_name(rec, buf, sizeof(buf)) == 0) {
// no name match requested
else
RETVAL = -1;
}
else
RETVAL = -1;
OUTPUT:
RETVAL
int
_bind(fd, port, proto)
int fd
int port
char *proto
CODE:
if(strcasecmp(proto, "RFCOMM") == 0) {
struct sockaddr_rc rcaddr;
// set the connection parameters
rcaddr.rc_family = AF_BLUETOOTH;
rcaddr.rc_channel = (uint8_t) port;
rcaddr.rc_bdaddr = *BDADDR_ANY;
RETVAL = bind(fd, (struct sockaddr *)&rcaddr, sizeof(rcaddr));
}
else if(strcasecmp(proto, "L2CAP") == 0) {
struct sockaddr_l2 l2addr = { 0 };
// set the connection parameters
l2addr.l2_family = AF_BLUETOOTH;
l2addr.l2_psm = htobs(port);
l2addr.l2_bdaddr = *BDADDR_ANY;
RETVAL = bind(fd, (struct sockaddr *)&l2addr, sizeof(l2addr));
}
else
RETVAL = -1;
OUTPUT:
RETVAL
int
_listen(fd, backlog)
int fd
int backlog
CODE:
RETVAL = listen(fd, backlog);
OUTPUT:
RETVAL
void
_accept(fd, proto)
int fd
char *proto
PPCODE:
EXTEND(sp, 2);
socklen_t addr_len;
int res;
if(strcasecmp(proto, "RFCOMM") == 0) {
struct sockaddr_rc rcaddr;
addr_len = sizeof(rcaddr);
res = accept(fd, (struct sockaddr *)&rcaddr, &addr_len);
PUSHs(sv_2mortal(newSViv(res)));
if(res >= 0) {
char addr[19];
ba2str(&rcaddr.rc_bdaddr, addr);
PUSHs(sv_2mortal(newSVpv(addr, 0)));
}
}
else if(strcasecmp(proto, "L2CAP") == 0) {
struct sockaddr_l2 l2addr = { 0 };
addr_len = sizeof(l2addr);
res = accept(fd, (struct sockaddr *)&l2addr, &addr_len);
PUSHs(sv_2mortal(newSViv(res)));
if(res >= 0) {
char addr[19];
ba2str(&l2addr.l2_bdaddr, addr);
PUSHs(sv_2mortal(newSVpv(addr, 0)));
}
}
else
PUSHs(sv_2mortal(newSViv(-1)));
unsigned int
_register_service_handle(proto, port, service_id, name, desc)
char *proto
int port
char *service_id
char *name
char *desc
PPCODE:
uint8_t rfcomm_channel = 0;
uint16_t l2cap_port = 0;
const char *service_name = name;
const char *service_dsc = desc;
const char *service_prov = name;
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
sdp_list_t *l2cap_list = 0,
*rfcomm_list = 0,
*root_list = 0,
*proto_list = 0,
*access_proto_list = 0;
sdp_data_t *channel = 0, *psm = 0;
sdp_record_t *record = sdp_record_alloc();
//sdp_uuid16_create(&svc_uuid, service_id);
if(str2uuid(service_id, &svc_uuid) != 0) {
XSRETURN_IV(0);
}
sdp_set_service_id(record, svc_uuid);
// make the service record publicly browsable
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root_list = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups(record, root_list);
// set l2cap information
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append(0, &l2cap_uuid);
proto_list = sdp_list_append(0, l2cap_list);
if(strcasecmp(proto, "L2CAP") == 0) {
uint16_t l2cap_port = port;
psm = sdp_data_alloc(SDP_UINT16, &l2cap_port);
sdp_list_append(l2cap_list, psm);
}
//proto_list = sdp_list_append(0, l2cap_list);
// set rfcomm information
//sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
//rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
if(strcasecmp(proto, "RFCOMM") == 0) {
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
uint8_t rfcomm_channel = port;
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
sdp_list_append(rfcomm_list, channel);
sdp_list_append(proto_list, rfcomm_list);
}
//sdp_list_append(proto_list, rfcomm_list);
// attach protocol information to service record
access_proto_list = sdp_list_append( 0, proto_list );
sdp_set_access_protos( record, access_proto_list );
// set the name, provider, and description
sdp_set_info_attr(record, service_name, service_prov, service_dsc);
// connect to the local SDP server, register the service record, and disconnect
sdp_session_t *session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
if(session) {
if(sdp_record_register(session, record, 0) >= 0) {
// this is bad and should be kept internal
// will fix this up next run
PUSHs(sv_2mortal(newSVuv((unsigned int)session)));
}
else {
PUSHs(sv_2mortal(newSViv(0)));
}
}
else {
PUSHs(sv_2mortal(newSViv(0)));
}
if(psm) sdp_data_free(psm);
if(channel) sdp_data_free(channel);
sdp_list_free(l2cap_list, 0);
sdp_list_free(rfcomm_list, 0);
sdp_list_free(root_list, 0);
sdp_list_free(access_proto_list, 0);
void
_stop_service_handle(sdp_addr)
unsigned int sdp_addr
CODE:
sdp_session_t *sdp_session;
sdp_session = (sdp_session_t *) sdp_addr;
sdp_close(sdp_session);
void
_getpeername(fd, proto)
int fd
char *proto
PPCODE:
EXTEND(sp, 2);
if(strcasecmp(proto, "RFCOMM") == 0) {
struct sockaddr_rc rcaddr;
socklen_t len = sizeof(rcaddr);
if(getpeername(fd, (struct sockaddr *) &rcaddr, &len) == 0) {
char addr[19];
ba2str(&rcaddr.rc_bdaddr, addr);
PUSHs(sv_2mortal(newSVpv(addr, 0)));
PUSHs(sv_2mortal(newSVuv(rcaddr.rc_channel)));
}
}
else if(strcasecmp(proto, "L2CAP") == 0) {
struct sockaddr_l2 l2addr = { 0 };
socklen_t len = sizeof(l2addr);
if(getpeername(fd, (struct sockaddr *) &l2addr, &len) == 0) {
char addr[19];
ba2str(&l2addr.l2_bdaddr, addr);
PUSHs(sv_2mortal(newSVpv(addr, 0)));
PUSHs(sv_2mortal(newSVuv(l2addr.l2_psm)));
}
}
( run in 0.521 second using v1.01-cache-2.11-cpan-5511b514fd6 )