1 /*
2 OWFS -- One-Wire filesystem
3 OWHTTPD -- One-Wire Web Server
4 Written 2003 Paul H Alfille
5 email: paul.alfille@gmail.com
6 Released under the GPL
7 See the header file: ow.h for full attribution
8 1wire/iButton system from Dallas Semiconductor
9 */
10
11 /* ow_server talks to the server, sending and recieving messages */
12 /* this is an alternative to direct bus communication */
13
14 #include "owshell.h"
15
16 static int FromServer(int file_descriptor, struct client_msg *cm, char *msg, size_t size);
17 static void *FromServerAlloc(int file_descriptor, struct client_msg *cm);
18 static int ToServer(int file_descriptor, struct server_msg *sm, struct serverpackage *sp);
19 static uint32_t SetupSemi(void);
20 static void Write( char * buffer, int length ) ;
21
Server_detect(void)22 void Server_detect(void)
23 {
24 if (count_inbound_connections == 0) {
25 PRINT_ERROR("No owserver_connection defined\n");
26 errno = ENOENT ;
27 Exit(2);
28 }
29 if (owserver_connection->name == NULL || ClientAddr(owserver_connection->name)) {
30 PRINT_ERROR("Could not connect with owserver %s\n", owserver_connection->name);
31 errno = ENOENT ;
32 Exit(2);
33 }
34 }
35
ServerRead(ASCII * path)36 int ServerRead(ASCII * path)
37 {
38 struct server_msg sm;
39 struct client_msg cm;
40 struct serverpackage sp = { path, NULL, 0, NULL, 0, };
41 int connectfd = ClientConnect();
42 int size = 65536;
43 char buf[size + 1];
44 int ret = 0;
45
46 if (connectfd < 0) {
47 return -EIO;
48 }
49 //printf("Read <%s>\n",path);
50 memset(&sm, 0, sizeof(struct server_msg));
51 memset(&cm, 0, sizeof(struct client_msg));
52 sm.type = msg_read;
53 sm.size = size;
54 sm.offset = offset_into_data;
55
56 if ( size_of_data >=0 && size_of_data <= 65536 ) {
57 sm.size = size_of_data ;
58 }
59
60 if (ToServer(connectfd, &sm, &sp)) {
61 PRINT_ERROR("ServerRead: Error sending request for %s\n", path);
62 ret = -EIO;
63 } else if (FromServer(connectfd, &cm, buf, size) < 0) {
64 PRINT_ERROR("ServerRead: Error receiving data on %s\n", path);
65 ret = -EIO;
66 } else {
67 ret = cm.ret;
68 if (ret < 0 || ret > size ) {
69 PRINT_ERROR("ServerRead: Data error on %s\n", path);
70 } else {
71 Write( buf, ret ) ;
72 }
73 }
74 close(connectfd);
75 return ret;
76 }
77
ServerWrite(ASCII * path,ASCII * data,int size)78 int ServerWrite(ASCII * path, ASCII * data, int size)
79 {
80 struct server_msg sm;
81 struct client_msg cm;
82 struct serverpackage sp = { path, (BYTE *) data, size, NULL, 0, };
83 int connectfd = ClientConnect();
84 int ret = 0;
85
86 if (connectfd < 0) {
87 return -EIO;
88 }
89 //printf("Write <%s> <%s>\n",path,data);
90 memset(&sm, 0, sizeof(struct server_msg));
91 sm.type = msg_write;
92 sm.size = size;
93 sm.offset = offset_into_data;
94
95 if (ToServer(connectfd, &sm, &sp)) {
96 ret = -EIO;
97 } else if (FromServer(connectfd, &cm, NULL, 0) < 0) {
98 ret = -EIO;
99 } else {
100 ret = cm.ret;
101 }
102 close(connectfd);
103 return ret;
104 }
105
ServerDirall(ASCII * path)106 int ServerDirall(ASCII * path)
107 {
108 struct server_msg sm;
109 struct client_msg cm;
110 struct serverpackage sp = { path, NULL, 0, NULL, 0, };
111 char *path2;
112 int connectfd = ClientConnect();
113
114 if (connectfd < 0) {
115 return -EIO;
116 }
117 //printf("DirALL <%s>\n",path ) ;
118
119 memset(&sm, 0, sizeof(struct server_msg));
120 sm.type = slashflag ? msg_dirallslash : msg_dirall;
121
122 if (ToServer(connectfd, &sm, &sp)) {
123 cm.ret = -EIO;
124 } else if ((path2 = FromServerAlloc(connectfd, &cm))) {
125 char *p;
126 path2[cm.payload - 1] = '\0'; /* Ensure trailing null */
127 for (p = path2; *p; ++p)
128 if (*p == ',')
129 *p = '\n';
130 printf("%s\n", path2);
131 free(path2);
132 }
133 close(connectfd);
134 return cm.ret;
135 }
136
ServerDir(ASCII * path)137 int ServerDir(ASCII * path)
138 {
139 struct server_msg sm;
140 struct client_msg cm;
141 struct serverpackage sp = { path, NULL, 0, NULL, 0, };
142 int connectfd = ClientConnect();
143
144 if (connectfd < 0) {
145 return -EIO;
146 }
147 //printf("Dir <%s>\n", path ) ;
148
149 memset(&sm, 0, sizeof(struct server_msg));
150 sm.type = msg_dir;
151
152 if (ToServer(connectfd, &sm, &sp)) {
153 cm.ret = -EIO;
154 } else {
155 char *path2;
156 while ((path2 = FromServerAlloc(connectfd, &cm))) {
157 path2[cm.payload - 1] = '\0'; /* Ensure trailing null */
158 printf("%s\n", path2);
159 free(path2);
160 }
161 }
162 close(connectfd);
163 return cm.ret;
164 }
165
ServerPresence(ASCII * path)166 int ServerPresence(ASCII * path)
167 {
168 struct server_msg sm;
169 struct client_msg cm;
170 struct serverpackage sp = { path, NULL, 0, NULL, 0, };
171 int connectfd = ClientConnect();
172 int ret = 0;
173
174 if (connectfd < 0) {
175 return -EIO;
176 }
177 //printf("Presence <%s>\n",path);
178 memset(&sm, 0, sizeof(struct server_msg));
179 sm.type = msg_presence;
180
181 if (ToServer(connectfd, &sm, &sp)) {
182 ret = -EIO;
183 } else if (FromServer(connectfd, &cm, NULL, 0) < 0) {
184 ret = -EIO;
185 } else {
186 ret = cm.ret;
187 }
188 close(connectfd);
189 printf((ret >= 0) ? "1" : "0");
190 return ret;
191 }
192
193 /* read from server, free return pointer if not Null */
FromServerAlloc(int file_descriptor,struct client_msg * cm)194 static void *FromServerAlloc(int file_descriptor, struct client_msg *cm)
195 {
196 char *msg;
197 int ret;
198 struct timeval tv = { Globals.timeout_network + 1, 0, };
199
200 do { /* loop until non delay message (payload>=0) */
201 //printf("OW_SERVER loop1\n");
202 ret = tcp_read(file_descriptor, cm, sizeof(struct client_msg), &tv);
203 if (ret != sizeof(struct client_msg)) {
204 memset(cm, 0, sizeof(struct client_msg));
205 cm->ret = -EIO;
206 return NULL;
207 }
208 cm->payload = ntohl(cm->payload);
209 cm->size = ntohl(cm->size);
210 cm->ret = ntohl(cm->ret);
211 cm->sg = ntohl(cm->sg);
212 cm->offset = ntohl(cm->offset);
213 } while (cm->payload < 0);
214
215 //printf("FromServerAlloc payload=%d size=%d ret=%d sg=%X offset=%d\n",cm->payload,cm->size,cm->ret,cm->sg,cm->offset);
216 //printf(">%.4d|%.4d\n",cm->ret,cm->payload);
217 if (cm->payload == 0)
218 return NULL;
219 if (cm->ret < 0)
220 return NULL;
221 if (cm->payload > MAX_OWSERVER_PROTOCOL_PAYLOAD_SIZE) {
222 //printf("FromServerAlloc payload too large\n");
223 return NULL;
224 }
225
226 if ((msg = (char *) malloc((size_t) cm->payload))) {
227 ret = tcp_read(file_descriptor, msg, (size_t) (cm->payload), &tv);
228 if (ret != cm->payload) {
229 //printf("FromServer couldn't read payload\n");
230 cm->payload = 0;
231 cm->offset = 0;
232 cm->ret = -EIO;
233 free(msg);
234 msg = NULL;
235 }
236 //printf("FromServer payload read ok\n");
237 }
238 return msg;
239 }
240
241 /* Read from server -- return negative on error,
242 return 0 or positive giving size of data element */
FromServer(int file_descriptor,struct client_msg * cm,char * msg,size_t size)243 static int FromServer(int file_descriptor, struct client_msg *cm, char *msg, size_t size)
244 {
245 size_t rtry;
246 size_t ret;
247 struct timeval tv = { Globals.timeout_network + 1, 0, };
248
249 do { // read regular header, or delay (delay when payload<0)
250 //printf("OW_SERVER loop2\n");
251 ret = tcp_read(file_descriptor, cm, sizeof(struct client_msg), &tv);
252 if (ret != sizeof(struct client_msg)) {
253 //printf("OW_SERVER loop2 bad\n");
254 cm->size = 0;
255 cm->ret = -EIO;
256 return -EIO;
257 }
258
259 cm->payload = ntohl(cm->payload);
260 cm->size = ntohl(cm->size);
261 cm->ret = ntohl(cm->ret);
262 cm->sg = ntohl(cm->sg);
263 cm->offset = ntohl(cm->offset);
264 } while (cm->payload < 0); // flag to show a delay message
265 //printf("OW_SERVER loop2 done\n");
266
267 //printf("FromServer payload=%d size=%d ret=%d sg=%d offset=%d\n",cm->payload,cm->size,cm->ret,cm->sg,cm->offset);
268 //printf(">%.4d|%.4d\n",cm->ret,cm->payload);
269 if (cm->payload == 0)
270 return 0; // No payload, done.
271
272 rtry = cm->payload < (ssize_t) size ? (size_t) cm->payload : size;
273 ret = tcp_read(file_descriptor, msg, rtry, &tv); // read expected payload now.
274 if (ret != rtry) {
275 cm->ret = -EIO;
276 return -EIO;
277 }
278
279 if (cm->payload > (ssize_t) size) { // Uh oh. payload bigger than expected. read it in and discard
280 size_t d = cm->payload - size;
281 char extra[d];
282 ret = tcp_read(file_descriptor, extra, d, &tv);
283 if (ret != d) {
284 cm->ret = -EIO;
285 return -EIO;
286 }
287 return size;
288 }
289 return cm->payload;
290 }
291
292 // should be const char * data but iovec has problems with const arguments
ToServer(int file_descriptor,struct server_msg * sm,struct serverpackage * sp)293 static int ToServer(int file_descriptor, struct server_msg *sm, struct serverpackage *sp)
294 {
295 int payload = 0;
296 int nio = 0;
297 struct iovec io[5] = { {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0}, };
298
299 // Set up flags
300 sm->sg = SetupSemi() ;
301
302 // First block to send, the header
303 io[nio].iov_base = sm;
304 io[nio].iov_len = sizeof(struct server_msg);
305 nio++;
306
307 // Next block, the path
308 if ((io[nio].iov_base = sp->path)) { // send path (if not null)
309 io[nio].iov_len = payload = strlen(sp->path) + 1;
310 nio++;
311 //printf("ToServer path=%s\n", sp->path);
312 }
313
314 // next block, data (only for writes)
315 if ((sp->datasize>0) && (io[nio].iov_base = sp->data)) { // send data only for writes (if datasize not zero)
316 payload += (io[nio].iov_len = sp->datasize);
317 nio++;
318 //LEVEL_DEBUG("ToServer data=%s\n", sp->data);
319 }
320
321 sp->tokens = 0;
322 sm->version = 0; // shouldn't this be MakeServerprotocol(OWSERVER_PROTOCOL_VERSION);
323
324 //printf("ToServer payload=%d size=%d type=%d tempscale=%X offset=%d\n",payload,sm->size,sm->type,sm->sg,sm->offset);
325 //printf("<%.4d|%.4d\n",sm->type,payload);
326
327 // encode in network order (just the header)
328 sm->version = htonl(sm->version);
329 sm->payload = htonl(payload);
330 sm->size = htonl(sm->size);
331 sm->type = htonl(sm->type);
332 sm->sg = htonl(sm->sg);
333 sm->offset = htonl(sm->offset);
334
335 //Debug_Writev(io, nio);
336 return writev(file_descriptor, io, nio) != (ssize_t) (payload + sizeof(struct server_msg) + sp->tokens * sizeof(struct antiloop));
337 }
338
339 /* flag the sg for "virtual root" -- the remote bus was specifically requested */
340 /* Also ALIAS_REQUEST means that aliases will be applied */
SetupSemi(void)341 static uint32_t SetupSemi(void)
342 {
343 uint32_t sg = SHOULD_RETURN_BUS_LIST ;
344
345 // Device format
346 sg |= (device_format) << DEVFORMAT_BIT ;
347 // Pressure scale
348 sg |= (pressure_scale) << PRESSURESCALE_BIT ;
349 // Temperature scale
350 sg |= (temperature_scale) << TEMPSCALE_BIT ;
351 // Uncached
352 sg |= uncached ? UNCACHED : 0 ;
353 // Unaliased
354 sg |= unaliased ? 0 : ALIAS_REQUEST ;
355 // Trim
356 sg |= trim ? TRIM : 0 ;
357 // OWNet flag or Presence check
358 sg |= OWNET ;
359
360 return sg;
361 }
362
Write(char * buffer,int length)363 static void Write( char * buffer, int length)
364 {
365 int i ;
366 char *fmt;
367
368 /*
369 * Write binary (raw) or hex-formatted ASCII depending on
370 * the value of "hexflag" (set through the CLI argument
371 * --hex).
372 */
373 fmt = hexflag ? "%.2X" : "%c";
374
375 for ( i=0 ; i<length ; ++i ) {
376 printf( fmt, (unsigned char) buffer[i]);
377 }
378 }
379