Add network transport for image transfer
authorDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 27 Sep 2017 07:17:21 +0000 (16:17 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Mon, 2 Jul 2018 01:21:36 +0000 (10:21 +0900)
This patch adds network transport which can transfer image via tcp
layer. If the option "--net=<ip[:port]>" is passed, lthor tries to
connect the target with given ip and port, or else, it just try to
connect via usb.

When the port nubmer is not provided for network option, it uses
default port.

Change-Id: I14bea3523d01e3a4f547e41d40d353790a870460
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
CMakeLists.txt
libthor/thor.h
libthor/thor_net.c [new file with mode: 0644]
libthor/thor_transport.c
libthor/thor_transport.h
lthor.c

index 852822911c22d80526bf4e83de33cfd42c3c453f..4d67887ab9eabee4df182d8c90d7d53e0b71ef6b 100755 (executable)
@@ -8,6 +8,7 @@ SET(LIBTHOR_SRCS
        libthor/thor_tar.c
        libthor/thor_transport.c
        libthor/thor_usb.c
+       libthor/thor_net.c
 )
 
 SET(SRCS
index 75c918b91f840d19e6bf2ef53215f56bd6488041..e45c7a04b83828506111c8c4bf2b3b25cfbdccfb 100644 (file)
@@ -28,8 +28,16 @@ struct usb_device_id {
        const char *serial;
 };
 
+#define THOR_NET_PORT (23456)
+
+struct net_device_id {
+       const char *ip_addr;
+       int port;
+};
+
 struct thor_device_id {
        struct usb_device_id usb_dev;
+       struct net_device_id net_dev;
 };
 
 struct thor_device_handle;
@@ -71,6 +79,7 @@ typedef void (*thor_next_entry_cb)(thor_device_handle *th,
 
 enum thor_transport_type {
        THOR_TRANSPORT_USB = 0,
+       THOR_TRANSPORT_NET,
        THOR_TRANSPORT_MAX,
 };
 
diff --git a/libthor/thor_net.c b/libthor/thor_net.c
new file mode 100644 (file)
index 0000000..08d479f
--- /dev/null
@@ -0,0 +1,233 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "thor.h"
+#include "thor_internal.h"
+#include "thor_transport.h"
+
+#define INVALID_SOCKFD (-1)
+
+static int thor_net_connect_device(struct net_device_handle *nh,
+                                  struct net_device_id *dev_id,
+                                  int wait)
+{
+       struct sockaddr_in server;
+       int s;
+       int ret;
+
+reconnect:
+       s = socket(AF_INET, SOCK_STREAM, 0);
+       if (s < 0)
+               return -EIO;
+
+       memset(&server, 0, sizeof(server));
+
+       ret = inet_pton(AF_INET, dev_id->ip_addr, &server.sin_addr);
+       if (ret <= 0) {
+               fprintf(stderr, "IP addr is not valid:%s\n", dev_id->ip_addr);
+               close(s);
+               return -EINVAL;
+       }
+       server.sin_family = AF_INET;
+       server.sin_port = htons(dev_id->port);
+
+       if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
+               if (!wait) {
+                       close(s);
+                       return -ENODEV;
+               }
+
+               sleep(1);
+               close(s);
+               goto reconnect;
+       }
+
+       nh->sock_fd = s;
+
+       return 0;
+}
+
+static int thor_net_open(thor_device_handle *th,
+                        struct thor_device_id *user_dev_id,
+                        int wait)
+{
+       struct net_device_handle *nh;
+       struct net_device_id *dev_id = &user_dev_id->net_dev;
+       int ret;
+
+       if (!dev_id->ip_addr || !dev_id->port) {
+               fprintf(stderr, "net mode requires --ip-addr and --tcp-port\n");
+               return -EINVAL;
+       }
+
+       nh = calloc(sizeof(*nh), 1);
+       if (!nh)
+               return -ENOMEM;
+
+       nh->sock_fd = INVALID_SOCKFD;
+
+       ret = thor_net_connect_device(nh, dev_id, wait);
+       if (ret)
+               goto close_dev;
+
+       th->dev_priv = nh;
+
+       return 0;
+
+close_dev:
+       th->ops->close(th);
+       return ret;
+}
+
+static void thor_net_close(thor_device_handle *th)
+{
+       struct net_device_handle *nh = th->dev_priv;
+
+       if (!nh)
+               return;
+
+       if (nh->sock_fd >= 0)
+               close(nh->sock_fd);
+
+       free(nh);
+       th->dev_priv = NULL;
+}
+
+static int thor_net_send(thor_device_handle *th, unsigned char *buf,
+                        off_t count, int timeout)
+{
+       struct net_device_handle *nh = th->dev_priv;
+       ssize_t transferred;
+
+       if (!nh)
+               return -ENODEV;
+
+       transferred = send(nh->sock_fd, buf, count, 0);
+       if (transferred < 0)
+               return transferred;
+
+       if (transferred < (ssize_t)count)
+               return -EIO;
+
+       return 0;
+}
+
+static int thor_net_recv(thor_device_handle *th, unsigned char *buf,
+                        off_t count, int timeout)
+{
+       struct net_device_handle *nh = th->dev_priv;
+       ssize_t transferred;
+
+       if (!nh)
+               return -ENODEV;
+
+       transferred = recv(nh->sock_fd, buf, count, MSG_WAITALL);
+       if (transferred < 0)
+               return transferred;
+
+       if (transferred < (ssize_t)count)
+               return -EIO;
+
+       return 0;
+}
+
+static int t_thor_net_send_chunk(thor_device_handle *th, unsigned char *chunk,
+                                off_t size, int chunk_number)
+{
+       struct data_res_pkt resp;
+       int ret;
+
+       ret = thor_net_send(th, chunk, size, 0);
+       if (ret < 0)
+               return ret;
+
+       memset(&resp, 0, DATA_RES_PKT_SIZE);
+
+       ret = thor_net_recv(th, (unsigned char *)&resp, DATA_RES_PKT_SIZE, 0);
+       if (ret < 0)
+               return ret;
+
+       if (resp.cnt != chunk_number)
+               return -EIO;
+
+       return resp.ack;
+}
+
+static int thor_net_send_raw_data(thor_device_handle *th,
+                                 struct thor_data_src *data,
+                                 off_t trans_unit_size,
+                                 thor_progress_cb report_progress,
+                                 void *user_data)
+{
+       struct net_device_handle *nh = th->dev_priv;
+       unsigned char *chunk;
+       off_t data_left;
+       off_t size;
+       off_t data_sent = 0;
+       int chunk_number = 1;
+       int ret;
+
+       if (!nh)
+               return -ENODEV;
+
+       chunk = malloc(trans_unit_size);
+       if (!chunk)
+               return -ENOMEM;
+
+       data_left = data->get_file_length(data);
+
+       while (data_left) {
+               size = data_left > trans_unit_size ?
+                      trans_unit_size : data_left;
+
+               ret = data->get_block(data, chunk, size);
+               if (ret < 0 || ret != size)
+                       goto cleanup;
+
+               memset(chunk + size, 0, trans_unit_size - size);
+               if (th) {
+                       ret = t_thor_net_send_chunk(th, chunk, trans_unit_size,
+                                                   chunk_number);
+                       if (ret)
+                               goto cleanup;
+               }
+
+               data_sent += size;
+               data_left -= size;
+               ++chunk_number;
+               if (report_progress)
+                       report_progress(NULL, data, data_sent, data_left,
+                                       chunk_number, user_data);
+       }
+
+       ret = 0;
+
+cleanup:
+       free(chunk);
+       return ret;
+}
+
+
+static struct thor_transport_ops thor_net_ops = {
+       .open = thor_net_open,
+       .close = thor_net_close,
+       .send = thor_net_send,
+       .recv = thor_net_recv,
+       .send_data = thor_net_send_raw_data,
+};
+
+int thor_net_init(thor_device_handle *th)
+{
+       th->ops = &thor_net_ops;
+
+       return 0;
+}
+
+void thor_net_cleanup(thor_device_handle *th)
+{
+       return;
+}
index ae8b642f817636b9d9eae815b049243576bc2b8e..d6817e92348012f86caf98e911ced1950cd08d22 100644 (file)
@@ -28,6 +28,8 @@ int t_thor_init(thor_device_handle *th)
        switch (th->type) {
        case THOR_TRANSPORT_USB:
                return thor_usb_init(th);
+       case THOR_TRANSPORT_NET:
+               return thor_net_init(th);
        default:
                break;
        }
@@ -41,6 +43,9 @@ void t_thor_cleanup(thor_device_handle *th)
        case THOR_TRANSPORT_USB:
                thor_usb_cleanup(th);
                break;
+       case THOR_TRANSPORT_NET:
+               thor_net_cleanup(th);
+               break;
        default:
                break;
        }
index daddc9e6bd5a177721d475f4e545d3aacb945b8c..7db1017f15a03bb6b8fd703de2bb7d79d7170b88 100644 (file)
@@ -45,4 +45,12 @@ int thor_usb_init(thor_device_handle *th);
 void thor_usb_cleanup(thor_device_handle *th);
 int t_acm_prepare_device(struct usb_device_handle *uh);
 
+/* Net transport */
+struct net_device_handle {
+       int sock_fd;
+};
+
+int thor_net_init(thor_device_handle *th);
+void thor_net_cleanup(thor_device_handle *th);
+
 #endif /* THOR_TRANSPORT_H__ */
diff --git a/lthor.c b/lthor.c
index 964a44ebef4da72732080c479e65f35736eecb1e..38a80d41662cd4964bcbad397fa1e334d8f90f8e 100644 (file)
--- a/lthor.c
+++ b/lthor.c
@@ -355,11 +355,12 @@ close_dev:
 static void usage(const char *exename)
 {
        fprintf(stderr,
-               "Usage: %s: [options] [-d port] [-p pitfile] [tar] [tar] ..\n"
+               "Usage: %s: [options] [-n ip[:port]] [-d port] [-p pitfile] [tar] [tar] ..\n"
                "Options:\n"
                "  -t, --test                         Don't flash, just check if given tar files are correct\n"
                "  -v, --verbose                      Be more verbose\n"
                "  -c, --check                        Don't flash, just check if given tty port is thor capable\n"
+               "  -n <ip[:port]>, --net=<ip[:port]>  Flash device through network connection mode with given IP\n"
                "  -p <pitfile>, --pitfile=<pitfile>  Flash new partition table\n"
                "  -b <busid>, --busid=<busid>        Flash device with given busid\n"
                "  --vendor-id=<vid>                  Flash device with given Vendor ID\n"
@@ -398,6 +399,8 @@ int main(int argc, char **argv)
                .usb_dev.vid = -1,
                .usb_dev.pid = -1,
                .usb_dev.serial = NULL,
+               .net_dev.ip_addr = NULL,
+               .net_dev.port = 0,
        };
 
        struct option opts[] = {
@@ -406,6 +409,7 @@ int main(int argc, char **argv)
                {"check", no_argument, 0, 'c'},
                {"port", required_argument, 0, 'd'},
                {"pitfile", required_argument, 0, 'p'},
+               {"net", required_argument, 0, 'n'},
                {"busid", required_argument, 0, 'b'},
                {"vendor-id", required_argument, 0, 1},
                {"product-id", required_argument, 0, 2},
@@ -422,7 +426,7 @@ int main(int argc, char **argv)
        exename = argv[0];
 
        while (1) {
-               opt = getopt_long(argc, argv, "tvcd:p:b:", opts, &optindex);
+               opt = getopt_long(argc, argv, "tvcd:p:b:n:", opts, &optindex);
                if (opt == -1)
                        break;
 
@@ -442,6 +446,21 @@ int main(int argc, char **argv)
                case 'p':
                        pitfile = optarg;
                        break;
+               case 'n':
+               {
+                       unsigned long int val;
+
+                       type = THOR_TRANSPORT_NET;
+                       dev_id.net_dev.ip_addr = strsep(&optarg, ":");
+
+                       if (optarg)
+                               val = strtoul(optarg, NULL, 0);
+                       else
+                               val = THOR_NET_PORT;
+
+                       dev_id.net_dev.port = (int)val;
+                       break;
+               }
                case 'b':
                        dev_id.usb_dev.busid = optarg;
                        break;