1/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30// System dependencies
31#include <stdio.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <string.h>
35#include <unistd.h>
36
37// Camera dependencies
38#include "mm_camera_dbg.h"
39#include "mm_camera_sock.h"
40
41/*===========================================================================
42 * FUNCTION   : mm_camera_socket_create
43 *
44 * DESCRIPTION: opens a domain socket tied to camera ID and socket type
45 *  @cam_id   : camera ID
46 *  @sock_type: socket type, TCP/UDP
47 *
48 * RETURN     : fd related to the domain socket
49 *==========================================================================*/
50int mm_camera_socket_create(int cam_id, mm_camera_sock_type_t sock_type)
51{
52    int socket_fd;
53    mm_camera_sock_addr_t sock_addr;
54    int sktype;
55    int rc;
56
57    switch (sock_type)
58    {
59      case MM_CAMERA_SOCK_TYPE_UDP:
60        sktype = SOCK_DGRAM;
61        break;
62      case MM_CAMERA_SOCK_TYPE_TCP:
63        sktype = SOCK_STREAM;
64        break;
65      default:
66        LOGE("unknown socket type =%d", sock_type);
67        return -1;
68    }
69    socket_fd = socket(AF_UNIX, sktype, 0);
70    if (socket_fd < 0) {
71        LOGE("error create socket fd =%d", socket_fd);
72        return socket_fd;
73    }
74
75    memset(&sock_addr, 0, sizeof(sock_addr));
76    sock_addr.addr_un.sun_family = AF_UNIX;
77    snprintf(sock_addr.addr_un.sun_path,
78             UNIX_PATH_MAX, QCAMERA_DUMP_FRM_LOCATION"cam_socket%d", cam_id);
79    rc = connect(socket_fd, &sock_addr.addr, sizeof(sock_addr.addr_un));
80    if (0 != rc) {
81      close(socket_fd);
82      socket_fd = -1;
83      LOGE("socket_fd=%d %s ", socket_fd, strerror(errno));
84    }
85
86    LOGD("socket_fd=%d %s", socket_fd,
87        sock_addr.addr_un.sun_path);
88    return socket_fd;
89}
90
91/*===========================================================================
92 * FUNCTION   : mm_camera_socket_close
93 *
94 * DESCRIPTION:  close domain socket by its fd
95 *   @fd      : file descriptor for the domain socket to be closed
96 *
97 * RETURN     : none
98 *==========================================================================*/
99void mm_camera_socket_close(int fd)
100{
101    if (fd >= 0) {
102      close(fd);
103    }
104}
105
106/*===========================================================================
107 * FUNCTION   : mm_camera_socket_sendmsg
108 *
109 * DESCRIPTION:  send msg through domain socket
110 *   @fd      : socket fd
111 *   @msg     : pointer to msg to be sent over domain socket
112 *   @sendfd  : file descriptors to be sent
113 *
114 * RETURN     : the total bytes of sent msg
115 *==========================================================================*/
116int mm_camera_socket_sendmsg(
117  int fd,
118  void *msg,
119  size_t buf_size,
120  int sendfd)
121{
122    struct msghdr msgh;
123    struct iovec iov[1];
124    struct cmsghdr * cmsghp = NULL;
125    char control[CMSG_SPACE(sizeof(int))];
126
127    if (msg == NULL) {
128      LOGD("msg is NULL");
129      return -1;
130    }
131    memset(&msgh, 0, sizeof(msgh));
132    msgh.msg_name = NULL;
133    msgh.msg_namelen = 0;
134
135    iov[0].iov_base = msg;
136    iov[0].iov_len = buf_size;
137    msgh.msg_iov = iov;
138    msgh.msg_iovlen = 1;
139    LOGD("iov_len=%llu",
140            (unsigned long long int)iov[0].iov_len);
141
142    msgh.msg_control = NULL;
143    msgh.msg_controllen = 0;
144
145    /* if sendfd is valid, we need to pass it through control msg */
146    if( sendfd >= 0) {
147      msgh.msg_control = control;
148      msgh.msg_controllen = sizeof(control);
149      cmsghp = CMSG_FIRSTHDR(&msgh);
150      if (cmsghp != NULL) {
151        LOGD("Got ctrl msg pointer");
152        cmsghp->cmsg_level = SOL_SOCKET;
153        cmsghp->cmsg_type = SCM_RIGHTS;
154        cmsghp->cmsg_len = CMSG_LEN(sizeof(int));
155        *((int *)CMSG_DATA(cmsghp)) = sendfd;
156        LOGD("cmsg data=%d", *((int *) CMSG_DATA(cmsghp)));
157      } else {
158        LOGD("ctrl msg NULL");
159        return -1;
160      }
161    }
162
163    return sendmsg(fd, &(msgh), 0);
164}
165
166/*===========================================================================
167 * FUNCTION   : mm_camera_socket_bundle_sendmsg
168 *
169 * DESCRIPTION:  send msg through domain socket
170 *   @fd      : socket fd
171 *   @msg     : pointer to msg to be sent over domain socket
172 *   @sendfds : file descriptors to be sent
173 *   @numfds  : num of file descriptors to be sent
174 *
175 * RETURN     : the total bytes of sent msg
176 *==========================================================================*/
177int mm_camera_socket_bundle_sendmsg(
178  int fd,
179  void *msg,
180  size_t buf_size,
181  int sendfds[CAM_MAX_NUM_BUFS_PER_STREAM],
182  int numfds)
183{
184    struct msghdr msgh;
185    struct iovec iov[1];
186    struct cmsghdr * cmsghp = NULL;
187    char control[CMSG_SPACE(sizeof(int) * numfds)];
188    int *fds_ptr = NULL;
189
190    if (msg == NULL) {
191      LOGD("msg is NULL");
192      return -1;
193    }
194    memset(&msgh, 0, sizeof(msgh));
195    msgh.msg_name = NULL;
196    msgh.msg_namelen = 0;
197
198    iov[0].iov_base = msg;
199    iov[0].iov_len = buf_size;
200    msgh.msg_iov = iov;
201    msgh.msg_iovlen = 1;
202    LOGD("iov_len=%llu",
203            (unsigned long long int)iov[0].iov_len);
204
205    msgh.msg_control = NULL;
206    msgh.msg_controllen = 0;
207
208    /* if numfds is valid, we need to pass it through control msg */
209    if (numfds > 0) {
210      msgh.msg_control = control;
211      msgh.msg_controllen = sizeof(control);
212      cmsghp = CMSG_FIRSTHDR(&msgh);
213      if (cmsghp != NULL) {
214        cmsghp->cmsg_level = SOL_SOCKET;
215        cmsghp->cmsg_type = SCM_RIGHTS;
216        cmsghp->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
217
218        fds_ptr = (int*) CMSG_DATA(cmsghp);
219        memcpy(fds_ptr, sendfds, sizeof(int) * numfds);
220      } else {
221        LOGE("ctrl msg NULL");
222        return -1;
223      }
224    }
225
226    return sendmsg(fd, &(msgh), 0);
227}
228
229/*===========================================================================
230 * FUNCTION   : mm_camera_socket_recvmsg
231 *
232 * DESCRIPTION:  receive msg from domain socket.
233 *   @fd      : socket fd
234 *   @msg     : pointer to mm_camera_sock_msg_packet_t to hold incoming msg,
235 *              need be allocated by the caller
236 *   @buf_size: the size of the buf that holds incoming msg
237 *   @rcvdfd  : pointer to hold recvd file descriptor if not NULL.
238 *
239 * RETURN     : the total bytes of received msg
240 *==========================================================================*/
241int mm_camera_socket_recvmsg(
242  int fd,
243  void *msg,
244  uint32_t buf_size,
245  int *rcvdfd)
246{
247    struct msghdr msgh;
248    struct iovec iov[1];
249    struct cmsghdr *cmsghp = NULL;
250    char control[CMSG_SPACE(sizeof(int))];
251    int rcvd_fd = -1;
252    int rcvd_len = 0;
253
254    if ( (msg == NULL) || (buf_size <= 0) ) {
255      LOGE("msg buf is NULL");
256      return -1;
257    }
258
259    memset(&msgh, 0, sizeof(msgh));
260    msgh.msg_name = NULL;
261    msgh.msg_namelen = 0;
262    msgh.msg_control = control;
263    msgh.msg_controllen = sizeof(control);
264
265    iov[0].iov_base = msg;
266    iov[0].iov_len = buf_size;
267    msgh.msg_iov = iov;
268    msgh.msg_iovlen = 1;
269
270    if ( (rcvd_len = recvmsg(fd, &(msgh), 0)) <= 0) {
271      LOGE("recvmsg failed");
272      return rcvd_len;
273    }
274
275    LOGD("msg_ctrl %p len %zd", msgh.msg_control,
276        msgh.msg_controllen);
277
278    if( ((cmsghp = CMSG_FIRSTHDR(&msgh)) != NULL) &&
279        (cmsghp->cmsg_len == CMSG_LEN(sizeof(int))) ) {
280      if (cmsghp->cmsg_level == SOL_SOCKET &&
281        cmsghp->cmsg_type == SCM_RIGHTS) {
282        LOGD("CtrlMsg is valid");
283        rcvd_fd = *((int *) CMSG_DATA(cmsghp));
284        LOGD("Receieved fd=%d", rcvd_fd);
285      } else {
286        LOGE("Unexpected Control Msg. Line=%d");
287      }
288    }
289
290    if (rcvdfd) {
291      *rcvdfd = rcvd_fd;
292    }
293
294    return rcvd_len;
295}
296