1 /*
2  * Purpose: Test for dbsqlexec on closed connection
3  */
4 
5 #include "common.h"
6 
7 #if HAVE_UNISTD_H
8 #include <unistd.h>
9 #endif /* HAVE_UNISTD_H */
10 
11 #include <freetds/time.h>
12 
13 #if HAVE_SYS_SOCKET_H
14 #include <sys/socket.h>
15 #endif /* HAVE_SYS_SOCKET_H */
16 
17 #if HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif /* HAVE_SYS_STAT_H */
20 
21 #if HAVE_SYS_IOCTL_H
22 #include <sys/ioctl.h>
23 #endif /* HAVE_SYS_IOCTL_H */
24 
25 #if HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #endif /* HAVE_SYS_WAIT_H */
28 
29 #if HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif /* HAVE_NET_INET_IN_H */
32 
33 #include <freetds/utils.h>
34 
35 char *UNITTEST;
36 
37 #if HAVE_FSTAT && defined(S_IFSOCK)
38 
39 static int end_socket = -1;
40 
41 static int
shutdown_socket(DBPROCESS * dbproc)42 shutdown_socket(DBPROCESS *dbproc)
43 {
44 	union {
45 		struct sockaddr sa;
46 		char data[256];
47 	} u;
48 	SOCKLEN_T addrlen;
49 	struct stat file_stat;
50 	TDS_SYS_SOCKET sockets[2];
51 
52 	TDS_SYS_SOCKET socket = DBIOWDESC(dbproc);
53 
54 	if (fstat(socket, &file_stat))
55 		return 0;
56 	if ((file_stat.st_mode & S_IFSOCK) != S_IFSOCK)
57 		return 0;
58 
59 	addrlen = sizeof(u);
60 	if (tds_getsockname(socket, &u.sa, &addrlen) < 0 || (u.sa.sa_family != AF_INET && u.sa.sa_family != AF_INET6))
61 		return 0;
62 
63 	/* replace socket with a new one */
64 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
65 		return 0;
66 
67 	tds_socket_set_nosigpipe(sockets[0], 1);
68 
69 	/* substitute socket */
70 	close(socket);
71 	dup2(sockets[0], socket);
72 
73 	/* close connection */
74 	close(sockets[0]);
75 	end_socket = sockets[1];
76 	return 1;
77 }
78 
79 static int
test(int close_socket)80 test(int close_socket)
81 {
82 	LOGINREC *login;
83 	DBPROCESS *dbproc;
84 	RETCODE ret;
85 	int expected_error = -1;
86 
87 	printf("Starting %s\n", UNITTEST);
88 
89 	dbinit();
90 
91 	dberrhandle(syb_err_handler);
92 	dbmsghandle(syb_msg_handler);
93 
94 	printf("About to logon\n");
95 
96 	login = dblogin();
97 	DBSETLPWD(login, PASSWORD);
98 	DBSETLUSER(login, USER);
99 	DBSETLAPP(login, "t0020");
100 
101 	printf("About to open\n");
102 
103 	dbproc = dbopen(login, SERVER);
104 	dbsetuserdata(dbproc, (BYTE*) &expected_error);
105 	if (strlen(DATABASE))
106 		dbuse(dbproc, DATABASE);
107 	dbloginfree(login);
108 
109 	dbcmd(dbproc, "select * from sysobjects");
110 	printf("dbsqlexec should not hang.\n");
111 
112 	ret = dbsettime(15);
113 	if (ret != SUCCEED) {
114 		fprintf(stderr, "Failed.  Error setting timeout.\n");
115 		return 1;
116 	}
117 
118 	if (!shutdown_socket(dbproc)) {
119 		fprintf(stderr, "Error shutting down connection\n");
120 		return 1;
121 	}
122 	if (close_socket)
123 		close(end_socket);
124 
125 	alarm(20);
126 	expected_error = close_socket ? 20006 : 20003;
127 	ret = dbsqlexec(dbproc);
128 	alarm(0);
129 	if (ret != FAIL) {
130 		fprintf(stderr, "Failed.  Expected FAIL to be returned.\n");
131 		return 1;
132 	}
133 
134 	dbsetuserdata(dbproc, NULL);
135 	if (!close_socket)
136 		close(end_socket);
137 	dbexit();
138 
139 	printf("dblib okay on %s\n", __FILE__);
140 	return 0;
141 }
142 
143 int
main(int argc,char ** argv)144 main(int argc, char **argv)
145 {
146 	UNITTEST = argv[0];
147 	read_login_info(argc, argv);
148 	if (test(0) || test(1))
149 		return 1;
150 	return 0;
151 }
152 
153 #else
154 int
main(void)155 main(void)
156 {
157 	fprintf(stderr, "Not possible for this platform.\n");
158 	return 0;
159 }
160 #endif
161 
162