static int connect_client(int idx) { struct lws_client_connect_info i; if (tries == limit) { lwsl_user("Reached limit... finishing\n"); return 0; } memset(&i, 0, sizeof(i)); i.context = context; i.port = port; i.address = server_address; i.path = "/"; i.host = i.address; i.origin = i.address; i.ssl_connection = ssl_connection; i.protocol = pro; i.local_protocol_name = pro; i.pwsi = &clients[idx].wsi; clients[idx].state = CLIENT_CONNECTING; tries++; if (!lws_client_connect_via_info(&i)) { clients[idx].wsi = NULL; clients[idx].state = CLIENT_IDLE; return 1; } return 0; }
int ps_websockets_init (ps_transport_callbacks * callback) { if (g_atomic_int_get(&stopping)) { return -1; } if (callback == NULL) { return -1; } gateway = callback; struct lws * wsi; /* Set Log level */ lws_set_log_level (0, NULL); /* Prepare context */ struct lws_context_creation_info info; struct lws_client_connect_info cinfo; memset(&info, 0, sizeof info); memset(&cinfo, 0, sizeof cinfo); info.port = CONTEXT_PORT_NO_LISTEN; info.iface = NULL; info.protocols = wss_protocols; info.extensions = NULL; //lws_get_internal_extensions(); info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; info.gid = -1; info.uid = -1; info.options = 0; /* Create the websockets context */ wss = lws_create_context(&info); cinfo.context = wss; cinfo.ssl_connection = 0; cinfo.host = host; cinfo.address = host; cinfo.port = wsport; cinfo.path = path; cinfo.protocol = "ps-protocol"; //wss_protocols.name; GError * error = NULL; if (wss != NULL) { /* Connect to the server */ wsi = lws_client_connect_via_info (&cinfo); /*TODO: somehow, check if the connection is established?*/ wss_thread = g_thread_try_new("websockets thread", &ps_websockets_thread, wss, &error); if (!wss_thread) { g_atomic_int_set(&initialized, 0); PS_LOG (LOG_ERR,"Got error %d (%s) trying to launch the wss thread...\n", error->code, error->message ? error->message : "??"); return -1; } } /* done */ g_atomic_int_set(&initialized, 1); return 0; }
JNIEXPORT jboolean JNICALL jni_connectLws(JNIEnv *env, jobject obj) { struct lws_client_connect_info info_ws; memset(&info_ws, 0, sizeof(info_ws)); info_ws.port = port; info_ws.address = address; info_ws.path = "/"; info_ws.context = context; info_ws.ssl_connection = use_ssl; info_ws.host = address; info_ws.origin = address; info_ws.ietf_version_or_minus_one = -1; info_ws.client_exts = exts; info_ws.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; // connect wsi = lws_client_connect_via_info(&info_ws); if(wsi == NULL ){ // Error emit_log(LLL_ERR, "Protocol failed to connect."); return JNI_FALSE; } return JNI_TRUE; }
void FWebSocket::Connect(){ #if !PLATFORM_HTML5 struct lws_client_connect_info ConnectInfo = { Context, TCHAR_TO_ANSI(*StrInetAddress), InetPort, false, "/", TCHAR_TO_ANSI(*StrInetAddress), TCHAR_TO_ANSI(*StrInetAddress), Protocols[1].name, -1, this }; Wsi = lws_client_connect_via_info(&ConnectInfo); check(Wsi); #else // PLATFORM_HTML5 SockFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SockFd == -1) { UE_LOG(LogHTML5Networking, Error, TEXT("Socket creationg failed ")); } else { UE_LOG(LogHTML5Networking, Warning, TEXT(" Socked %d created "), SockFd); } fcntl(SockFd, F_SETFL, O_NONBLOCK); #endif // Windows XP does not have support for inet_pton #if PLATFORM_WINDOWS && _WIN32_WINNT <= 0x0502 memset(&RemoteAddr, 0, sizeof(RemoteAddr)); int32 SizeOfRemoteAddr = sizeof(RemoteAddr); // Force ServerAddress into non-const array. API doesn't modify contents but old API still requires non-const string if (WSAStringToAddress(StrInetAddress.GetCharArray().GetData(), AF_INET, NULL, (sockaddr*)&RemoteAddr, &SizeOfRemoteAddr) != 0) { UE_LOG(LogHTML5Networking, Warning, TEXT("WSAStringToAddress failed ")); return; } RemoteAddr.sin_family = AF_INET; RemoteAddr.sin_port = htons(InetPort); #else memset(&RemoteAddr, 0, sizeof(RemoteAddr)); RemoteAddr.sin_family = AF_INET; RemoteAddr.sin_port = htons(InetPort); if (inet_pton(AF_INET, TCHAR_TO_ANSI(*StrInetAddress), &RemoteAddr.sin_addr) != 1) { UE_LOG(LogHTML5Networking, Warning, TEXT("inet_pton failed ")); return; } #endif #if PLATFORM_HTML5 int Ret = connect(SockFd, (struct sockaddr *)&RemoteAddr, sizeof(RemoteAddr)); UE_LOG(LogHTML5Networking, Warning, TEXT(" Connect socket returned %d"), Ret); #endif IsDestroyed = false; }
static int connect_client(struct per_vhost_data__minimal *vhd) { vhd->i.context = vhd->context; vhd->i.port = 7681; vhd->i.address = "localhost"; vhd->i.path = "/publisher"; vhd->i.host = vhd->i.address; vhd->i.origin = vhd->i.address; vhd->i.ssl_connection = 0; vhd->i.protocol = "lws-minimal-broker"; vhd->i.pwsi = &vhd->client_wsi; return !lws_client_connect_via_info(&vhd->i); }
static int connect_client(void) { struct lws_client_connect_info i; memset(&i, 0, sizeof(i)); i.context = context; i.port = port; i.address = server_address; i.path = "/"; i.host = i.address; i.origin = i.address; i.ssl_connection = ssl_connection; i.protocol = pro; i.local_protocol_name = "lws-ping-test"; i.pwsi = &client_wsi; return !lws_client_connect_via_info(&i); }
/* * Notice: trashes i and url */ static struct lws * lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh, struct lws **pwsi, struct lws_client_connect_info *i, char *url, const char *method) { const char *prot, *p; char path[200], _url[256]; struct lws *wsi; memset(i, 0, sizeof(*i)); i->port = 443; lws_strncpy(_url, url, sizeof(_url)); if (lws_parse_uri(_url, &prot, &i->address, &i->port, &p)) { lwsl_err("unable to parse uri %s\n", url); return NULL; } /* add back the leading / on path */ path[0] = '/'; lws_strncpy(path + 1, p, sizeof(path) - 1); i->path = path; i->context = context; i->vhost = vh; i->ssl_connection = 1; i->host = i->address; i->origin = i->address; i->method = method; i->pwsi = pwsi; i->protocol = "lws-acme-client"; wsi = lws_client_connect_via_info(i); if (!wsi) { lws_snprintf(path, sizeof(path) - 1, "Unable to connect to %s", url); lwsl_notice("%s: %s\n", __func__, path); lws_acme_report_status(vh, LWS_CUS_FAILED, path); } return wsi; }
LWS_VISIBLE struct lws * lws_client_connect(struct lws_context *context, const char *address, int port, int ssl_connection, const char *path, const char *host, const char *origin, const char *protocol, int ietf_version_or_minus_one) { struct lws_client_connect_info i; memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = ssl_connection; i.path = path; i.host = host; i.origin = origin; i.protocol = protocol; i.ietf_version_or_minus_one = ietf_version_or_minus_one; i.userdata = NULL; return lws_client_connect_via_info(&i); }
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *)user; unsigned char buffer[4096 + LWS_PRE]; unsigned long amount, file_len, sent; char leaf_path[1024]; const char *mimetype; char *other_headers; unsigned char *end, *start; struct timeval tv; unsigned char *p; #ifndef LWS_NO_CLIENT struct per_session_data__http *pss1; struct lws *wsi1; #endif char buf[256]; char b64[64]; int n, m; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif switch (reason) { case LWS_CALLBACK_HTTP: lwsl_info("lws_http_serve: %s\n",in); if (debug_level & LLL_INFO) { dump_handshake_info(wsi); /* dump the individual URI Arg parameters */ n = 0; while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n) > 0) { lwsl_notice("URI Arg %d: %s\n", ++n, buf); } } { lws_get_peer_simple(wsi, buf, sizeof(buf)); lwsl_info("HTTP connect from %s\n", buf); } if (len < 1) { lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } #ifndef LWS_NO_CLIENT if (!strncmp(in, "/proxytest", 10)) { struct lws_client_connect_info i; char *rootpath = "/"; const char *p = (const char *)in; if (lws_get_child(wsi)) break; pss->client_finished = 0; memset(&i,0, sizeof(i)); i.context = lws_get_context(wsi); i.address = "git.libwebsockets.org"; i.port = 80; i.ssl_connection = 0; if (p[10]) i.path = (char *)in + 10; else i.path = rootpath; i.host = "git.libwebsockets.org"; i.origin = NULL; i.method = "GET"; i.parent_wsi = wsi; i.uri_replace_from = "git.libwebsockets.org/"; i.uri_replace_to = "/proxytest/"; if (!lws_client_connect_via_info(&i)) { lwsl_err("proxy connect fail\n"); break; } break; } #endif #if 1 /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL); goto try_to_reuse; } #endif /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len, LWS_O_RDONLY); if (pss->fd == LWS_INVALID_FILE) { lwsl_err("failed to open file %s\n", leaf_path); return -1; } /* * we will send a big jpeg file, but it could be * anything. Set the Content-Type: appropriately * so the browser knows what to do with it. * * Notice we use the APIs to build the header, which * will do the right thing for HTTP 1/1.1 and HTTP2 * depending on what connection it happens to be working * on */ if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"image/jpeg", 10, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, file_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; /* * send the http headers... * this won't block since it's the first payload sent * on the connection since it was established * (too small for partial) * * Notice they are sent using LWS_WRITE_HTTP_HEADERS * which also means you can't send body too in one step, * this is mandated by changes in HTTP2 */ *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) { lws_plat_file_close(wsi, pss->fd); return -1; } /* * book us a LWS_CALLBACK_HTTP_WRITEABLE callback */ lws_callback_on_writable(wsi); break; } /* if not, send a file the easy way */ if (!strncmp(in, "/cgit-data/", 11)) { in = (char *)in + 11; strcpy(buf, "/usr/share/cgit"); } else strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(buf) - 1); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); lws_return_http_status(wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = leaf_path; p = (unsigned char *)leaf_path; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; } if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *) "max-age=15768000 ; " "includeSubDomains", 36, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: /* create the POST argument parser if not already existing */ if (!pss->spa) { pss->spa = lws_spa_create(wsi, param_names, ARRAY_SIZE(param_names), 1024, file_upload_cb, pss); if (!pss->spa) return -1; pss->filename[0] = '\0'; pss->file_length = 0; } /* let it parse the POST data */ if (lws_spa_process(pss->spa, in, len)) return -1; break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* * the whole of the sent body arrived, * respond to the client with a redirect to show the * results */ /* call to inform no more payload data coming */ lws_spa_finalize(pss->spa); p = (unsigned char *)pss->result + LWS_PRE; end = p + sizeof(pss->result) - LWS_PRE - 1; p += sprintf((char *)p, "<html><body><h1>Form results (after urldecoding)</h1>" "<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>"); for (n = 0; n < ARRAY_SIZE(param_names); n++) p += lws_snprintf((char *)p, end - p, "<tr><td><b>%s</b></td><td>%d</td><td>%s</td></tr>", param_names[n], lws_spa_get_length(pss->spa, n), lws_spa_get_string(pss->spa, n)); p += lws_snprintf((char *)p, end - p, "</table><br><b>filename:</b> %s, <b>length</b> %ld", pss->filename, pss->file_length); p += lws_snprintf((char *)p, end - p, "</body></html>"); pss->result_len = p - (unsigned char *)(pss->result + LWS_PRE); p = buffer + LWS_PRE; start = p; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n < 0) return 1; n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE, pss->result_len, LWS_WRITE_HTTP); if (n < 0) return 1; goto try_to_reuse; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: lwsl_debug("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n"); /* called when our wsi user_space is going to be destroyed */ if (pss->spa) { lws_spa_destroy(pss->spa); pss->spa = NULL; } break; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n"); if (pss->client_finished) return -1; if (pss->fd == LWS_INVALID_FILE) goto try_to_reuse; #ifndef LWS_NO_CLIENT if (pss->reason_bf & 2) { char *px = buf + LWS_PRE; int lenx = sizeof(buf) - LWS_PRE; /* * our sink is writeable and our source has something * to read. So read a lump of source material of * suitable size to send or what's available, whichever * is the smaller. */ pss->reason_bf &= ~2; wsi1 = lws_get_child(wsi); if (!wsi1) break; if (lws_http_client_read(wsi1, &px, &lenx) < 0) goto bail; if (pss->client_finished) return -1; break; } #endif /* * we can send more of whatever it is we were sending */ sent = 0; do { /* we'd like the send this much */ n = sizeof(buffer) - LWS_PRE; /* but if the peer told us he wants less, we can adapt */ m = lws_get_peer_write_allowance(wsi); /* -1 means not using a protocol that has this info */ if (m == 0) /* right now, peer can't handle anything */ goto later; if (m != -1 && m < n) /* he couldn't handle that much */ n = m; n = lws_plat_file_read(wsi, pss->fd, &amount, buffer + LWS_PRE, n); /* problem reading, close conn */ if (n < 0) { lwsl_err("problem reading file\n"); goto bail; } n = (int)amount; /* sent it all, close conn */ if (n == 0) goto penultimate; /* * To support HTTP2, must take care about preamble space * * identification of when we send the last payload frame * is handled by the library itself if you sent a * content-length header */ m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP); if (m < 0) { lwsl_err("write failed\n"); /* write failed, close conn */ goto bail; } if (m) /* while still active, extend timeout */ lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5); sent += m; } while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024)); later: lws_callback_on_writable(wsi); break; penultimate: lws_plat_file_close(wsi, pss->fd); pss->fd = LWS_INVALID_FILE; goto try_to_reuse; bail: lws_plat_file_close(wsi, pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default unhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ break; #ifndef LWS_NO_CLIENT case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { char ctype[64], ctlen = 0; lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n"); p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(lws_get_parent(wsi), 200, &p, end)) return 1; if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE); if (ctlen > 0) { if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)ctype, ctlen, &p, end)) return 1; } #if 0 if (lws_add_http_header_content_length(lws_get_parent(wsi), file_len, &p, end)) return 1; #endif if (lws_finalize_http_header(lws_get_parent(wsi), &p, end)) return 1; *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) return -1; break; } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); return -1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; // lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n", // wsi, lws_get_socket_fd(wsi), // lws_get_parent(wsi), // lws_get_socket_fd(lws_get_parent(wsi)), len); pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->reason_bf |= 2; lws_callback_on_writable(lws_get_parent(wsi)); break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len); assert(lws_get_parent(wsi)); m = lws_write(lws_get_parent(wsi), (unsigned char *)in, len, LWS_WRITE_HTTP); if (m < 0) return -1; break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->client_finished = 1; break; #endif /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_unlock(len); break; #ifdef EXTERNAL_POLL case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "lws_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: /* Verify the client certificate */ if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) { int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user); int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user); const char* msg = X509_verify_cert_error_string(err); lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth); return 1; } break; #if defined(LWS_HAVE_SSL_CTX_set1_param) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if (crl_path[0]) { /* Enable CRL checking */ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); SSL_CTX_set1_param((SSL_CTX*)user, param); X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); X509_VERIFY_PARAM_free(param); if (n != 1) { char errbuf[256]; n = ERR_get_error(); lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); return 1; } } break; #endif #endif #endif #endif default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* * For LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE * * | LLL_INFO | LLL_PARSER | LLL_HEADER | LLL_EXT | * LLL_CLIENT | LLL_LATENCY | LLL_DEBUG */ ; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ info.protocols = protocols; #if defined(LWS_WITH_MBEDTLS) /* * OpenSSL uses the system trust store. mbedTLS has to be told which * CA to trust explicitly. */ info.client_ssl_ca_filepath = "./warmcat.com.cer"; #endif context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */ i.context = context; i.ssl_connection = LCCSCF_USE_SSL; if (lws_cmdline_option(argc, argv, "-l")) { i.port = 7681; i.address = "localhost"; i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; } else { i.port = 443; i.address = "warmcat.com"; } if (lws_cmdline_option(argc, argv, "--h1")) i.alpn = "http/1.1"; i.path = "/"; i.host = i.address; i.origin = i.address; i.method = "GET"; i.protocol = protocols[0].name; i.pwsi = &client_wsi; lws_client_connect_via_info(&i); while (n >= 0 && client_wsi && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); return bad; }
static int callback_client_loopback_test(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct lws_client_connect_info i; struct per_session_data__client_loopback_test *pss = (struct per_session_data__client_loopback_test *)user; const char *p = (const char *)in; char buf[100]; int n; switch (reason) { /* HTTP part */ case LWS_CALLBACK_HTTP: if (len < 10) return -1; p++; while (*p && *p != '/') p++; if (!*p) { lws_return_http_status(wsi, 400, "Arg needs to be in format ws://xxx or wss://xxx"); return -1; } p++; memset(&i, 0, sizeof(i)); i.context = lws_get_context(wsi); // stacked /// get resolved to / if (strncmp(p, "ws:/", 4) == 0) { i.ssl_connection = 0; i.port = 80; p += 4; } else if (strncmp(p, "wss:/", 5) == 0) { i.port = 443; i.ssl_connection = 1; p += 5; } else { sprintf(buf, "Arg %s is not in format ws://xxx or wss://xxx\n", p); lws_return_http_status(wsi, 400, buf); return -1; } i.address = p; i.path = ""; i.host = p; i.origin = p; i.ietf_version_or_minus_one = -1; i.protocol = "client-loopback-test"; pss->wsi = lws_client_connect_via_info(&i); if (!pss->wsi) lws_return_http_status(wsi, 401, "client-loopback-test: connect failed\n"); else { lwsl_notice("client connection to %s:%d with ssl: %d started\n", i.address, i.port, i.ssl_connection); lws_return_http_status(wsi, 200, "OK"); } /* either way, close the triggering http link */ return -1; case LWS_CALLBACK_CLOSED_HTTP: lwsl_notice("Http part closed\n"); break; /* server part */ case LWS_CALLBACK_ESTABLISHED: lwsl_notice("server part: LWS_CALLBACK_ESTABLISHED\n"); strcpy(buf + LWS_PRE, "Made it"); n = lws_write(wsi, (unsigned char *)buf + LWS_PRE, 7, LWS_WRITE_TEXT); if (n < 7) return -1; break; /* client part */ case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_notice("Client connection established\n"); break; case LWS_CALLBACK_CLIENT_RECEIVE: strncpy(buf, in, sizeof(buf) - 1); lwsl_notice("Client connection received %d from server '%s'\n", len, buf); /* OK we are done with the client connection */ return -1; default: break; } return 0; }
int main(int argc, char **argv) { int n = 0, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1; unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1, pp_secs = 0; struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *prot, *p; char path[300]; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; memset(&info, 0, sizeof info); lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n"); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "Snuv:hsp:d:lC:K:A:P:", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': /* lax SSL, allow selfsigned, skip checking hostname */ use_ssl = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; break; case 'S': /* Strict SSL, no selfsigned, check server hostname */ use_ssl = LCCSCF_USE_SSL; break; case 'p': port = atoi(optarg); break; case 'P': pp_secs = atoi(optarg); lwsl_notice("Setting pingpong interval to %d\n", pp_secs); break; case 'l': longlived = 1; break; case 'v': ietf_version = atoi(optarg); break; case 'u': deny_deflate = 1; break; case 'n': flag_no_mirror_traffic = 1; lwsl_notice("Disabled sending mirror data (for pingpong testing)\n"); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif #endif case 'h': goto usage; } } if (optind >= argc) goto usage; signal(SIGINT, sighandler); memset(&i, 0, sizeof(i)); i.port = port; if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &p)) goto usage; /* add back the leading / on path */ path[0] = '/'; strncpy(path + 1, p, sizeof(path) - 2); path[sizeof(path) - 1] = '\0'; i.path = path; if (!strcmp(prot, "http") || !strcmp(prot, "ws")) use_ssl = 0; if (!strcmp(prot, "https") || !strcmp(prot, "wss")) if (!use_ssl) use_ssl = LCCSCF_USE_SSL; /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, * and if each connection is client or server side. * * For this client-only demo, we tell it to not listen on any port. */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.gid = -1; info.uid = -1; info.ws_ping_pong_interval = pp_secs; if (use_ssl) { info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; /* * If the server wants us to present a valid SSL client certificate * then we can set it up here. */ if (cert_path[0]) info.ssl_cert_filepath = cert_path; if (key_path[0]) info.ssl_private_key_filepath = key_path; /* * A CA cert and CRL can be used to validate the cert send by the server */ if (ca_path[0]) info.ssl_ca_filepath = ca_path; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) else if (crl_path[0]) lwsl_notice("WARNING, providing a CRL requires a CA cert!\n"); #endif #endif #endif } if (use_ssl & LCCSCF_USE_SSL) lwsl_notice(" Using SSL\n"); else lwsl_notice(" SSL disabled\n"); if (use_ssl & LCCSCF_ALLOW_SELFSIGNED) lwsl_notice(" Selfsigned certs allowed\n"); else lwsl_notice(" Cert must validate correctly (use -s to allow selfsigned)\n"); if (use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK) lwsl_notice(" Skipping peer cert hostname check\n"); else lwsl_notice(" Requiring peer cert hostname matches\n"); context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } i.context = context; i.ssl_connection = use_ssl; i.host = i.address; i.origin = i.address; i.ietf_version_or_minus_one = ietf_version; i.client_exts = exts; if (!strcmp(prot, "http") || !strcmp(prot, "https")) { lwsl_notice("using %s mode (non-ws)\n", prot); i.method = "GET"; do_ws = 0; } else lwsl_notice("using %s mode (ws)\n", prot); /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket * * nothing happens until the client websocket connection is * asynchronously established... calling lws_client_connect() only * instantiates the connection logically, lws_service() progresses it * asynchronously. */ while (!force_exit) { if (do_ws) { if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("dumb: connecting\n"); i.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; i.pwsi = &wsi_dumb; lws_client_connect_via_info(&i); } if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { lwsl_notice("mirror: connecting\n"); i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; i.pwsi = &wsi_mirror; wsi_mirror = lws_client_connect_via_info(&i); } } else if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("http: connecting\n"); i.pwsi = &wsi_dumb; lws_client_connect_via_info(&i); } lws_service(context, 500); } lwsl_err("Exiting\n"); lws_context_destroy(context); return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " "<server address> [--port=<p>] " "[--ssl] [-k] [-v <ver>] " "[-d <log bitfield>] [-l]\n"); return 1; }
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *)user; unsigned char buffer[4096 + LWS_PRE]; unsigned long amount, file_len, sent; char leaf_path[1024]; const char *mimetype; char *other_headers; unsigned char *end; struct timeval tv; unsigned char *p; #ifndef LWS_NO_CLIENT struct per_session_data__http *pss1; struct lws *wsi1; #endif char buf[256]; char b64[64]; int n, m; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif // lwsl_err("%s: reason %d\n", __func__, reason); switch (reason) { case LWS_CALLBACK_HTTP: { char name[100], rip[50]; lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); sprintf(buf, "%s (%s)", name, rip); lwsl_notice("HTTP connect from %s\n", buf); } if (len < 1) { lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } #ifndef LWS_NO_CLIENT if (!strncmp(in, "/proxytest", 10)) { struct lws_client_connect_info i; char *rootpath = "/"; const char *p = (const char *)in; if (lws_get_child(wsi)) break; pss->client_finished = 0; memset(&i,0, sizeof(i)); i.context = lws_get_context(wsi); i.address = "git.libwebsockets.org"; i.port = 80; i.ssl_connection = 0; if (p[10]) i.path = (char *)in + 10; else i.path = rootpath; i.host = "git.libwebsockets.org"; i.origin = NULL; i.method = "GET"; i.parent_wsi = wsi; i.uri_replace_from = "git.libwebsockets.org/"; i.uri_replace_to = "/proxytest/"; if (!lws_client_connect_via_info(&i)) { lwsl_err("proxy connect fail\n"); break; } break; } #endif #if 1 /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); goto try_to_reuse; } #endif /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ lwsl_notice("%s\n", in); if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len, LWS_O_RDONLY); if (pss->fd == LWS_INVALID_FILE) { lwsl_err("faild to open file %s\n", leaf_path); return -1; } /* * we will send a big jpeg file, but it could be * anything. Set the Content-Type: appropriately * so the browser knows what to do with it. * * Notice we use the APIs to build the header, which * will do the right thing for HTTP 1/1.1 and HTTP2 * depending on what connection it happens to be working * on */ if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"image/jpeg", 10, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, file_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; /* * send the http headers... * this won't block since it's the first payload sent * on the connection since it was established * (too small for partial) * * Notice they are sent using LWS_WRITE_HTTP_HEADERS * which also means you can't send body too in one step, * this is mandated by changes in HTTP2 */ *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) { lws_plat_file_close(wsi, pss->fd); return -1; } /* * book us a LWS_CALLBACK_HTTP_WRITEABLE callback */ lws_callback_on_writable(wsi); break; } /* if not, send a file the easy way */ if (!strncmp(in, "/cgit-data/", 11)) { in = (char *)in + 11; strcpy(buf, "/usr/share/cgit"); } else strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(buf) - 1); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); lws_return_http_status(wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = leaf_path; p = (unsigned char *)leaf_path; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; } if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *) "max-age=15768000 ; " "includeSubDomains", 36, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: strncpy(buf, in, 20); buf[20] = '\0'; if (len < 20) buf[len] = '\0'; lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n", (const char *)buf, (int)len); break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* the whole of the sent body arrived, close or reuse the connection */ lws_return_http_status(wsi, HTTP_STATUS_OK, NULL); goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n"); if (pss->client_finished) return -1; if (pss->fd == LWS_INVALID_FILE) goto try_to_reuse; #ifdef LWS_WITH_CGI if (pss->reason_bf & 1) { if (lws_cgi_write_split_stdout_headers(wsi) < 0) goto bail; pss->reason_bf &= ~1; break; } #endif #ifndef LWS_NO_CLIENT if (pss->reason_bf & 2) { char *px = buf + LWS_PRE; int lenx = sizeof(buf) - LWS_PRE; /* * our sink is writeable and our source has something * to read. So read a lump of source material of * suitable size to send or what's available, whichever * is the smaller. */ pss->reason_bf &= ~2; wsi1 = lws_get_child(wsi); if (!wsi1) break; if (lws_http_client_read(wsi1, &px, &lenx) < 0) goto bail; if (pss->client_finished) return -1; break; } #endif /* * we can send more of whatever it is we were sending */ sent = 0; do { /* we'd like the send this much */ n = sizeof(buffer) - LWS_PRE; /* but if the peer told us he wants less, we can adapt */ m = lws_get_peer_write_allowance(wsi); /* -1 means not using a protocol that has this info */ if (m == 0) /* right now, peer can't handle anything */ goto later; if (m != -1 && m < n) /* he couldn't handle that much */ n = m; n = lws_plat_file_read(wsi, pss->fd, &amount, buffer + LWS_PRE, n); /* problem reading, close conn */ if (n < 0) { lwsl_err("problem reading file\n"); goto bail; } n = (int)amount; /* sent it all, close conn */ if (n == 0) goto penultimate; /* * To support HTTP2, must take care about preamble space * * identification of when we send the last payload frame * is handled by the library itself if you sent a * content-length header */ m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP); if (m < 0) { lwsl_err("write failed\n"); /* write failed, close conn */ goto bail; } if (m) /* while still active, extend timeout */ lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5); sent += m; } while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024)); later: lws_callback_on_writable(wsi); break; penultimate: lws_plat_file_close(wsi, pss->fd); pss->fd = LWS_INVALID_FILE; goto try_to_reuse; bail: lws_plat_file_close(wsi, pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default unhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ break; #ifndef LWS_NO_CLIENT case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { char ctype[64], ctlen = 0; lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n"); p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(lws_get_parent(wsi), 200, &p, end)) return 1; if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE); if (ctlen > 0) { if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)ctype, ctlen, &p, end)) return 1; } #if 0 if (lws_add_http_header_content_length(lws_get_parent(wsi), file_len, &p, end)) return 1; #endif if (lws_finalize_http_header(lws_get_parent(wsi), &p, end)) return 1; *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) return -1; break; } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); return -1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; // lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n", // wsi, lws_get_socket_fd(wsi), // lws_get_parent(wsi), // lws_get_socket_fd(lws_get_parent(wsi)), len); pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->reason_bf |= 2; lws_callback_on_writable(lws_get_parent(wsi)); break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len); assert(lws_get_parent(wsi)); m = lws_write(lws_get_parent(wsi), (unsigned char *)in, len, LWS_WRITE_HTTP); if (m < 0) return -1; break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->client_finished = 1; break; #endif #ifdef LWS_WITH_CGI /* CGI IO events (POLLIN/OUT) appear here our demo user code policy is * * - POST data goes on subprocess stdin * - subprocess stdout goes on http via writeable callback * - subprocess stderr goes to the logs */ case LWS_CALLBACK_CGI: pss->args = *((struct lws_cgi_args *)in); //lwsl_notice("LWS_CALLBACK_CGI: ch %d\n", pss->args.ch); switch (pss->args.ch) { /* which of stdin/out/err ? */ case LWS_STDIN: /* TBD stdin rx flow control */ break; case LWS_STDOUT: pss->reason_bf |= 1; /* when writing to MASTER would not block */ lws_callback_on_writable(wsi); break; case LWS_STDERR: n = read(lws_get_socket_fd(pss->args.stdwsi[LWS_STDERR]), buf, 127); //lwsl_notice("stderr reads %d\n", n); if (n > 0) { if (buf[n - 1] != '\n') buf[n++] = '\n'; buf[n] = '\0'; lwsl_notice("CGI-stderr: %s\n", buf); } break; } break; case LWS_CALLBACK_CGI_TERMINATED: //lwsl_notice("LWS_CALLBACK_CGI_TERMINATED\n"); /* because we sent on openended http, close the connection */ return -1; case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */ //lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA\n"); pss->args = *((struct lws_cgi_args *)in); n = write(lws_get_socket_fd(pss->args.stdwsi[LWS_STDIN]), pss->args.data, pss->args.len); //lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: write says %d", n); if (n < pss->args.len) lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: sent %d only %d went", n, pss->args.len); return n; #endif /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_unlock(len); break; #ifdef EXTERNAL_POLL case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "lws_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; }
void FLwsWebSocket::Connect() { bIsConnecting = true; if (LwsContext == nullptr) { DelayConnectionError(TEXT("Invalid context")); return; } if (LwsConnection != nullptr) { DelayConnectionError(TEXT("Already connected")); return; } struct lws_client_connect_info ConnectInfo = {}; ConnectInfo.context = LwsContext; FTCHARToUTF8 UrlUtf8(*Url); const char *UrlProtocol, *TmpUrlPath; char UrlPath[300]; if (lws_parse_uri((char*) UrlUtf8.Get(), &UrlProtocol, &ConnectInfo.address, &ConnectInfo.port, &TmpUrlPath)) { DelayConnectionError(TEXT("Bad URL")); return; } UrlPath[0] = '/'; FCStringAnsi::Strncpy(UrlPath+1, TmpUrlPath, sizeof(UrlPath)-2); UrlPath[sizeof(UrlPath)-1]='\0'; ConnectInfo.path = UrlPath; ConnectInfo.host = ConnectInfo.address; ConnectInfo.origin = ConnectInfo.address; ConnectInfo.ietf_version_or_minus_one = -1; ConnectInfo.client_exts = LwsExtensions; // Use SSL and require a valid cerver cert if (FCStringAnsi::Stricmp(UrlProtocol, "wss") == 0 ) { ConnectInfo.ssl_connection = 1; } // Use SSL, and allow self-signed certs else if (FCStringAnsi::Stricmp(UrlProtocol, "wss+insecure") == 0 ) { ConnectInfo.ssl_connection = 2; } // No encryption else if (FCStringAnsi::Stricmp(UrlProtocol, "ws") == 0 ) { ConnectInfo.ssl_connection = 0; } // Else return an error else { DelayConnectionError(FString::Printf(TEXT("Bad protocol '%s'. Use either 'ws', 'wss', or 'wss+insecure'"), UTF8_TO_TCHAR(UrlProtocol))); return; } FString Combined = FString::Join(Protocols, TEXT(",")); FTCHARToUTF8 CombinedUTF8(*Combined); ConnectInfo.protocol = CombinedUTF8.Get(); ConnectInfo.userdata = this; if (lws_client_connect_via_info(&ConnectInfo) == nullptr) { DelayConnectionError(TEXT("Could not initialize connection")); } }
int main(int argc, char *argv[]) { //setup signal handler to detect if the mirror //wants to terminate this program. struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); action.sa_handler = terminate; sigaction(SIGTERM, &action, NULL); //start of program here lws_set_log_level(0, NULL); char protoName[1024]; strcpy(protoName, argv[1]); struct lws_context *context = NULL; struct lws_context_creation_info info; struct lws *wsi = NULL; struct lws_protocols protocol; struct lws_client_connect_info i; memset(&info, 0, sizeof info); info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = &protocol; info.max_http_header_pool = 128; info.gid = -1; info.uid = -1; protocol.name = protoName; protocol.callback = ws_service_callback; protocol.per_session_data_size = sizeof(struct session_data); protocol.rx_buffer_size = 125; printf("Creating context\n"); context = lws_create_context(&info); printf(KRED"[Main] context created.\n"RESET); if (context == NULL) { printf(KRED"[Main] context is NULL.\n"RESET); return -1; } printf("Connecting...\n"); const char *prot; if (lws_parse_uri(server, &prot, &i.address, &i.port, &i.path)) { printf("Client.c: Error parsing uri\n"); exit(1); } i.port = 5000; i.context = context; i.ssl_connection = 0; i.host = i.address; i.origin = i.address; i.ietf_version_or_minus_one = -1; i.protocol = protoName; //struct lws *wsi = NULL; const struct timespec sleepTime = { 0, NANOSECOND/FPS }; char command[256]; int left = 0, dir = 1; if (!connection_flag || !wsi) { wsi = lws_client_connect_via_info(&i); } while(!destroy_flag) { lws_service(context, 0); if (!connection_flag || !wsi) continue; left += (dir * SPEED); if (left > SCREEN_WIDTH) dir = -dir; else if (left < 0) dir = -dir; sprintf(command, "{\"command\":\"setcss\",\"data\":\"left=%dpx\"}", left); websocket_write_back(wsi, command, -1); nanosleep(&sleepTime, NULL); } lws_context_destroy(context); return 0; }
int main(int argc, char **argv) { int n = 0, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1; unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1; struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *prot, *p; char path[300]; memset(&info, 0, sizeof info); lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n"); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': use_ssl = 2; /* 2 = allow selfsigned */ break; case 'p': port = atoi(optarg); break; case 'l': longlived = 1; break; case 'v': ietf_version = atoi(optarg); break; case 'u': deny_deflate = 1; break; case 'n': deny_mux = 1; break; case 'h': goto usage; } } if (optind >= argc) goto usage; signal(SIGINT, sighandler); memset(&i, 0, sizeof(i)); i.port = port; if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &p)) goto usage; /* add back the leading / on path */ path[0] = '/'; strncpy(path + 1, p, sizeof(path) - 2); path[sizeof(path) - 1] = '\0'; i.path = path; if (!strcmp(prot, "http") || !strcmp(prot, "ws")) use_ssl = 0; if (!strcmp(prot, "https") || !strcmp(prot, "wss")) use_ssl = 1; /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, * and if each connection is client or server side. * * For this client-only demo, we tell it to not listen on any port. */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.gid = -1; info.uid = -1; if (use_ssl) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } i.context = context; i.ssl_connection = use_ssl; i.host = i.address; i.origin = i.address; i.ietf_version_or_minus_one = ietf_version; i.client_exts = exts; if (!strcmp(prot, "http") || !strcmp(prot, "https")) { lwsl_notice("using %s mode (non-ws)\n", prot); i.method = "GET"; do_ws = 0; } else lwsl_notice("using %s mode (ws)\n", prot); /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket * * nothing happens until the client websocket connection is * asynchronously established... calling lws_client_connect() only * instantiates the connection logically, lws_service() progresses it * asynchronously. */ while (!force_exit) { if (do_ws) { if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("dumb: connecting\n"); i.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; wsi_dumb = lws_client_connect_via_info(&i); } if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { lwsl_notice("mirror: connecting\n"); i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; wsi_mirror = lws_client_connect_via_info(&i); } } else if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("http: connecting\n"); wsi_dumb = lws_client_connect_via_info(&i); } lws_service(context, 500); } lwsl_err("Exiting\n"); lws_context_destroy(context); return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " "<server address> [--port=<p>] " "[--ssl] [-k] [-v <ver>] " "[-d <log bitfield>] [-l]\n"); return 1; }
int websocket_init(struct lws_context **context, struct lws **wsi, char *host, char *path, int port, void *handle ){ struct lws_context *c; struct lws *w; const char *interface = NULL; const char *cert_path = NULL; const char *key_path = NULL; int use_ssl = 0; int opts = 0; int ietf_version = -1; struct lws_context_creation_info info; if(handle == NULL){ ERROR("Socket handler not found"); return WEBSOCKET_FAIL; } if(host == NULL){ ERROR("Host not found"); return WEBSOCKET_FAIL; } memset(&info, 0, sizeof info); info.port = CONTEXT_PORT_NO_LISTEN; info.iface = interface; info.protocols = protocols; info.extensions = NULL; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; info.gid = -1; info.uid = -1; info.options = opts; info.user = handle; info.ka_time = 25000; info.ka_probes = 3; info.ka_interval = 500; // set log level to debug so that we dont get notice messages lws_set_log_level(LLL_ERR, NULL); // create libwebsockets context *context = lws_create_context(&info); if (context == NULL) { ERROR("libwebsocket init failed"); return WEBSOCKET_FAIL; } // connect to handle struct lws_client_connect_info connect_info; memset(&connect_info, 0, sizeof(connect_info)); connect_info.context = *context; connect_info.address = host; connect_info.port = port; connect_info.ssl_connection = use_ssl; connect_info.path = path; connect_info.host = host; connect_info.origin = host; connect_info.protocol = NULL; connect_info.ietf_version_or_minus_one = ietf_version; *wsi = lws_client_connect_via_info(&connect_info); if(wsi == NULL){ ERROR("libwebsocket connect failed"); return WEBSOCKET_FAIL; } return WEBSOCKET_SUCCESS; }
Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) { ERR_FAIL_COND_V(context != NULL, FAILED); IP_Address addr; if (!p_host.is_valid_ip_address()) { addr = IP::get_singleton()->resolve_hostname(p_host); } else { addr = p_host; } ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER); // Prepare protocols _lws_make_protocols(this, &LWSClient::_lws_gd_callback, p_protocols, &_lws_ref); // Init lws client struct lws_context_creation_info info; struct lws_client_connect_info i; memset(&i, 0, sizeof i); memset(&info, 0, sizeof info); info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = _lws_ref->lws_structs; info.gid = -1; info.uid = -1; //info.ws_ping_pong_interval = 5; info.user = _lws_ref; #if defined(LWS_OPENSSL_SUPPORT) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; #endif context = lws_create_context(&info); if (context == NULL) { _lws_free_ref(_lws_ref); _lws_ref = NULL; ERR_EXPLAIN("Unable to create lws context"); ERR_FAIL_V(FAILED); } i.context = context; if (p_protocols.size() > 0) i.protocol = _lws_ref->lws_names; else i.protocol = NULL; if (p_ssl) { i.ssl_connection = LCCSCF_USE_SSL; if (!verify_ssl) i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; } else { i.ssl_connection = 0; } // These CharStrings needs to survive till we call lws_client_connect_via_info CharString addr_ch = ((String)addr).ascii(); CharString host_ch = p_host.utf8(); CharString path_ch = p_path.utf8(); i.address = addr_ch.get_data(); i.host = host_ch.get_data(); i.path = path_ch.get_data(); i.port = p_port; lws_client_connect_via_info(&i); return OK; };
Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) { ERR_FAIL_COND_V(context != NULL, FAILED); IP_Address addr; if (!p_host.is_valid_ip_address()) { addr = IP::get_singleton()->resolve_hostname(p_host); } else { addr = p_host; } ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER); // prepare protocols if (p_protocols.size() == 0) // default to binary protocol p_protocols.append("binary"); _lws_make_protocols(this, &LWSClient::_lws_gd_callback, p_protocols, &_lws_ref); // init lws client struct lws_context_creation_info info; struct lws_client_connect_info i; memset(&i, 0, sizeof i); memset(&info, 0, sizeof info); info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = _lws_ref->lws_structs; info.gid = -1; info.uid = -1; //info.ws_ping_pong_interval = 5; info.user = _lws_ref; #if defined(LWS_OPENSSL_SUPPORT) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; #endif context = lws_create_context(&info); if (context == NULL) { _lws_free_ref(_lws_ref); _lws_ref = NULL; ERR_EXPLAIN("Unable to create lws context"); ERR_FAIL_V(FAILED); } char abuf[1024]; char hbuf[1024]; char pbuf[2048]; String addr_str = (String)addr; strncpy(abuf, addr_str.ascii().get_data(), 1024); strncpy(hbuf, p_host.utf8().get_data(), 1024); strncpy(pbuf, p_path.utf8().get_data(), 2048); i.context = context; i.protocol = _lws_ref->lws_names; i.address = abuf; i.host = hbuf; i.path = pbuf; i.port = p_port; if (p_ssl) { i.ssl_connection = LCCSCF_USE_SSL; if (!verify_ssl) i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; } else { i.ssl_connection = 0; } lws_client_connect_via_info(&i); return OK; };