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