1 /*
2     Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved.
3     Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
4     Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
5     Copyright 2018 Capitar IT Group BV <info@capitar.com>
6 
7     Permission is hereby granted, free of charge, to any person obtaining a
8     copy of this software and associated documentation files (the "Software"),
9     to deal in the Software without restriction, including without limitation
10     the rights to use, copy, modify, merge, publish, distribute, sublicense,
11     and/or sell copies of the Software, and to permit persons to whom
12     the Software is furnished to do so, subject to the following conditions:
13 
14     The above copyright notice and this permission notice shall be included
15     in all copies or substantial portions of the Software.
16 
17     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23     DEALINGS IN THE SOFTWARE.
24 */
25 
26 // Note: This file started life in nanomsg.  We have copied it, and adjusted
27 // it for validating the compatibility features of nanomsg.   As much as
28 // possible we want to run tests from the nanomsg test suite unmodified.
29 
30 #include <assert.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <nng/compat/nanomsg/nn.h>
36 #include "compat_testutil.h"
37 
38 int  test_socket_impl(char *file, int line, int family, int protocol);
39 int  test_connect_impl(char *file, int line, int sock, char *address);
40 int  test_bind_impl(char *file, int line, int sock, char *address);
41 void test_close_impl(char *file, int line, int sock);
42 void test_send_impl(char *file, int line, int sock, char *data);
43 void test_recv_impl(char *file, int line, int sock, char *data);
44 void test_drop_impl(char *file, int line, int sock, int err);
45 int test_setsockopt_impl(char *file, int line, int sock, int level, int option,
46     const void *optval, size_t optlen);
47 
48 int
test_socket_impl(char * file,int line,int family,int protocol)49 test_socket_impl(char *file, int line, int family, int protocol)
50 {
51 	int sock;
52 
53 	sock = nn_socket(family, protocol);
54 	if (sock == -1) {
55 		fprintf(stderr, "Failed create socket: %s [%d] (%s:%d)\n",
56 		    nn_err_strerror(errno), (int) errno, file, line);
57 		nn_err_abort();
58 	}
59 
60 	return (sock);
61 }
62 
63 int
test_connect_impl(char * file,int line,int sock,char * address)64 test_connect_impl(char *file, int line, int sock, char *address)
65 {
66 	int rc;
67 
68 	rc = nn_connect(sock, address);
69 	if (rc < 0) {
70 		fprintf(stderr, "Failed connect to \"%s\": %s [%d] (%s:%d)\n",
71 		    address, nn_err_strerror(errno), (int) errno, file, line);
72 		nn_err_abort();
73 	}
74 	return (rc);
75 }
76 
77 int
test_bind_impl(char * file,int line,int sock,char * address)78 test_bind_impl(char *file, int line, int sock, char *address)
79 {
80 	int rc;
81 
82 	rc = nn_bind(sock, address);
83 	if (rc < 0) {
84 		fprintf(stderr, "Failed bind to \"%s\": %s [%d] (%s:%d)\n",
85 		    address, nn_err_strerror(errno), (int) errno, file, line);
86 		nn_err_abort();
87 	}
88 	return (rc);
89 }
90 
91 int
test_setsockopt_impl(char * file,int line,int sock,int level,int option,const void * optval,size_t optlen)92 test_setsockopt_impl(char *file, int line, int sock, int level, int option,
93     const void *optval, size_t optlen)
94 {
95 	int rc;
96 
97 	rc = nn_setsockopt(sock, level, option, optval, optlen);
98 	if (rc < 0) {
99 		fprintf(stderr, "Failed set option \"%d\": %s [%d] (%s:%d)\n",
100 		    option, nn_err_strerror(errno), (int) errno, file, line);
101 		nn_err_abort();
102 	}
103 	return rc;
104 }
105 
106 void
test_close_impl(char * file,int line,int sock)107 test_close_impl(char *file, int line, int sock)
108 {
109 	int rc;
110 
111 	rc = nn_close(sock);
112 	if ((rc != 0) && (errno != EBADF && errno != ETERM)) {
113 		fprintf(stderr, "Failed to close socket: %s [%d] (%s:%d)\n",
114 		    nn_err_strerror(errno), (int) errno, file, line);
115 		nn_err_abort();
116 	}
117 }
118 
119 void
test_send_impl(char * file,int line,int sock,char * data)120 test_send_impl(char *file, int line, int sock, char *data)
121 {
122 	size_t data_len;
123 	int    rc;
124 
125 	data_len = strlen(data);
126 
127 	rc = nn_send(sock, data, data_len, 0);
128 	if (rc < 0) {
129 		fprintf(stderr, "Failed to send: %s [%d] (%s:%d)\n",
130 		    nn_err_strerror(errno), (int) errno, file, line);
131 		nn_err_abort();
132 	}
133 	if (rc != (int) data_len) {
134 		fprintf(stderr,
135 		    "Data to send is truncated: %d != %d (%s:%d)\n", rc,
136 		    (int) data_len, file, line);
137 		nn_err_abort();
138 	}
139 }
140 
141 void
test_recv_impl(char * file,int line,int sock,char * data)142 test_recv_impl(char *file, int line, int sock, char *data)
143 {
144 	size_t data_len;
145 	int    rc;
146 	char * buf;
147 
148 	data_len = strlen(data);
149 	/*  We allocate plus one byte so that we are sure that message received
150 	    has correct length and not truncated  */
151 	buf = malloc(data_len + 1);
152 	alloc_assert(buf);
153 
154 	rc = nn_recv(sock, buf, data_len + 1, 0);
155 	if (rc < 0) {
156 		fprintf(stderr, "Failed to recv: %s [%d] (%s:%d)\n",
157 		    nn_err_strerror(errno), (int) errno, file, line);
158 		nn_err_abort();
159 	}
160 	if (rc != (int) data_len) {
161 		fprintf(stderr,
162 		    "Received data has wrong length: %d != %d (%s:%d)\n", rc,
163 		    (int) data_len, file, line);
164 		nn_err_abort();
165 	}
166 	if (memcmp(data, buf, data_len) != 0) {
167 		/*  We don't print the data as it may have binary garbage  */
168 		fprintf(
169 		    stderr, "Received data is wrong (%s:%d)\n", file, line);
170 		nn_err_abort();
171 	}
172 
173 	free(buf);
174 }
175 
176 void
test_drop_impl(char * file,int line,int sock,int err)177 test_drop_impl(char *file, int line, int sock, int err)
178 {
179 	int  rc;
180 	char buf[1024];
181 
182 	rc = nn_recv(sock, buf, sizeof(buf), 0);
183 	if (rc < 0 && err != errno) {
184 		fprintf(stderr,
185 		    "Got wrong err to recv: %s [%d != %d] (%s:%d)\n",
186 		    nn_err_strerror(errno), (int) errno, err, file, line);
187 		nn_err_abort();
188 	} else if (rc >= 0) {
189 		fprintf(stderr, "Did not drop message: [%d bytes] (%s:%d)\n",
190 		    rc, file, line);
191 		nn_err_abort();
192 	}
193 }
194 
195 int
get_test_port(int argc,const char * argv[])196 get_test_port(int argc, const char *argv[])
197 {
198 	return (atoi(argc < 2 ? "5555" : argv[1]));
199 }
200 
201 void
test_addr_from(char * out,const char * proto,const char * ip,int port)202 test_addr_from(char *out, const char *proto, const char *ip, int port)
203 {
204 	sprintf(out, "%s://%s:%d", proto, ip, port);
205 }
206 
207 extern int nng_thread_create(void **, void (*)(void *), void *);
208 
209 int
nn_thread_init(struct nn_thread * thr,void (* func)(void *),void * arg)210 nn_thread_init(struct nn_thread *thr, void (*func)(void *), void *arg)
211 {
212 	return (nng_thread_create(&thr->thr, func, arg));
213 }
214 
215 extern void nng_thread_destroy(void *);
216 
217 void
nn_thread_term(struct nn_thread * thr)218 nn_thread_term(struct nn_thread *thr)
219 {
220 	nng_thread_destroy(thr->thr);
221 }
222 
223 extern void nng_msleep(int32_t);
224 
225 void
nn_sleep(int ms)226 nn_sleep(int ms)
227 {
228 	nng_msleep(ms);
229 }
230