Compare commits

...

Author SHA1 Message Date
  Maciek Borzecki 2562fa5258 meson: update the listing of mconnect source files 7 years ago
  Maciek Borzecki be58f7b02d transfer-download: log on connection and transfer start 7 years ago
  Maciek Borzecki 4d1fe13f60 share: remove unnecessary warning 7 years ago
  Maciek Borzecki 9f122ac0e8 share: trigger transfer share and share-request packets 7 years ago
  Maciek Borzecki 38fb2e7693 packethandlers-proxy: remove unnecessary break 8 years ago
  Maciek Borzecki 00893a722b share: remove unnecessary warning log 8 years ago
  Maciek Borzecki 17001f9edf transfer-download: remove unused variable 8 years ago
  Maciek Borzecki 23b2abf9bd transfer: cleanup error & stream handling 8 years ago
  Maciek Borzecki d92bb2d8c4 share, transfer: user friendly size formatting 8 years ago
  Maciek Borzecki 6b8e5fa223 share: fix error handling when creating downloads path 8 years ago
  Maciek Borzecki bb02424799 mconnect/utils: put helper code inside Utils namespace 8 years ago
  Maciek Borzecki bf9dde0e14 mconnect: move logging to separate file 8 years ago
  Maciek Borzecki 1ad268a6ee device, utils: remove unnecessary helper array_list_to_list() 8 years ago
  Maciek Borzecki 6c72f5e215 mconnect/{share,transfer,download): file sharing - download support 8 years ago
  Maciek Borzecki 574e54aff5 mconnect/devicechannel, utils: move socket keepalive setup to utils 8 years ago
  Maciek Borzecki b190a75738 share: starting work on file sharing support 8 years ago
13 changed files with 425 additions and 82 deletions
Split View
  1. +4
    -0
      Makefile.am
  2. +4
    -0
      meson.build
  3. +1
    -1
      src/mconnect/application.vala
  4. +10
    -8
      src/mconnect/device.vala
  5. +2
    -32
      src/mconnect/devicechannel.vala
  6. +4
    -4
      src/mconnect/discovereddevice.vala
  7. +46
    -0
      src/mconnect/logging.vala
  8. +0
    -2
      src/mconnect/packethandlers-proxy.vala
  9. +2
    -0
      src/mconnect/packethandlers.vala
  10. +85
    -0
      src/mconnect/share.vala
  11. +154
    -0
      src/mconnect/transfer-download.vala
  12. +69
    -0
      src/mconnect/transfer.vala
  13. +44
    -35
      src/mconnect/utils.vala

+ 4
- 0
Makefile.am View File

@ -77,10 +77,14 @@ mconnect_SOURCES = \
src/mconnect/mousepad.vala \
src/mconnect/ping.vala \
src/mconnect/ping-proxy.vala \
src/mconnect/share.vala \
src/mconnect/config.vala \
src/mconnect/application.vala \
src/mconnect/utils.vala \
src/mconnect/property-proxy.vala \
src/mconnect/transfer.vala \
src/mconnect/transfer-download.vala \
src/mconnect/logging.vala \
src/crypt/certificate.vala
mconnect_LDADD = \


+ 4
- 0
meson.build View File

@ -45,6 +45,10 @@ mconnect_src = [
'src/mconnect/application.vala',
'src/mconnect/utils.vala',
'src/mconnect/property-proxy.vala',
'src/mconnect/share.vala',
'src/mconnect/transfer.vala',
'src/mconnect/transfer-download.vala',
'src/mconnect/logging.vala',
'src/crypt/certificate.vala',
]


+ 1
- 1
src/mconnect/application.vala View File

@ -56,7 +56,7 @@ namespace Mconn {
Environment.set_variable("G_MESSAGES_DEBUG", "all", false);
if (log_debug_verbose == true)
enable_vdebug();
Logging.enable_vdebug();
core = Core.instance();
if (core == null)


+ 10
- 8
src/mconnect/device.vala View File

@ -178,15 +178,17 @@ class Device : Object {
* Generates a unique string for this device
*/
public string to_unique_string() {
return make_unique_device_string(this.device_id,
this.device_name,
this.device_type,
this.protocol_version);
return Utils.make_unique_device_string(this.device_id,
this.device_name,
this.device_type,
this.protocol_version);
}
public string to_string() {
return make_device_string(this.device_id, this.device_name,
this.device_type, this.protocol_version);
return Utils.make_device_string(this.device_id,
this.device_name,
this.device_type,
this.protocol_version);
}
/**
@ -206,9 +208,9 @@ class Device : Object {
cache.set_boolean(name, "paired", this.is_paired);
cache.set_string(name, "certificate", this.certificate);
cache.set_string_list(name, "outgoing_capabilities",
array_list_to_list(this.outgoing_capabilities));
this.outgoing_capabilities.to_array());
cache.set_string_list(name, "incoming_capabilities",
array_list_to_list(this.incoming_capabilities));
this.incoming_capabilities.to_array());
}
private async void greet() {


+ 2
- 32
src/mconnect/devicechannel.vala View File

@ -19,7 +19,6 @@
*/
using Mconn;
using Posix;
/**
* Device communication channel
@ -50,36 +49,7 @@ class DeviceChannel : Object {
}
private static void fixup_socket(Socket sock) {
#if 0
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
TCP_KEEPIDLE 4 /* Start keeplives after this period */
TCP_KEEPINTVL 5 /* Interval between keepalives */
TCP_KEEPCNT 6 /* Number of keepalives before death */
#endif
#if 0
int option = 10;
Posix.setsockopt(sock.fd, 6, 4, &option, (Posix.socklen_t) sizeof(int));
option = 5;
Posix.setsockopt(sock.fd, 6, 5, &option, (Posix.socklen_t) sizeof(int));
option = 3;
Posix.setsockopt(sock.fd, 6, 6, &option, (Posix.socklen_t) sizeof(int));
#endif
int option = 10;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPIDLE,
&option, (Posix.socklen_t) sizeof(int));
option = 5;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPINTVL,
&option, (Posix.socklen_t) sizeof(int));
option = 3;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPCNT,
&option, (Posix.socklen_t) sizeof(int));
// enable keepalive
sock.set_keepalive(true);
Utils.socket_set_keepalive(sock);
}
private void replace_streams(InputStream input, OutputStream output) {
@ -191,7 +161,7 @@ class DeviceChannel : Object {
this.peer_certificate = peer_cert;
if (expected_peer != null) {
if (DebugLog.Verbose) {
if (Logging.VERBOSE) {
vdebug("verify certificate, expecting: %s, got: %s",
expected_peer.certificate_pem,
peer_cert.certificate_pem);


+ 4
- 4
src/mconnect/discovereddevice.vala View File

@ -73,10 +73,10 @@ class DiscoveredDevice : Object {
}
public string to_unique_string() {
return make_unique_device_string(this.device_id,
this.device_name,
this.device_type,
this.protocol_version);
return Utils.make_unique_device_string(this.device_id,
this.device_name,
this.device_type,
this.protocol_version);
}
}

+ 46
- 0
src/mconnect/logging.vala View File

@ -0,0 +1,46 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
namespace Logging {
public bool VERBOSE = false;
/**
* enable_vdebug:
*
* Enable verbose debug logging
*/
void enable_vdebug() {
VERBOSE = true;
}
}
/**
* vdebug:
* @format: format string
*
* Same as debug() but looks at verbose debug flag
*/
void vdebug(string format, ...) {
if (Logging.VERBOSE == true) {
var l = va_list();
logv(null, LogLevelFlags.LEVEL_DEBUG, format, l);
}
}

+ 0
- 2
src/mconnect/packethandlers-proxy.vala View File

@ -28,11 +28,9 @@ class PacketHandlersProxy : Object {
switch (iface.get_pkt_type()) {
case BatteryHandler.BATTERY: {
return new BatteryHandlerProxy.for_device_handler(dev, iface);
break;
}
case PingHandler.PING: {
return new PingHandlerProxy.for_device_handler(dev, iface);
break;
}
default:
warning("cannot register bus handler for %s",


+ 2
- 0
src/mconnect/packethandlers.vala View File

@ -41,12 +41,14 @@ class PacketHandlers : Object {
var telephony = TelephonyHandler.instance();
var mousepad = MousepadHandler.instance();
var ping = PingHandler.instance();
var share = ShareHandler.instance();
hnd.@set(notification.get_pkt_type(), notification);
hnd.@set(battery.get_pkt_type(), battery);
hnd.@set(telephony.get_pkt_type(), telephony);
hnd.@set(mousepad.get_pkt_type(), mousepad);
hnd.@set(ping.get_pkt_type(), ping);
hnd.@set(share.get_pkt_type(), share);
return hnd;
}


+ 85
- 0
src/mconnect/share.vala View File

@ -0,0 +1,85 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
class ShareHandler : Object, PacketHandlerInterface {
private const string SHARE = "kdeconnect.share.request";
private const string SHARE_PKT = "kdeconnect.share";
private static string DOWNLOADS = null;
public void use_device(Device dev) {
debug("use device %s for sharing", dev.to_string());
dev.message.connect(this.message);
}
private ShareHandler() {
}
public static ShareHandler instance() {
if (ShareHandler.DOWNLOADS == null) {
ShareHandler.DOWNLOADS = Path.build_filename(
Environment.get_user_special_dir(UserDirectory.DOWNLOAD),
"mconnect");
if (DirUtils.create_with_parents(ShareHandler.DOWNLOADS,
0700) == -1) {
warning("failed to create downloads directory: %s",
Posix.strerror(Posix.errno));
}
}
info("downloads will be saved to %s", ShareHandler.DOWNLOADS);
return new ShareHandler();
}
private static string make_downloads_path(string name) {
return Path.build_filename(ShareHandler.DOWNLOADS, name);
}
public string get_pkt_type() {
return SHARE;
}
public void release_device(Device dev) {
debug("release device %s", dev.to_string());
dev.message.disconnect(this.message);
}
private void message(Device dev, Packet pkt) {
if (pkt.pkt_type != SHARE_PKT && pkt.pkt_type != SHARE) {
return;
}
if (pkt.payload == null) {
warning("missing payload info");
return;
}
string name = pkt.body.get_string_member("filename");
debug("file: %s size: %s", name, format_size(pkt.payload.size));
var t = new DownloadTransfer(
new InetSocketAddress(dev.host,
(uint16) pkt.payload.port),
pkt.payload.size,
make_downloads_path(name));
t.start();
}
}

+ 154
- 0
src/mconnect/transfer-download.vala View File

@ -0,0 +1,154 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
class DownloadTransfer : Object {
private InetSocketAddress isa = null;
private File file = null;
private FileOutputStream foutstream = null;
private Cancellable cancel = null;
private SocketConnection conn = null;
public uint64 size = 0;
public uint64 transferred = 0;
public string destination = "";
private Transfer transfer = null;
public DownloadTransfer(InetSocketAddress isa, uint64 size, string dest) {
this.isa = isa;
this.cancel = new Cancellable();
this.destination = dest;
this.size = size;
}
public bool start() {
try {
this.file = File.new_for_path(this.destination + ".part");
this.foutstream = this.file.replace(null, false,
FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION);
} catch (Error e) {
warning("failed to open destination path %s: %s",
this.destination, e.message);
return false;
}
debug("start transfer from %s", this.isa.to_string());
var client = new SocketClient();
client.connect_async.begin(this.isa, null, this.connected);
return true;
}
private void connected(Object? obj, AsyncResult res) {
try {
var sc = (SocketClient)obj;
this.conn = sc.connect_async.end(res);
var sock = this.conn.get_socket();
Utils.socket_set_keepalive(sock);
this.start_transfer();
} catch (Error e) {
var err ="failed to connect: %s".printf(e.message);
warning(err);
this.cleanup_error(err);
}
}
private void start_transfer() {
debug("connected, start transfer");
this.transfer = new Transfer(this.conn.input_stream,
this.foutstream);
this.transfer.progress.connect((t, done) => {
int percent = (int) (100.0 * ((double)done / (double)this.size));
debug("progress: %s/%s %d%%",
format_size(done), format_size(this.size), percent);
this.transferred = done;
});
this.transfer.transfer_async.begin(this.cancel,
this.transfer_complete);
}
private void transfer_complete(Object? obj, AsyncResult res) {
info("transfer finished");
try {
var rcvd_bytes = this.transfer.transfer_async.end(res);
debug("transfer done, got %s", format_size(rcvd_bytes));
this.cleanup_success();
} catch (Error err) {
warning("transfer failed: %s", err.message);
this.cleanup_error(err.message);
}
}
private void cleanup() {
if (this.foutstream != null) {
try {
this.foutstream.close();
} catch (IOError e) {
warning("failed to close file output: %s",
e.message);
}
}
if (this.conn != null) {
try {
this.conn.close();
} catch (IOError e) {
warning("failed to close connection: %s",
e.message);
}
}
this.file = null;
this.foutstream = null;
this.conn = null;
this.transfer = null;
}
private void cleanup_error(string reason) {
this.file.@delete();
this.cleanup();
this.error(reason);
}
private void cleanup_success() {
try {
var dest = File.new_for_path(this.destination);
this.file.move(dest, FileCopyFlags.OVERWRITE);
this.cleanup();
this.finished();
} catch (IOError e) {
var err = "failed to rename temporary file %s to %s: %s".printf(this.file.get_path(),
this.destination,
e.message);
warning(err);
this.cleanup_error(err);
}
}
public signal void finished();
public signal void error(string reason);
}

+ 69
- 0
src/mconnect/transfer.vala View File

@ -0,0 +1,69 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
class Transfer : Object {
private InputStream from = null;
private OutputStream to = null;
public Transfer(InputStream from, OutputStream to) {
this.from = from;
this.to = to;
}
/**
* transfer_async:
* @cancel: cancellable
*
* Starty asynchronous transfer of data from @from stream to @to stream.
*
* @return number of bytes transferred if no error occurred
*/
public async uint64 transfer_async(Cancellable? cancel) throws Error {
uint64 bytes_done = 0;
var chunk_size = 4096;
var max_chunk_size = 64 * 1024;
while (true) {
var data = yield this.from.read_bytes_async(chunk_size);
debug("read %d bytes", data.length);
if (data.length == 0) {
break;
}
yield this.to.write_bytes_async(data);
bytes_done += data.length;
this.progress(bytes_done);
if (data.length == chunk_size)
chunk_size = 2 * chunk_size;
if (chunk_size > max_chunk_size)
chunk_size = max_chunk_size;
}
debug("transfer done, got %llu bytes", format_size(bytes_done));
return bytes_done;
}
/**
* progress:
* @bytes_down: number of bytes transferred
*
* Indicate transfer progress
*/
public signal void progress(uint64 bytes_done);
}

+ 44
- 35
src/mconnect/utils.vala View File

@ -18,42 +18,9 @@
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
/**
* @array_list_to_list:
* @al: Gee.ArrayList<T>
*
* Convert Gee.ArrayList<T> to T[]
*/
T[] array_list_to_list<T>(Gee.ArrayList<T> al) {
T[] out_list = new T[al.size];
int i = 0;
foreach(var v in al) {
out_list[i] = v;
i++;
}
return out_list;
}
namespace Utils {
namespace DebugLog{
public bool Verbose = false;
}
void enable_vdebug() {
DebugLog.Verbose = true;
}
/**
* vdebug:
* @format: format string
*
* Same as debug() but looks at verbose debug flag
*/
void vdebug(string format, ...) {
if (DebugLog.Verbose == true) {
var l = va_list();
logv(null, LogLevelFlags.LEVEL_DEBUG, format, l);
}
}
using Posix;
/**
* make_unique_device_string:
@ -83,3 +50,45 @@ string make_device_string(string id, string name,
return "%s-%s-%s-%u".printf(id, name, type, pv);
}
/**
* socket_set_keepalive:
* @sock: socket
*
* Set keepalive counters on socket
*/
void socket_set_keepalive(Socket sock) {
#if 0
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
TCP_KEEPIDLE 4 /* Start keeplives after this period */
TCP_KEEPINTVL 5 /* Interval between keepalives */
TCP_KEEPCNT 6 /* Number of keepalives before death */
#endif
#if 0
int option = 10;
Posix.setsockopt(sock.fd, 6, 4, &option, (Posix.socklen_t) sizeof(int));
option = 5;
Posix.setsockopt(sock.fd, 6, 5, &option, (Posix.socklen_t) sizeof(int));
option = 3;
Posix.setsockopt(sock.fd, 6, 6, &option, (Posix.socklen_t) sizeof(int));
#endif
int option = 10;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPIDLE,
&option, (Posix.socklen_t) sizeof(int));
option = 5;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPINTVL,
&option, (Posix.socklen_t) sizeof(int));
option = 3;
Posix.setsockopt(sock.fd, IPProto.TCP,
Posix.TCP_KEEPCNT,
&option, (Posix.socklen_t) sizeof(int));
// enable keepalive
sock.set_keepalive(true);
}
}

Loading…
Cancel
Save