xref: /haiku/src/tests/system/network/unix_dgram_test.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2023, Trung Nguyen, trungnt282910@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <fcntl.h>
12 #include <sys/mman.h>
13 #include <sys/socket.h>
14 #include <sys/stat.h>
15 #include <sys/un.h>
16 #include <unistd.h>
17 
18 
19 #define REPORT_ERROR(msg, ...) \
20 	fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__)
21 
22 
23 int
24 connect_test()
25 {
26 	unlink("test.sock");
27 	unlink("test1.sock");
28 	unlink("test2.sock");
29 
30 	int status;
31 
32 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
33 	if (sock == -1) {
34 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
35 		return 1;
36 	}
37 
38 	struct sockaddr_un addr;
39 	addr.sun_family = AF_UNIX;
40 	strcpy(addr.sun_path, "test.sock");
41 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
42 	if (status == -1) {
43 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
44 		return 1;
45 	}
46 
47 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
48 	if (sock1 == -1) {
49 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
50 		return 1;
51 	}
52 
53 	struct sockaddr_un addr1;
54 	addr1.sun_family = AF_UNIX;
55 	strcpy(addr1.sun_path, "test1.sock");
56 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
57 	if (status == -1) {
58 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
59 		return 1;
60 	}
61 
62 	// Set non-blocking on both sockets
63 	int flags1 = fcntl(sock, F_GETFL, 0);
64 	if (flags1 == -1) {
65 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
66 		return 1;
67 	}
68 	status = fcntl(sock, F_SETFL, flags1 | O_NONBLOCK);
69 	if (status == -1) {
70 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
71 		return 1;
72 	}
73 	status = fcntl(sock1, F_SETFL, flags1 | O_NONBLOCK);
74 	if (status == -1) {
75 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
76 		return 1;
77 	}
78 
79 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
80 	if (status == -1) {
81 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
82 		return 1;
83 	}
84 
85 	// Connect in the opposite way
86 	status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr));
87 	if (status == -1) {
88 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
89 		return 1;
90 	}
91 
92 	// Reconnect a connected DGRAM socket
93 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
94 	if (status == -1) {
95 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
96 		return 1;
97 	}
98 
99 	int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0);
100 	if (sock2 == -1) {
101 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
102 		return 1;
103 	}
104 
105 	struct sockaddr_un addr2;
106 	addr2.sun_family = AF_UNIX;
107 	strcpy(addr2.sun_path, "test2.sock");
108 	status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2));
109 	if (status == -1) {
110 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
111 		return 1;
112 	}
113 
114 	// Connect to a socket that are already connected
115 	status = connect(sock2, (struct sockaddr*)&addr1, sizeof(addr1));
116 	if (status != -1) {
117 		REPORT_ERROR("connect() succeeded unexpectedly\n");
118 		return 1;
119 	}
120 	if (errno != EPERM) {
121 		REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno));
122 		return 1;
123 	}
124 
125 	status = close(sock2);
126 	if (status == -1) {
127 		REPORT_ERROR("close() failed: %s\n", strerror(errno));
128 		return 1;
129 	}
130 
131 	// Connect to a closed socket
132 	status = connect(sock, (struct sockaddr*)&addr2, sizeof(addr2));
133 	if (status != -1) {
134 		REPORT_ERROR("connect() succeeded unexpectedly\n");
135 		return 1;
136 	}
137 	if (errno != ECONNREFUSED) {
138 		REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno));
139 		return 1;
140 	}
141 
142 	close(sock);
143 	close(sock1);
144 
145 	unlink("test.sock");
146 	unlink("test1.sock");
147 	unlink("test2.sock");
148 
149 	return 0;
150 }
151 
152 
153 int
154 send_test()
155 {
156 	unlink("test.sock");
157 	unlink("test1.sock");
158 	unlink("test2.sock");
159 
160 	int status;
161 
162 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
163 	if (sock == -1) {
164 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
165 		return 1;
166 	}
167 
168 	struct sockaddr_un addr;
169 	memset(&addr, 0, sizeof(addr));
170 	addr.sun_family = AF_UNIX;
171 	strcpy(addr.sun_path, "test.sock");
172 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
173 	if (status == -1) {
174 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
175 		return 1;
176 	}
177 
178 	status = send(sock, "test", 4, 0);
179 	if (status != -1) {
180 		REPORT_ERROR("send() succeeded unexpectedly\n");
181 		return 1;
182 	}
183 	// if (errno != ENOTCONN) {
184 	// 	REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
185 	// 	return 1;
186 	// }
187 
188 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
189 	if (sock1 == -1) {
190 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
191 		return 1;
192 	}
193 
194 	struct sockaddr_un addr1;
195 	addr1.sun_family = AF_UNIX;
196 	strcpy(addr1.sun_path, "test1.sock");
197 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
198 	if (status == -1) {
199 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
200 		return 1;
201 	}
202 
203 	// Set non-blocking on both sockets
204 	status = fcntl(sock, F_SETFL, O_NONBLOCK);
205 	if (status == -1) {
206 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
207 		return 1;
208 	}
209 	status = fcntl(sock1, F_SETFL, O_NONBLOCK);
210 	if (status == -1) {
211 		REPORT_ERROR("fcntl() failed: %s\n", strerror(errno));
212 		return 1;
213 	}
214 
215 	status = sendto(sock, "test1", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1));
216 	if (status == -1) {
217 		REPORT_ERROR("sendto() failed: %s\n", strerror(errno));
218 		return 1;
219 	}
220 
221 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
222 	if (status == -1) {
223 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
224 		return 1;
225 	}
226 	status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr));
227 	if (status == -1) {
228 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
229 		return 1;
230 	}
231 
232 	status = send(sock, "test2", 5, 0);
233 	if (status == -1) {
234 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
235 		return 1;
236 	}
237 
238 	int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0);
239 	if (sock2 == -1) {
240 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
241 		return 1;
242 	}
243 
244 	struct sockaddr_un addr2;
245 	addr2.sun_family = AF_UNIX;
246 	strcpy(addr2.sun_path, "test2.sock");
247 	status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2));
248 	if (status == -1) {
249 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
250 		return 1;
251 	}
252 
253 	status = sendto(sock2, "test3", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1));
254 	if (status != -1) {
255 		REPORT_ERROR("sendto() succeeded unexpectedly\n");
256 		return 1;
257 	}
258 	if (errno != EPERM) {
259 		REPORT_ERROR("sendto() failed with unexpected error: %s\n", strerror(errno));
260 		return 1;
261 	}
262 
263 	char buf[16];
264 	memset(buf, 0, sizeof(buf));
265 	status = recv(sock1, buf, sizeof(buf), 0);
266 	if (status == -1) {
267 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
268 		return 1;
269 	}
270 	if (strcmp(buf, "test1") != 0) {
271 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
272 		return 1;
273 	}
274 
275 	memset(buf, 0, sizeof(buf));
276 	struct sockaddr_un addr3;
277 	memset(&addr3, 0, sizeof(addr3));
278 	socklen_t addrlen = sizeof(addr3);
279 	status = recvfrom(sock1, buf, sizeof(buf), 0, (struct sockaddr*)&addr3, &addrlen);
280 	if (status == -1) {
281 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
282 		return 1;
283 	}
284 	if (strcmp(buf, "test2") != 0) {
285 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
286 		return 1;
287 	}
288 	if (strcmp(addr.sun_path, addr3.sun_path) != 0) {
289 		REPORT_ERROR("recv() received unexpected address: %s\n", addr3.sun_path);
290 		return 1;
291 	}
292 
293 	status = send(sock, "test4", 4, 0);
294 	if (status == -1) {
295 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
296 		return 1;
297 	}
298 
299 	status = send(sock, "test5", 5, 0);
300 	if (status == -1) {
301 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
302 		return 1;
303 	}
304 
305 	memset(buf, 0, sizeof(buf));
306 	status = recv(sock1, buf, 4, 0);
307 	if (status == -1) {
308 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
309 		return 1;
310 	}
311 	if (strcmp(buf, "test") != 0) {
312 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
313 		return 1;
314 	}
315 
316 	// The last byte of the previous datagram should be discarded.
317 	memset(buf, 0, sizeof(buf));
318 	status = recv(sock1, buf, sizeof(buf), 0);
319 	if (status == -1) {
320 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
321 		return 1;
322 	}
323 	if (strcmp(buf, "test5") != 0) {
324 		REPORT_ERROR("recv() received unexpected data: %s\n", buf);
325 		return 1;
326 	}
327 
328 	close(sock1);
329 	status = send(sock, "test6", 5, 0);
330 	if (status != -1) {
331 		REPORT_ERROR("send() succeeded unexpectedly\n");
332 		return 1;
333 	}
334 	if (errno != ECONNREFUSED) {
335 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
336 		return 1;
337 	}
338 
339 	close(sock);
340 	close(sock2);
341 
342 	unlink("test.sock");
343 	unlink("test1.sock");
344 	unlink("test2.sock");
345 
346 	return 0;
347 }
348 
349 
350 int
351 send_unbound_test()
352 {
353 	unlink("test-socket-unix");
354 	int sock_server = socket(AF_UNIX, SOCK_DGRAM, 0);
355 	if (sock_server == -1) {
356 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
357 		return 1;
358 	}
359 
360 	struct sockaddr_un addr;
361 	addr.sun_family = AF_UNIX;
362 	strcpy(addr.sun_path, "test-socket-unix");
363 	int status = bind(sock_server, (struct sockaddr*)&addr, sizeof(addr));
364 	if (status == -1) {
365 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
366 		unlink("test-socket-unix");
367 		close(sock_server);
368 		return 1;
369 	}
370 
371 	int sock_client = socket(AF_UNIX, SOCK_DGRAM, 0);
372 	if (sock_client == -1) {
373 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
374 		unlink("test-socket-unix");
375 		close(sock_server);
376 		return 1;
377 	}
378 
379 	status = sendto(sock_client, "t", 1, 0, (struct sockaddr*)&addr, sizeof(addr));
380 	if (status != 1) {
381 		REPORT_ERROR("sendto() failed: %s\n", strerror(errno));
382 		unlink("test-socket-unix");
383 		close(sock_server);
384 		close(sock_client);
385 		return 1;
386 	}
387 
388 	char buf[1024];
389 	memset(buf, 0, sizeof(buf));
390 	struct sockaddr_un addr_sender;
391 	memset(&addr_sender, 0, sizeof(addr_sender));
392 	socklen_t addrlen = sizeof(addr_sender);
393 	status = recvfrom(sock_server, buf, sizeof(buf), 0, (struct sockaddr*)&addr_sender, &addrlen);
394 	if (strcmp(addr_sender.sun_path, "") != 0 || status != 1 || strcmp(buf, "t") != 0) {
395 		REPORT_ERROR("recvfrom() failed: %s\n", strerror(errno));
396 		unlink("test-socket-unix");
397 		close(sock_server);
398 		close(sock_client);
399 		return 1;
400 	}
401 	return 0;
402 }
403 
404 
405 int
406 shutdown_test()
407 {
408 	unlink("test.sock");
409 	unlink("test1.sock");
410 
411 	int status;
412 
413 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
414 	if (sock == -1) {
415 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
416 		return 1;
417 	}
418 
419 	struct sockaddr_un addr;
420 	addr.sun_family = AF_UNIX;
421 	strcpy(addr.sun_path, "test.sock");
422 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
423 	if (status == -1) {
424 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
425 		return 1;
426 	}
427 
428 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
429 	if (sock1 == -1) {
430 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
431 		return 1;
432 	}
433 
434 	struct sockaddr_un addr1;
435 	addr1.sun_family = AF_UNIX;
436 	strcpy(addr1.sun_path, "test1.sock");
437 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
438 	if (status == -1) {
439 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
440 		return 1;
441 	}
442 
443 	status = shutdown(sock, SHUT_WR);
444 	if (status == -1) {
445 		REPORT_ERROR("shutdown() failed: %s\n", strerror(errno));
446 		return 1;
447 	}
448 
449 	status = sendto(sock, "test", 4, 0, (struct sockaddr*)&addr1, sizeof(addr1));
450 	if (status != -1) {
451 		REPORT_ERROR("send() succeeded unexpectedly\n");
452 		return 1;
453 	}
454 	if (errno != EPIPE) {
455 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
456 		return 1;
457 	}
458 
459 	status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr));
460 	if (status == -1) {
461 		REPORT_ERROR("send() failed: %s\n", strerror(errno));
462 		return 1;
463 	}
464 
465 	status = shutdown(sock, SHUT_RD);
466 	if (status == -1) {
467 		REPORT_ERROR("shutdown() failed: %s\n", strerror(errno));
468 		return 1;
469 	}
470 
471 	status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr));
472 	if (status != -1) {
473 		REPORT_ERROR("send() succeeded unexpectedly\n");
474 		return 1;
475 	}
476 	if (errno != EPIPE) {
477 		REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno));
478 		return 1;
479 	}
480 
481 	char buf[16];
482 	memset(buf, 0, sizeof(buf));
483 	status = recv(sock, buf, sizeof(buf), 0);
484 	if (status == -1) {
485 		REPORT_ERROR("recv() failed: %s\n", strerror(errno));
486 		return 1;
487 	}
488 	if (status != 0) {
489 		REPORT_ERROR("recv() received unexpected data\n");
490 		return 1;
491 	}
492 
493 	close(sock);
494 	close(sock1);
495 
496 	unlink("test.sock");
497 	unlink("test1.sock");
498 
499 	return 0;
500 }
501 
502 
503 int
504 send_fd_test()
505 {
506 	unlink("test.sock");
507 	unlink("test1.sock");
508 
509 	int status;
510 
511 	int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
512 	if (sock == -1) {
513 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
514 		return 1;
515 	}
516 
517 	struct sockaddr_un addr;
518 	addr.sun_family = AF_UNIX;
519 	strcpy(addr.sun_path, "test.sock");
520 	status = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
521 	if (status == -1) {
522 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
523 		return 1;
524 	}
525 
526 	int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0);
527 	if (sock1 == -1) {
528 		REPORT_ERROR("socket() failed: %s\n", strerror(errno));
529 		return 1;
530 	}
531 
532 	struct sockaddr_un addr1;
533 	addr1.sun_family = AF_UNIX;
534 	strcpy(addr1.sun_path, "test1.sock");
535 	status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1));
536 	if (status == -1) {
537 		REPORT_ERROR("bind() failed: %s\n", strerror(errno));
538 		return 1;
539 	}
540 
541 	status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1));
542 	if (status == -1) {
543 		REPORT_ERROR("connect() failed: %s\n", strerror(errno));
544 		return 1;
545 	}
546 
547 	int fd = shm_open("test_shm", O_CREAT | O_RDWR, 0666);
548 	if (fd == -1) {
549 		REPORT_ERROR("shm_open() failed: %s\n", strerror(errno));
550 		return 1;
551 	}
552 	shm_unlink("test_shm");
553 
554 	// Send FD
555 	char iobuf[] = "test";
556 	struct iovec iov {
557 		.iov_base = iobuf,
558 		.iov_len = sizeof(iobuf),
559 	};
560 
561 	struct msghdr msg;
562 	memset(&msg, 0, sizeof(msg));
563 
564 	struct cmsghdr *cmsg;
565 	char buf[CMSG_SPACE(sizeof(fd))];
566 	memset(buf, 0, sizeof(buf));
567 	msg.msg_control = buf;
568 	msg.msg_controllen = sizeof(buf);
569 	msg.msg_iov = &iov;
570 	msg.msg_iovlen = 1;
571 
572 	cmsg = CMSG_FIRSTHDR(&msg);
573 	cmsg->cmsg_level = SOL_SOCKET;
574 	cmsg->cmsg_type = SCM_RIGHTS;
575 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
576 	memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
577 	msg.msg_controllen = cmsg->cmsg_len;
578 
579 	status = sendmsg(sock, &msg, 0);
580 	if (status == -1) {
581 		REPORT_ERROR("sendmsg() failed: %s\n", strerror(errno));
582 		return 1;
583 	}
584 
585 	// Receive FD
586 	memset(buf, 0, sizeof(buf));
587 	msg.msg_control = buf;
588 	msg.msg_controllen = sizeof(buf);
589 	msg.msg_iov = &iov;
590 	msg.msg_iovlen = 1;
591 
592 	status = recvmsg(sock1, &msg, 0);
593 	if (status == -1) {
594 		REPORT_ERROR("recvmsg() failed: %s\n", strerror(errno));
595 		return 1;
596 	}
597 
598 	cmsg = CMSG_FIRSTHDR(&msg);
599 	if (cmsg == NULL) {
600 		REPORT_ERROR("recvmsg() failed: no control message\n");
601 		return 1;
602 	}
603 	if (cmsg->cmsg_level != SOL_SOCKET) {
604 		REPORT_ERROR("recvmsg() failed: unexpected level %d\n", cmsg->cmsg_level);
605 		return 1;
606 	}
607 	if (cmsg->cmsg_type != SCM_RIGHTS) {
608 		REPORT_ERROR("recvmsg() failed: unexpected type %d\n", cmsg->cmsg_type);
609 		return 1;
610 	}
611 	if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
612 		REPORT_ERROR("recvmsg() failed: unexpected length %ld\n", cmsg->cmsg_len);
613 		return 1;
614 	}
615 
616 	int fd1;
617 	memcpy(&fd1, CMSG_DATA(cmsg), sizeof(fd1));
618 	if (fd1 == -1) {
619 		REPORT_ERROR("recvmsg() failed: unexpected fd %d\n", fd1);
620 		return 1;
621 	}
622 
623 	// Check that the FD refers to the same file
624 	struct stat statbuf;
625 	status = fstat(fd, &statbuf);
626 	if (status == -1) {
627 		REPORT_ERROR("fstat() failed: %s\n", strerror(errno));
628 		return 1;
629 	}
630 
631 	struct stat statbuf1;
632 	status = fstat(fd1, &statbuf1);
633 	if (status == -1) {
634 		REPORT_ERROR("fstat() failed: %s\n", strerror(errno));
635 		return 1;
636 	}
637 
638 	if (statbuf.st_dev != statbuf1.st_dev) {
639 		REPORT_ERROR("recvmsg() failed: unexpected device %ld\n", (long)statbuf1.st_dev);
640 		return 1;
641 	}
642 	if (statbuf.st_ino != statbuf1.st_ino) {
643 		REPORT_ERROR("recvmsg() failed: unexpected inode %ld\n", (long)statbuf1.st_ino);
644 		return 1;
645 	}
646 
647 	close(sock);
648 	close(sock1);
649 	close(fd);
650 	close(fd1);
651 
652 	unlink("test.sock");
653 	unlink("test1.sock");
654 
655 	return 0;
656 }
657 
658 
659 int
660 main()
661 {
662 	if (connect_test() != 0)
663 		return 1;
664 
665 	if (send_test() != 0)
666 		return 1;
667 
668 	if (send_unbound_test() != 0)
669 		return 1;
670 
671 	if (shutdown_test() != 0)
672 		return 1;
673 
674 	if (send_fd_test() != 0)
675 		return 1;
676 
677 	return 0;
678 }
679