Connection between DTLS server and client not working - c++

I am developing a DTLS server and client. But there is no handshake between them.
PS I made a cut from the project in order to reduce the amount of code. If you forgot something - do not kick ...
a common part
static int dtls_verify_callback(int ok, X509_STORE_CTX* ctx) {
return ok;
}
static int generate_cookie(SSL* ssl, unsigned char* cookie, unsigned int* cookie_len) {
unsigned int i;
for (i = 0; i < COOKIE_LEN; i++, cookie++)
*cookie = i;
*cookie_len = COOKIE_LEN;
return 1;
}
static int verify_cookie(SSL* ssl,
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const
#endif
unsigned char* cookie,
unsigned int cookie_len) {
unsigned int i;
if (cookie_len != COOKIE_LEN)
return 0;
for (i = 0; i < COOKIE_LEN; i++, cookie++) {
if (*cookie != i)
return 0;
}
return 1;
}
Server side
int main() {
int iTimeout = 1000;
ADDRINFOW* pAddressInfo;
ADDRINFOW AddressHints;
WSADATA WinsockData;
LPCWSTR lpwszAddress = L"";
SOCKET socket;
union {
struct sockaddr_storage ss;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} server_addr, client_addr;
const TIMEVAL Timeout = { iTimeout / 1000, (iTimeout % 1000) * 1000 };
if (1 != OPENSSL_init_ssl(0
| OPENSSL_INIT_NO_LOAD_CONFIG
| OPENSSL_INIT_ASYNC
| OPENSSL_INIT_ENGINE_DYNAMIC
| OPENSSL_INIT_ENGINE_ALL_BUILTIN
| OPENSSL_INIT_NO_ATEXIT
| OPENSSL_INIT_LOAD_SSL_STRINGS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, nullptr))
{
return 1;
}
WSAStartup(MAKEWORD(2, 2), &WinsockData);
auto ctx = unique_ptr_c<SSL_CTX>(SSL_CTX_new(DTLS_server_method()), SSL_CTX_free);
auto cert_store = unique_ptr_c<X509_STORE>(X509_STORE_new(), X509_STORE_free);
X509_STORE_load_locations(cert_store.get(), "certs/ca-cert.pem", nullptr);
SSL_CTX_set1_verify_cert_store(ctx.get(), cert_store.get());
if (!SSL_CTX_use_certificate_chain_file(ctx.get(), "certs/server-cert.pem"))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_use_PrivateKey_file(ctx.get(), "certs/server-key.pem", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_check_private_key(ctx.get()))
{
ERR_print_errors_fp(stderr);
}
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx.get(), 1);
SSL_CTX_set_cookie_generate_cb(ctx.get(), generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx.get(), verify_cookie);
memset(&AddressHints, 0, sizeof(AddressHints));
AddressHints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
AddressHints.ai_family = AF_UNSPEC;
AddressHints.ai_socktype = SOCK_DGRAM;
AddressHints.ai_protocol = 0;
iResult = GetAddrInfoW(lpwszAddress, 12345, &AddressHints, &pAddressInfo);
if (0 != iResult)
{
}
else
{
for (const ADDRINFOW* pCurrentAddressInfo = pAddressInfo; nullptr != pCurrentAddressInfo; pCurrentAddressInfo = pCurrentAddressInfo->ai_next)
{
socket = socket(pCurrentAddressInfo->ai_family, pCurrentAddressInfo->ai_socktype, pCurrentAddressInfo->ai_protocol);
if (INVALID_SOCKET == CurrentSocket) { continue; }
if (SOCKET_ERROR == bind(CurrentSocket, pCurrentAddressInfo->ai_addr, static_cast<int>(pCurrentAddressInfo->ai_addrlen)))
{
(void)closesocket(CurrentSocket);
continue;
}
if (SOCKET_ERROR == setsockopt(CurrentSocket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char*>(&iTimeout), sizeof(iTimeout))) { }
break;
}
}
for (;;)
{
if (SOCKET_ERROR == select(0, &socket, nullptr, nullptr, &Timeout)) {}
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
auto bio = BIO_new_dgram(socket, BIO_NOCLOSE);
auto ssl = unique_ptr_c<SSL>(SSL_new(ctx.get()), SSL_close_and_free);
SSL_set_bio(ssl.get(), bio, bio);
SSL_set_options(ssl.get(), SSL_OP_COOKIE_EXCHANGE);
while (iResult <= 0) {
iResult = DTLSv1_listen(ssl.get(), (BIO_ADDR*)&client_addr);
if (iResult <= 0) { }
}
BIO_set_fd(SSL_get_rbio(ssl.get()), socket, BIO_NOCLOSE);
BIO_ctrl(SSL_get_rbio(ssl.get()), BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr);
iResult = SSL_accept(ssl.get());
if (iResult != 1) {
printf("%s\n", ERR_error_string(ERR_peek_last_error(), NULL));
printf("%s\n", ERR_error_string(ERR_get_error(), buf));
}
else
{
// I didn't cut the code further, since it never goes here
}
}
}
Client side
int main() {
ADDRINFOW AddressHints;
SOCKET ClientSocket = INVALID_SOCKET;
memset(&AddressHints, 0, sizeof(AddressHints));
AddressHints.ai_family = AF_UNSPEC;
AddressHints.ai_socktype = SOCK_DGRAM;
AddressHints.ai_protocol = 0;
int iResult = GetAddrInfoW(lpwszHost, wszPort, &AddressHints, &pAddressInfo);
if (0 != iResult)
{
}
else
{
unique_ptr_c<SSL_CTX> ctx;
unique_ptr_c<SSL> ssl;
BIO* bio;
if (1 != OPENSSL_init_ssl(0
| OPENSSL_INIT_NO_LOAD_CONFIG
| OPENSSL_INIT_ASYNC
| OPENSSL_INIT_ENGINE_DYNAMIC
| OPENSSL_INIT_ENGINE_ALL_BUILTIN
| OPENSSL_INIT_NO_ATEXIT
| OPENSSL_INIT_LOAD_SSL_STRINGS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, nullptr))
{
return 1;
}
ctx = unique_ptr_c<SSL_CTX>(SSL_CTX_new(DTLS_client_method()), SSL_CTX_free);
auto cert_store = unique_ptr_c<X509_STORE>(X509_STORE_new(), X509_STORE_free);
X509_STORE_load_locations(cert_store.get(), "certs/ca-cert.crt", nullptr);
SSL_CTX_set1_verify_cert_store(ctx.get(), cert_store.get());
iResult = SSL_CTX_use_certificate_chain_file(ctx.get(), "certs/client-cert.pem");
if (!iResult)
{
ERR_print_errors_fp(stderr);
}
iResult = SSL_CTX_use_PrivateKey_file(ctx.get(), "certs/client-key.pem", SSL_FILETYPE_PEM);
if (!iResult)
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_check_private_key(ctx.get()))
{
ERR_print_errors_fp(stderr);
}
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx.get(), 1);
SSL_CTX_set_cookie_generate_cb(ctx.get(), generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx.get(), verify_cookie);
ssl = unique_ptr_c<SSL>(SSL_new(ctx.get()), SSL_close_and_free);
for (pCurrentAddressInfo = pAddressInfo; nullptr != pCurrentAddressInfo; pCurrentAddressInfo = pCurrentAddressInfo->ai_next)
{
ClientSocket = socket(pCurrentAddressInfo->ai_family, pCurrentAddressInfo->ai_socktype, pCurrentAddressInfo->ai_protocol);
if (INVALID_SOCKET == ClientSocket)
{
continue;
}
iResult = connect(ClientSocket, pCurrentAddressInfo->ai_addr, static_cast<int>(pCurrentAddressInfo->ai_addrlen));
if (SOCKET_ERROR == iResult)
{
}
else
{
break;
}
if (SOCKET_ERROR == closesocket(ClientSocket))
{
}
}
if (nullptr != pCurrentAddressInfo)
{
if (SOCKET_ERROR == setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&iTimeout), sizeof(iTimeout)))
{
iResult = WSAGetLastError();
}
else
{
bio = BIO_new_dgram(ClientSocket, BIO_NOCLOSE);
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, remote_address.get());
SSL_set_bio(ssl.get(), bio, bio);
iResult = SSL_connect(ssl.get()); // Trying 5 handshakes fails with an SSL_ERROR_SYSCALL error
if (iResult <= 0) {
char buf[BUFFER_SIZE];
//print_errors_stderr();
ERR_print_errors_fp(stderr);
printf("%s\n", ERR_error_string(ERR_peek_last_error(), NULL));
printf("%s\n", ERR_error_string(ERR_get_error(), buf));
switch (SSL_get_error(ssl.get(), iResult)) {
...
case SSL_ERROR_SYSCALL:
ERR_print_errors_fp(stderr);
DBG_MSG((DBG_ERR, L"DTLSClient::Send: SSL_connect failed with SSL_ERROR_SYSCALL"));
break;
...
}
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
}
else
{
// I didn't cut the code further, since it never goes here
}
}
// Close the socket
if (SOCKET_ERROR == closesocket(ClientSocket))
{
}
}
}
}
The client tries 5 times to make a handshake with the server but it doesn't work.
An error occurs from the client side on the line iResult = SSL_connect(ssl.get()) - an error occurs:
error:00000000:lib(0)::reason(0)
ERR: DTLSClient::Send: SSL_connect failed with SSL_ERROR_SYSCALL
An error occurs on the server at the line iResult = SSL_accept(ssl.get()) - with the error:
SSL_accept: No error
error:00000000:lib(0)::reason(0)
Based on traffic
enter image description here
Client sends - Client Hello
The server replies to this - Hello verify Request
And then the client tries to answer something back. Now I don't know what to do next. Are there any ideas?
I tried to do it as in the examples from OpenLL and other examples on github.

Related

C++ Socket Programming - Socket won't bind. While working earlier

I have created a Socket class, everything was working perfect earlier. And just now every time I try to bind the socket server-side, it throws a bind error with message "Address already in use" while the port is free.
I am using macOS.
Should i use AF_INET or AF_UNIX?
This some of the code for the socket & bind.
// socket object class.
class Socket {
public:
int sock;
string address;
string port;
struct addrinfo address_info;
bool connected;
// initialize.
public:
Socket(string address__ = "", string port__ = "", bool initialize = false, int domain = -999, int type = -999, int protocol = -999) {
address = address__;
port = port__;
connected = false;
if (domain == -999) {
//domain = AF_INET;
domain = AF_UNIX;
//domain = 2;
} if (type == -999) {
type = SOCK_STREAM;
} if (protocol == -999) {
protocol = 0;
}
memset(&address_info, 0, sizeof address_info);
address_info.ai_family = domain;
address_info.ai_socktype = type;
address_info.ai_protocol = protocol;
if (initialize) {
print("Initialize socket...");
sock = socket(address_info.ai_family, address_info.ai_socktype, address_info.ai_protocol);
if (sock < 0) {
int e = errno;
string error = "BindError: Unable to initialize the socket.";
print(error);
throw BindError(error);
}
}
}
// bind server.
public:
int bind() {
int optVal = 1;
set_opt(SOL_SOCKET, SO_REUSEADDR, &optVal);
if (address_info.ai_family == AF_UNIX) {
//print("UNIX");
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, address.c_str(), sizeof(addr.sun_path)-1);
int status = ::bind(sock, (struct sockaddr*)&addr, sizeof(addr));
if (status < 0) {
int e = errno;
string error = "BindError: Unable to bind with "+address+":"+port+" - "+strerror(e)+".";
print(error);
throw BindError(error);
}
return status;
}
//print("NON UNIX");
int status;
struct addrinfo *res;
address_info.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(address.c_str(), port.c_str(), &address_info, &res)) != 0) {
throw std::runtime_error("GetInfoError"); // gai_strerror(errno)
}
address_info.ai_addrlen = res->ai_addrlen;
address_info.ai_addr = res->ai_addr;
freeaddrinfo(res);
int max_attempts = 1;
for (int attempt = 0; attempt < max_attempts; ++ attempt) {
status = ::bind(sock, address_info.ai_addr, address_info.ai_addrlen);
if (status >= 0) {
break;
}
if (status < 0 && attempt >= max_attempts - 1) {
//cout << sock << " - " << address_info.ai_addr << " - " << address_info.ai_addrlen << " - " << "\n";
int e = errno;
string error = "BindError: Unable to bind with "+address+":"+port+" - "+strerror(e)+".";
print(error);
throw BindError(error);
}
}
return status;
}
};
Does anyone have an idea how to fix this?

C++ Socket API "Heartbeat"

I'm trying to make a simple heartbeat check from client to server and vice-versa, if connection on either is broken off unexpectedly it prints a message and calls closesocket.
I spent 8 hours on this and it still isn't acceptable to my mentor. Right now I got something that works, but if breakpoint is placed before while loop and connected client is forcefully closed, trying to go past breakpoint causes crash when it should break the loop and write out error.
Server side code:
int main(int argc, char *argv[])
{
SOCKET s, sa;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
srv_address.sin_port = htons(1099);
bind(s, (sockaddr*) &srv_address, sizeof(srv_address));
int l = listen(s, 10);
if (l < 0)
printf("Listen error\n");
else
{
printf("Listen OK. Listening on port %u\n",
htons(srv_address.sin_port));
sa = accept(s, NULL, NULL);
while (true)
{
char buffer[1000];
int nRecvLen = recv(sa, buffer, 999, 0);
buffer[nRecvLen] = '\0';
int r = recv(sa, NULL, 0, 0);
if (r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
printf("Konekcija je naglo prekinuta!\n");
break;
}
else
{
if (nRecvLen > 0)
{
for (int i = 0; i < nRecvLen; i++)
{
cout << buffer[i];
}
}
}
}
closesocket(sa);
closesocket(s);
}
WSACleanup();
return 0;
}
and client side:
int main()
{
SOCKET s;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_un_b.s_b1 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b2 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b3 = x;
srv_address.sin_addr.S_un.S_un_b.s_b4 = xxx;
srv_address.sin_port = htons(1099);
int c = connect(s, (sockaddr*) &srv_address, sizeof(srv_address));
if (c < 0)
{
printf("Connection error\n");
cout << (WSAGetLastError());
}
else
{
string l = "Heartbeat\n";
int p = l.size();
char buff[1000];
strcpy_s(buff, l.c_str());
printf("Connected\n");
while (true)
{
if (send(s, buff, p, 0) > 0)
{
Sleep(1000);
}
else
{
printf("Konekcija je naglo prekinuta\n");
shutdown(s, SD_BOTH);
closesocket(s);
break;
}
}
WSACleanup();
return 0;
}
}

socket descriptor closes after assignment

I won't post all of the generic socket-code -- unless requested, then no problem.
I listen for connections on an already setup socket:
int
NetworkConnection::ListenForConnections()
{
char s[INET6_ADDRSTRLEN];
fcntl(socketFd, F_SETFL, O_NONBLOCK);
if (listen(socketFd, 15) == -1) {
perror("listen");
exit(1);
}
// sigAction.sa_handler = sigchld_handler; // reap all dead processes
// sigemptyset(&sigAction.sa_mask);
// sigAction.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sigAction, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
sin_size = sizeof theirAddress;
int new_fd = accept(socketFd, (struct sockaddr *)&theirAddress, &sin_size);
if (new_fd == -1) {
perror("accept");
return 1;
}
inet_ntop(theirAddress.ss_family,
get_in_addr((struct sockaddr *)&theirAddress),
s, sizeof s);
printf("server: got connection from %s\n", s);
NodeConnection nc = NodeConnection();
char ipstr[INET6_ADDRSTRLEN];
getpeername(new_fd, (struct sockaddr*)&theirAddress, &sin_size);
struct sockaddr_in *soc = (struct sockaddr_in *)&theirAddress;
int port = ntohs(soc->sin_port);
inet_ntop(AF_INET, &soc->sin_addr, nc.ipstr, sizeof ipstr);
nc.fd = new_fd;
nc.theirAddress = sockaddr_storage(theirAddress);
nc.sin_size = sin_size;
nc.port = port;
newConnections.push_back(nc);
}
This is called from here:
int main(int argc, const char* argv[])
{
RoutingManager *manager = new RoutingManager();
manager->ParseInputFile("topo.txt", 10, 3, " ");
manager->myConnection = new NetworkConnection("localhost", "7771");
manager->myConnection->SetSocketHints();
manager->myConnection->PopulateAddressInfo();
manager->myConnection->BindSocket();
while(1)
{
manager->myConnection->ListenForConnections(); // <- here
if (manager->myConnection->newConnections.size() > 0)
{
manager->ActivateNewNode();
}
}
}
And during the call to ActivateNewNode() I do:
bool
RoutingManager::ActivateNewNode()
{
TopologyIter iter = topology.begin();
do
{
if(!iter->second.online)
{
iter->second.online = true;
iter->second.connection = myConnection->newConnections.back();
myConnection->newConnections.pop_back();
cout << "Connected Activated!\n";
cout << "Node ID: " << iter->second.id << endl;
return true; //all good
}
iter++;
}while (iter != topology.end());
return false; //received a connection, but no more nodes to hand out
}
Where connection is the struct:
struct NodeConnection
{
int fd;
socklen_t sin_size;
struct sockaddr_storage theirAddress;
char ipstr[INET6_ADDRSTRLEN];
int port;
};
This works fine if I comment out the assignment of the connection during the call to ActivateNewNode(). I.e., this line:
iter->second.connection = myConnection->newConnections.back();
However, with it uncommented, then when I loop back through to continue listening for new connections, this snippet fails:
if (listen(socketFd, 15) == -1) {
perror("listen");
exit(1);
}
With the error: bad file descriptor
Can anyone tell me what I'm missing here?
put the listen() out of the while loop.

Error connecting to server by proxy server in c++ socket programming

The code for connection :
cout << "connecting1\n";
WSADATA wsadata;
int iResult = WSAStartup (MAKEWORD(2,2), &wsadata );
if (iResult !=NO_ERROR )
printf("\nmyERROR at WSAStartup()\n");
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("error opening socket"); return -1;
}
struct sockaddr_in sin;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(host.c_str());
sin.sin_family = AF_INET;
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
perror("error connecting to host"); return -1;
}
const int query_len = query.length() + 1; // trailing '\0'
if (send(sock, query.c_str(), query_len, 0) != query_len) {
perror("error sending query"); return -1;
}
const int buf_size = 1024 * 1024;
while (true) {
std::vector<char> buf(buf_size, '\0');
const int recv_len = recv(sock, &buf[0], buf_size - 1, 0);
if (recv_len == -1) {
perror("error receiving response"); return -1;
} else if (recv_len == 0) {
std::cout << std::endl; break;
} else {
std::cout << &buf[0];
fprintf(fp, "%s", &buf[0]);
}
}
In wifi without proxy it works fine, but when we use proxy server, net can be accessed in chrome, but the above code prints
connecting1
error connecting to host
What is the problem ?

Server does not respond to new clients using select(), cpp

I followed this nice tutorial to create a simple non-blocking server using select() function. Here's what I have:
void setNonBlocking(int socketFD) {
int x;
x = fcntl(socketFD,F_GETFL,0);
fcntl(socketFD,F_SETFL,x | O_NONBLOCK);
return;
}
int initialize(char * port) {
int yes = 1;
listener = socket(PF_INET,SOCK_STREAM, 0);
if (listener < 0) {
perror("listener");
exit(EXIT_FAILURE);
}
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
setNonBlocking(listener);
struct sockaddr_in server_address;
memset((char *) &server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
// server_address.sin_addr.s_addr = htonl(INADDR_ANY);
inet_aton("132.65.151.39",&(server_address.sin_addr));
server_address.sin_port = htons(atoi(port));
if (bind(listener, (struct sockaddr *) &server_address,
sizeof(server_address)) < 0 ) {
perror("bind");
close(listener);
exit(EXIT_FAILURE);
}
listen(listener,BACKLOG);
maxSocket = listener;
memset((char *) &clientQueue, 0, sizeof(clientQueue));
return 0;
}
void readSockets() {
int i;
cout << "in readSockets()" << endl;
if (FD_ISSET(listener,&sockets))
createConnection();
for (i = 0; i < 5; i++) {
if (FD_ISSET(clientQueue[i],&sockets))
readData(i);
} /* for (all entries in queue) */
}
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr,"usage: server port\n");
exit(EXIT_FAILURE);
}
if (initialize(argv[1]) != 0) {
exit(EXIT_FAILURE);
}
struct timeval timeout;
int value;
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
build_select_list();
timeout.tv_sec = 1;
timeout.tv_usec = 0;
value = select(maxSocket, &sockets, (fd_set *) 0,(fd_set *) 0, &timeout);
if (value == -1) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
printf("%d",value);
fflush(stdout);
} else{
cout << "Value is " << value << endl;
readSockets();
}
}
return EXIT_SUCCESS;
}
My problem is simple - select always returns 0, meaning it does not get or does not respond to a new connection. I checked my client a day ago with a blocking more simple server and it did work, so I don't think its the porblem.
You'll notice that I tried both IP addresses:
server_address.sin_family = AF_INET;
// server_address.sin_addr.s_addr = htonl(INADDR_ANY);
Can anyone please help me? I feel lost :)
Please refer to man select, first parameter should be number of highest descriptor + 1, so in your case:
value = select(maxSocket + 1, &sockets, (fd_set *) 0,(fd_set *) 0, &timeout);