1 /*
2 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
3 *
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
35 #include <string.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <malloc.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
43 #include "sockutils.h"
45 #define error_msg printf
47 typedef struct sock_data {
48 struct sockaddr_un addr;
49 fd_set readfds;
50 int fd;
51 } sock_data_t;
53 int check_and_create_path (char *path)
54 {
55 char *d = path;
56 if (!d)
57 return -1;
59 while ((d = strchr(d + 1, '/'))) {
60 *d = 0;
61 if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
62 if (errno != EEXIST) {
63 *d = '/';
64 error_msg("can't create path %s (error: %s)",
65 path, strerror(errno));
66 return -1;
67 }
68 }
69 *d = '/';
70 }
71 return 0;
72 }
74 sock_h sock_open (sock_name_t *sock_name)
75 {
76 sock_data_t *sd = 0;
77 int retval = 0;
79 if (!sock_name) {
80 return 0;
81 }
83 sd = calloc (1, sizeof(sock_data_t));
85 if (sock_name->type == sock_addr_e) {
86 memcpy (&sd->addr, sock_name->s.addr, sizeof(struct sockaddr_un));
87 } else {
88 if (check_and_create_path(sock_name->s.name) < 0) {
89 goto check_n_return;
90 }
91 sd->addr.sun_family = AF_UNIX;
92 strncpy(sd->addr.sun_path, sock_name->s.name, UNIX_PATH_MAX);
93 }
95 sd->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
96 if (sd->fd < 0) {
97 error_msg("can't open socket %s (error: %s)",
98 sd->addr.sun_path, strerror(errno));
99 goto check_n_return;
100 }
102 unlink(sd->addr.sun_path);
103 if (bind(sd->fd, (struct sockaddr *) &sd->addr, sizeof(struct sockaddr_un)) < 0) {
104 error_msg("can't bind socket %s (error: %s)",
105 sd->addr.sun_path, strerror(errno));
106 goto check_n_return;
107 }
109 FD_ZERO(&sd->readfds);
110 FD_SET(sd->fd, &sd->readfds);
112 retval = (int) sd;
114 check_n_return:
115 if (!retval) {
116 sock_close ((sock_h) &sd);
117 }
119 return ((sock_h) retval);
120 }
122 int sock_close (sock_h handle)
123 {
124 sock_data_t *sd = (sock_data_t *) handle;
126 if (!sd) {
127 return -1;
128 }
130 if (sd->fd)
131 close (sd->fd);
132 free (sd);
134 return 0;
135 }
137 int sock_send (sock_h handle, const char *data, int length,
138 sock_name_t *to)
139 {
140 int fd;
141 sock_data_t *sd = (sock_data_t *) handle;
142 struct sockaddr_un to_addr;
144 if (!to) {
145 return -1;
146 }
148 if (to->type == sock_addr_e) {
149 memcpy (&to_addr, to->s.addr, sizeof(struct sockaddr_un));
150 } else {
151 to_addr.sun_family = AF_UNIX;
152 strncpy(to_addr.sun_path, to->s.name, UNIX_PATH_MAX);
153 }
155 if (sd) {
156 fd = sd->fd;
157 } else {
158 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
159 if (fd < 0) {
160 error_msg("can't open socket %s (error: %s)",
161 to_addr.sun_path, strerror(errno));
162 return -1;
163 }
164 }
166 if (sendto (fd, data, length, 0, (struct sockaddr *) &to_addr,
167 sizeof(struct sockaddr_un)) < 0) {
168 error_msg("can't send data to %s (error: %s)",
169 to_addr.sun_path, strerror(errno));
170 return -1;
172 }
174 if (!sd) {
175 close(fd);
176 }
178 return 0;
179 }
181 int sock_wait (sock_h handle, int *size, struct timeval *timeout, int extern_fd)
182 {
183 sock_data_t *sd = (sock_data_t *) handle;
184 int retval;
185 fd_set fds;
187 if (!sd) {
188 error_msg("invalid hanlde");
189 return -1;
190 }
192 fds = sd->readfds;
194 if (extern_fd != -1) {
195 FD_SET(extern_fd, &fds);
196 }
198 retval = select(FD_SETSIZE, &fds, NULL, NULL, timeout);
199 if (retval == -1) {
200 error_msg("select failed for %s (error: %s)",
201 sd->addr.sun_path, strerror(errno));
202 return -1;
203 }
205 if ((extern_fd != -1) && (FD_ISSET(extern_fd, &fds))) {
206 return 1;
207 }
209 if (!FD_ISSET(sd->fd, &fds)) {
210 /* Wait timedout */
211 return -2;
212 }
214 if (!retval) {
215 return 0;
216 }
218 if (size != 0) {
219 retval = ioctl(sd->fd, FIONREAD, size);
220 if (retval == -1) {
221 error_msg("can't read datagram size for %s (error: %s)",
222 sd->addr.sun_path, strerror(errno));
223 return -1;
224 }
225 }
227 return 0;
228 }
230 int sock_recv (sock_h handle, char *data, int length, sock_name_t *from)
231 {
232 int size;
233 sock_data_t *sd = (sock_data_t *) handle;
234 socklen_t from_length = 0;
236 if (!sd) {
237 error_msg("invalid hanlde");
238 return -1;
239 }
241 if (from) {
242 if((from->type == sock_addr_e) && (from->s.addr))
243 from_length = sizeof(struct sockaddr_un);
244 else {
245 error_msg("invalid from parameter");
246 return -1;
247 }
248 }
250 size = recvfrom(sd->fd, data, length, 0, (struct sockaddr *)((from_length) ? from->s.addr : NULL), &from_length);
251 if (size < 1) {
252 error_msg("can't read datagram from socket for %s (error: %s), size %d",
253 sd->addr.sun_path, strerror(errno), size);
254 return -1;
255 }
257 return size;
259 }