1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <assert.h>
17 #include <errno.h>
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/uio.h>
23 #include <unistd.h>
24 
25 #include <trusty/tipc.h>
26 
27 #include "ipc.h"
28 #include "log.h"
29 
30 #define MAX_RECONNECT_RETRY_COUNT 5
31 #define TRUSTY_RECONNECT_TIMEOUT_SEC 5
32 
33 static int tipc_fd = -1;
34 
ipc_connect(const char * device,const char * port)35 int ipc_connect(const char *device, const char *port)
36 {
37     int rc;
38     uint retry_cnt = 0;
39 
40     assert(tipc_fd == -1);
41 
42     while(true) {
43         rc = tipc_connect(device, port);
44         if (rc >= 0)
45             break;
46 
47         ALOGE("failed (%d) to connect to storage server\n", rc);
48         if (++retry_cnt > MAX_RECONNECT_RETRY_COUNT) {
49             ALOGE("max number of reconnect retries (%d) has been reached\n",
50                    retry_cnt);
51             return -1;
52         }
53         sleep(TRUSTY_RECONNECT_TIMEOUT_SEC);
54     }
55     tipc_fd = rc;
56     return 0;
57 }
58 
ipc_disconnect(void)59 void ipc_disconnect(void)
60 {
61     assert(tipc_fd >=  0);
62 
63     tipc_close(tipc_fd);
64     tipc_fd = -1;
65 }
66 
ipc_get_msg(struct storage_msg * msg,void * req_buf,size_t req_buf_len)67 ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len)
68 {
69     ssize_t rc;
70     struct iovec iovs[2] = {{msg, sizeof(*msg)}, {req_buf, req_buf_len}};
71 
72     assert(tipc_fd >=  0);
73 
74     rc = readv(tipc_fd, iovs, 2);
75     if (rc < 0) {
76         ALOGE("failed to read request: %s\n", strerror(errno));
77         return rc;
78     }
79 
80    /* check for minimum size */
81    if ((size_t)rc < sizeof(*msg)) {
82        ALOGE("message is too short (%zu bytes received)\n", rc);
83        return -1;
84    }
85 
86    /* check for message completeness */
87    if (msg->size != (uint32_t)rc) {
88        ALOGE("inconsistent message size [cmd=%d] (%u != %u)\n",
89              msg->cmd, msg->size, (uint32_t)rc);
90        return -1;
91    }
92 
93    return rc - sizeof(*msg);
94 }
95 
ipc_respond(struct storage_msg * msg,void * out,size_t out_size)96 int ipc_respond(struct storage_msg *msg, void *out, size_t out_size)
97 {
98     ssize_t rc;
99     struct iovec iovs[2] = {{msg, sizeof(*msg)}, {out, out_size}};
100 
101     assert(tipc_fd >=  0);
102 
103     msg->cmd |= STORAGE_RESP_BIT;
104 
105     rc = writev(tipc_fd, iovs, out ? 2 : 1);
106     if (rc < 0) {
107         ALOGE("error sending response 0x%x: %s\n",
108               msg->cmd, strerror(errno));
109         return -1;
110     }
111 
112     return 0;
113 }
114 
115 
116