• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-minimal-raw-adopt-tcp
3  *
4  * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * This demonstrates integrating somebody else's connected tcp
10  * socket into the lws event loop as a RAW wsi.  It's interesting in
11  * the kind of situation where you already have a connected socket
12  * in your application, and you need to hand it over to lws to deal with.
13  *
14  * Lws supports "adopting" these foreign sockets.
15  *
16  * If you simply want a connected client raw socket using lws alone, you
17  * can just use lws_client_connect_via_info() with info.method = "RAW".
18  *
19  */
20 
21 #include <libwebsockets.h>
22 #include <string.h>
23 #include <signal.h>
24 #if !defined(WIN32)
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netdb.h>
28 #include <arpa/inet.h>
29 #endif
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 
37 static int
callback_raw_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)38 callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
39 			void *user, void *in, size_t len)
40 {
41 
42 	switch (reason) {
43 
44 	/* callbacks related to raw socket descriptor */
45 
46         case LWS_CALLBACK_RAW_ADOPT:
47 		lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
48 		lws_callback_on_writable(wsi);
49                 break;
50 
51 	case LWS_CALLBACK_RAW_CLOSE:
52 		lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
53 		break;
54 
55 	case LWS_CALLBACK_RAW_RX:
56 		lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
57 		lwsl_hexdump_level(LLL_NOTICE, in, len);
58 		break;
59 
60 	case LWS_CALLBACK_RAW_WRITEABLE:
61 		if (lws_write(wsi,
62 			      (uint8_t *)"GET / HTTP/1.1\xd\xa\xd\xa", 18,
63 			      LWS_WRITE_RAW) != 18) {
64 			lwsl_notice("%s: raw write failed\n", __func__);
65 			return 1;
66 		}
67 		break;
68 
69 	default:
70 		break;
71 	}
72 
73 	return 0;
74 }
75 
76 static struct lws_protocols protocols[] = {
77 	{ "raw-test", callback_raw_test, 0, 0 },
78 	{ NULL, NULL, 0, 0 } /* terminator */
79 };
80 
81 static int interrupted;
82 
sigint_handler(int sig)83 void sigint_handler(int sig)
84 {
85 	interrupted = 1;
86 }
87 
main(int argc,const char ** argv)88 int main(int argc, const char **argv)
89 {
90 	struct lws_context_creation_info info;
91 	struct lws_context *context;
92 	lws_sock_file_fd_type sock;
93 	struct addrinfo h, *r, *rp;
94 	struct lws_vhost *vhost;
95 	const char *p;
96 	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
97 			/* for LLL_ verbosity above NOTICE to be built into lws,
98 			 * lws must have been configured and built with
99 			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
100 			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
101 			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
102 			/* | LLL_DEBUG */;
103 
104 	signal(SIGINT, sigint_handler);
105 
106 	if ((p = lws_cmdline_option(argc, argv, "-d")))
107 		logs = atoi(p);
108 
109 	lws_set_log_level(logs, NULL);
110 	lwsl_user("LWS minimal raw adopt tcp\n");
111 
112 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
113 	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
114 
115 	context = lws_create_context(&info);
116 	if (!context) {
117 		lwsl_err("lws init failed\n");
118 		return 1;
119 	}
120 
121 	info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
122 	info.protocols = protocols;
123 
124 	vhost = lws_create_vhost(context, &info);
125 	if (!vhost) {
126 		lwsl_err("lws vhost creation failed\n");
127 		goto bail;
128 	}
129 
130 	/*
131 	 * Connect our own "foreign" socket to libwebsockets.org:80
132 	 *
133 	 * Normally you would do this with lws_client_connect_via_info() inside
134 	 * the lws event loop, hiding all this detail.  But this example
135 	 * demonstrates how to integrate an externally-connected "foreign"
136 	 * socket, so we create one by hand.
137 	 */
138 
139 	memset(&h, 0, sizeof(h));
140 	h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
141 	h.ai_socktype = SOCK_STREAM;
142 	h.ai_protocol = IPPROTO_TCP;
143 
144 	n = getaddrinfo("libwebsockets.org", "80", &h, &r);
145 	if (n) {
146 		lwsl_err("%s: problem resolving libwebsockets.org: %s\n", __func__, gai_strerror(n));
147 		return 1;
148 	}
149 
150 	for (rp = r; rp; rp = rp->ai_next) {
151 		sock.sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
152 		if (sock.sockfd != LWS_SOCK_INVALID)
153 			break;
154 	}
155 	if (!rp) {
156 		lwsl_err("%s: unable to create INET socket\n", __func__);
157 		freeaddrinfo(r);
158 
159 		return 1;
160 	}
161 
162 	lwsl_user("Starting connect...\n");
163 	if (connect(sock.sockfd, rp->ai_addr, sizeof(*rp->ai_addr)) < 0) {
164 		lwsl_err("%s: unable to connect to libwebsockets.org:80\n", __func__);
165 		freeaddrinfo(r);
166 		return 1;
167 	}
168 
169 	freeaddrinfo(r);
170 	signal(SIGINT, sigint_handler);
171 	lwsl_user("Connected...\n");
172 
173 	/* our foreign socket is connected... adopt it into lws */
174 
175 	if (!lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock,
176 				       protocols[0].name, NULL)) {
177 		lwsl_err("%s: foreign socket adoption failed\n", __func__);
178 		goto bail;
179 	}
180 
181 	while (n >= 0 && !interrupted)
182 		n = lws_service(context, 0);
183 
184 bail:
185 	lws_context_destroy(context);
186 
187 	return 0;
188 }
189