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 #define ENABLE_DEBUG
35 
36 #include "liblightify-private.h"
37 
38 #include "socket.h"
39 #include "context.h"
40 
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 int write_to_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size) {
48 
49  int n;
50  int fd = lightify_skt_getfd(ctx);
51  if (fd < 0) return -EINVAL;
52  size_t m = size; /*<< current position */
53  struct timeval to;
54 
55 #ifdef ENABLE_DEBUG
56  unsigned char *msg_ = msg;
57 #endif
58 
59  do {
60  n = write(fd, msg, m);
61  if (n < 0) {
62  if (EINTR == errno ) continue;
63  if (errno != EWOULDBLOCK && errno != EAGAIN) return -errno;
64  }
65  m -= n;
66  msg += n;
67  if (m) {
68  /* check if O_NONBLOCK is set; in this case we retry */
69  n = fcntl(fd, F_GETFL, 0);
70  if (-1 == n) return -errno;
71  if (0 == (n & O_NONBLOCK)) {
72  /* short write. return what we've got done */
73  dbg(ctx, "Short write: %d bytes written instead of %d", (int)(size - m), (int)size);
74  break;
75  }
76  /* non-blocking I/O confirmed -- setup timeout and retry when socket is ready */
77  to = lightify_skt_getiotimeout(ctx);
78  fd_set myset;
79  FD_ZERO(&myset);
80  FD_SET(fd, &myset);
81  n = select(fd, NULL, &myset, NULL, &to);
82  /* fd became ready to accept new bytes. */
83  if (m > 0) continue;
84  /* error handling :EINTR means repeat. */
85  if (n < 0 && errno == EINTR) continue;
86  /* all other errors: return what we've got or the error if we didn't */
87  if (n < 0 && m == size) return -errno;
88  if (n < 0) {
89  dbg(ctx, "Write error %d: %d bytes written, instead of %d", -errno, (int)(size-m), (int)size);
90  break;
91  }
92  /* no byte read at all -- timeout. */
93  if (n == 0 && m == size) {
94  /* could not write ANY byte. */
95  return -ETIMEDOUT;
96  }
97  /* timeout on partial write */
98  dbg(ctx, "Short write (timeout): %d bytes written instead of %d", (int)(size-m), (int) size);
99  break;
100  }
101  } while (m);
102 
103 #ifdef ENABLE_DEBUG
104  if (lightify_get_log_priority(ctx) >= LOG_DEBUG) {
105  unsigned int j = 0, k;
106  char buf[80];
107  buf[0] = 0;
108 
109  for (k = 0; k < size; k++, j++) {
110  if (8 == j) {
111  dbg(ctx,"> %s\n",buf);
112  buf[0] = 0;
113  j = 0;
114  }
115  sprintf(buf + strlen(buf), " 0x%02x,", msg_[k]);
116  }
117  dbg(ctx,"> %s\n",buf);
118  }
119 #endif
120  return size-m;
121 }
122 
123 int read_from_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size ) {
124 
125  int n;
126  int i;
127  int fd = lightify_skt_getfd(ctx);
128  if (fd < 0) return -EINVAL;
129  size_t m = size;
130  struct timeval to;
131 
132 #ifdef ENABLE_DEBUG
133  unsigned char *msg_ = msg;
134 #endif
135 
136  do {
137  n = read(fd, msg, m);
138  if (n == -1) {
139  if(errno == EINTR) continue;
140  if(errno != EWOULDBLOCK && errno != EAGAIN) return -errno;
141  }
142  // EOF
143  if (n == 0) return size-m;
144 
145  m -= n;
146  msg += n;
147 
148  if (m) {
149  /* check if O_NONBLOCK is set; in this case we retry */
150  n = fcntl(fd, F_GETFL, 0);
151  if (-1 == n) return -errno;
152  if (0 == (n & O_NONBLOCK)) {
153  /* short read. return what we've got done */
154  dbg(ctx, "Short read: %d instead of %d", (int)(size-m), (int) size);
155  break; /* break out for debug message logging. */
156  }
157  to = lightify_skt_getiotimeout(ctx);
158  fd_set myset;
159  FD_ZERO(&myset);
160  FD_SET(fd, &myset);
161  i = select(fd, &myset, NULL, NULL, &to);
162  /* fd is now ready to be read */
163  if (i > 0) continue;
164  /* error handling: Execpt interrupted system calls means we return the error */
165  if (i < 0 && errno == EINTR) continue;
166  /* return error if we did not get any byte */
167  if (i < 0 && m == size) return -errno;
168  /* return what we've got, even despite the error */
169  if (i < 0) {
170  dbg(ctx, "Read error %d: %d bytes read, instead of %d", -errno, (int)(size-m), (int)size);
171  break;
172  }
173  /* if no fd became ready, and we never saw a byte, we'll bail out with timeout */
174  if (i == 0 && m == size) {
175  return -ETIMEDOUT;
176  }
177  /* partial read and timeout: return what we've got so far.
178  This will be handled by the remaining code, so we just leave a message before
179  doing so.*/
180  dbg(ctx, "Short read (timeout): %d instead of %d", (int)(size-m), (int)size);
181  break;
182  }
183  } while (m);
184 
185 #ifdef ENABLE_DEBUG
186  if (lightify_get_log_priority(ctx) >= LOG_DEBUG) {
187  unsigned int j = 0, k;
188  char buf[80];
189  buf[0] = 0;
190 
191  for (k = 0; k < size-m; k++, j++) {
192  if (8 == j) {
193  dbg(ctx,"< %s\n",buf);
194  buf[0] = 0;
195  }
196  j = 0;
197  sprintf(buf + strlen(buf), " 0x%02x,", msg_[k]);
198  }
199  dbg(ctx,"< %s\n",buf);
200  }
201 #endif
202 
203  return size-m;
204 }
205 
206 LIGHTIFY_EXPORT int lightify_skt_setfd(struct lightify_ctx *ctx, int socket) {
207  if (!ctx) return -EINVAL;
208  ctx->socket = socket;
209  return 0;
210 }
211 
213  if (!ctx) return -EINVAL;
214  return ctx->socket;
215 }
216 
217 LIGHTIFY_EXPORT int lightify_skt_setiotimeout(struct lightify_ctx *ctx, struct timeval tv) {
218  if (!ctx) return -EINVAL;
219  ctx->iotimeout = tv;
220  return 0;
221 }
222 
224  if (!ctx) {
225  struct timeval tv;
226  tv.tv_sec = 0;
227  tv.tv_usec = 0;
228  return tv;
229  }
230  return ctx->iotimeout;
231 }
LIGHTIFY_EXPORT int lightify_skt_setfd(struct lightify_ctx *ctx, int socket)
Definition: socket.c:206
LIGHTIFY_EXPORT int lightify_skt_setiotimeout(struct lightify_ctx *ctx, struct timeval tv)
Definition: socket.c:217
int write_to_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size)
Definition: socket.c:47
LIGHTIFY_EXPORT int lightify_skt_getfd(struct lightify_ctx *ctx)
Definition: socket.c:212
#define dbg(ctx, arg...)
struct timeval iotimeout
Definition: context.h:94
#define LIGHTIFY_EXPORT
LIGHTIFY_EXPORT struct timeval lightify_skt_getiotimeout(struct lightify_ctx *ctx)
Definition: socket.c:223
int read_from_socket(struct lightify_ctx *ctx, unsigned char *msg, size_t size)
Definition: socket.c:123
int lightify_get_log_priority(struct lightify_ctx *ctx)
Definition: log.c:99
struct lightify_ctx * ctx
Definition: node.c:46
int socket
Definition: context.h:82