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