liblightify
socket.c
Go to the documentation of this file.
1 /*
2  liblightify -- library to control OSRAM's LIGHTIFY
3 
4 Copyright (c) 2015, Tobias Frost <tobi@coldtobi.de>
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in the
13  documentation and/or other materials provided with the distribution.
14  * Neither the name of the author nor the
15  names of its contributors may be used to endorse or promote products
16  derived from this software without specific prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include "liblightify-private.h"
35 
36 #include "socket.h"
37 #include "context.h"
38 
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 
45 int write_to_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size) {
46 
47  int n;
48  int fd = lightify_skt_getfd(ctx);
49  if (fd < 0) return -EINVAL;
50  size_t m = size; /*<< current position */
51  struct timeval to;
52 
53 #ifdef ENABLE_DEBUG_MSGS
54  unsigned char *msg_ = msg;
55 #endif
56 
57  do {
58  n = write(fd, msg, m);
59  if (n < 0) {
60  if (EINTR == errno ) continue;
61  if (errno != EWOULDBLOCK && errno != EAGAIN) return -errno;
62  }
63  m -= n;
64  msg += n;
65  if (m) {
66  /* check if O_NONBLOCK is set; in this case we retry */
67  n = fcntl(fd, F_GETFL, 0);
68  if (-1 == n) return -errno;
69  if (0 == (n & O_NONBLOCK)) {
70  /* short write. return what we've got done */
71  dbg(ctx, "Short write: %d bytes written instead of %d\n", (int)(size - m), (int)size);
72  break;
73  }
74  /* non-blocking I/O confirmed -- setup timeout and retry when socket is ready */
75  to = lightify_skt_getiotimeout(ctx);
76  fd_set myset;
77  FD_ZERO(&myset);
78  FD_SET(fd, &myset);
79  n = select(fd, NULL, &myset, NULL, &to);
80  /* fd became ready to accept new bytes. */
81  if (n > 0) continue;
82  /* error handling :EINTR means repeat. */
83  if (n < 0 && errno == EINTR) continue;
84  /* all other errors: return what we've got or the error if we didn't */
85  if (n < 0 && m == size) return -errno;
86  if (n < 0) {
87  dbg(ctx, "Write error %d: %d bytes written, instead of %d\n", -errno, (int)(size-m), (int)size);
88  break;
89  }
90  /* no byte read at all -- timeout. */
91  if (n == 0 && m == size) {
92  /* could not write ANY byte. */
93  return -ETIMEDOUT;
94  }
95  /* timeout on partial write */
96  dbg(ctx, "Short write (timeout): %d bytes written instead of %d\n", (int)(size-m), (int) size);
97  break;
98  }
99  } while (m);
100 
101 #ifdef ENABLE_DEBUG_MSGS
102  if (lightify_get_log_priority(ctx) >= LOG_DEBUG) {
103  unsigned int j = 0, k;
104  char buf[80];
105  buf[0] = 0;
106 
107  for (k = 0; k < size; k++, j++) {
108  if (8 == j) {
109  dbg(ctx,"> %s\n",buf);
110  buf[0] = 0;
111  j = 0;
112  }
113  sprintf(buf + strlen(buf), " 0x%02x,", msg_[k]);
114  }
115  dbg(ctx,"> %s\n",buf);
116  }
117 #endif
118  return size-m;
119 }
120 
121 int read_from_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size ) {
122 
123  int n;
124  int i;
125  int fd = lightify_skt_getfd(ctx);
126  if (fd < 0) return -EINVAL;
127  size_t m = size;
128  struct timeval to;
129 
130 #ifdef ENABLE_DEBUG_MSGS
131  unsigned char *msg_ = msg;
132 #endif
133 
134  do {
135  n = read(fd, msg, m);
136  if (n == -1) {
137  if(errno == EINTR) continue;
138  if(errno != EWOULDBLOCK && errno != EAGAIN) return -errno;
139  }
140  // EOF
141  if (n == 0) return size-m;
142 
143  m -= n;
144  msg += n;
145 
146  if (m) {
147  /* check if O_NONBLOCK is set; in this case we retry */
148  n = fcntl(fd, F_GETFL, 0);
149  if (-1 == n) return -errno;
150  if (0 == (n & O_NONBLOCK)) {
151  /* short read. return what we've got done */
152  dbg(ctx, "Short read: %d instead of %d\n", (int)(size-m), (int) size);
153  break; /* break out for debug message logging. */
154  }
155  to = lightify_skt_getiotimeout(ctx);
156  fd_set myset;
157  FD_ZERO(&myset);
158  FD_SET(fd, &myset);
159  i = select(fd, &myset, NULL, NULL, &to);
160  /* fd is now ready to be read */
161  if (i > 0) continue;
162  /* error handling: Execpt interrupted system calls means we return the error */
163  if (i < 0 && errno == EINTR) continue;
164  /* return error if we did not get any byte */
165  if (i < 0 && m == size) return -errno;
166  /* return what we've got, even despite the error */
167  if (i < 0) {
168  dbg(ctx, "Read error %d: %d bytes read, instead of %d\n", -errno, (int)(size-m), (int)size);
169  break;
170  }
171  /* if no fd became ready, and we never saw a byte, we'll bail out with timeout */
172  if (i == 0 && m == size) {
173  return -ETIMEDOUT;
174  }
175  /* partial read and timeout: return what we've got so far.
176  This will be handled by the remaining code, so we just leave a message before
177  doing so.*/
178  dbg(ctx, "Short read (timeout): %d instead of %d\n", (int)(size-m), (int)size);
179  break;
180  }
181  } while (m);
182 
183 #ifdef ENABLE_DEBUG_MSGS
184  if (lightify_get_log_priority(ctx) >= LOG_DEBUG) {
185  unsigned int j = 0, k;
186  char buf[80];
187  buf[0] = 0;
188 
189  for (k = 0; k < size-m; k++, j++) {
190  if (8 == j) {
191  dbg(ctx,"< %s\n",buf);
192  buf[0] = 0;
193  j = 0;
194  }
195  sprintf(buf + strlen(buf), " 0x%02x,", msg_[k]);
196  }
197  dbg(ctx,"< %s\n",buf);
198  }
199 #endif
200 
201  return size-m;
202 }
203 
204 LIGHTIFY_EXPORT int lightify_skt_setfd(struct lightify_ctx *ctx, int socket) {
205  if (!ctx) return -EINVAL;
206  ctx->socket = socket;
207  return 0;
208 }
209 
211  if (!ctx) return -EINVAL;
212  return ctx->socket;
213 }
214 
215 LIGHTIFY_EXPORT int lightify_skt_setiotimeout(struct lightify_ctx *ctx, struct timeval tv) {
216  if (!ctx) return -EINVAL;
217  ctx->iotimeout = tv;
218  return 0;
219 }
220 
222  if (!ctx) {
223  struct timeval tv;
224  tv.tv_sec = 0;
225  tv.tv_usec = 0;
226  return tv;
227  }
228  return ctx->iotimeout;
229 }
lightify_skt_setfd
LIGHTIFY_EXPORT int lightify_skt_setfd(struct lightify_ctx *ctx, int socket)
Definition: socket.c:204
lightify_skt_setiotimeout
LIGHTIFY_EXPORT int lightify_skt_setiotimeout(struct lightify_ctx *ctx, struct timeval tv)
Definition: socket.c:215
lightify_get_log_priority
int lightify_get_log_priority(struct lightify_ctx *ctx)
Definition: log.c:99
LIGHTIFY_EXPORT
#define LIGHTIFY_EXPORT
write_to_socket
int write_to_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size)
Definition: socket.c:45
lightify_ctx::iotimeout
struct timeval iotimeout
Definition: context.h:99
lightify_node::ctx
struct lightify_ctx * ctx
Definition: node.c:46
dbg
#define dbg(ctx, arg...)
lightify_skt_getiotimeout
LIGHTIFY_EXPORT struct timeval lightify_skt_getiotimeout(struct lightify_ctx *ctx)
Definition: socket.c:221
lightify_ctx::socket
int socket
Definition: context.h:87
lightify_ctx
Definition: context.h:68
lightify_skt_getfd
LIGHTIFY_EXPORT int lightify_skt_getfd(struct lightify_ctx *ctx)
Definition: socket.c:210
read_from_socket
int read_from_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size)
Definition: socket.c:121
socket.h
context.h
liblightify-private.h