Under libwebsockets, how to receive message bigger than 4096 on server side? - libwebsockets

I have create a websocket server with libwebsockets library, and the protocol list is like this:
/* List of supported protocols and callbacks. */
static struct libwebsocket_protocols protocols[] = {
{ "plain-websocket-protocol" /* Custom name. */,
callback_websocket,
sizeof(struct websocket_client_real),
0 },
{ NULL, NULL, 0, 0 } /* Terminator. */
};
When I use "html + javascript + chromium browser" as client to send websocket message bigger than 4096 bytes, the websocket server will receive the LWS_CALLBACK_RECEIVE callback more than one time, one message is splited to two or more, the max receive size is 4096.
How can I receive unlimited size websocket message on server side?

The lws_protocols struct now has a rx_buffer_size member so you should be able to configure the 4096 size using this.
See the api doc for details https://libwebsockets.org/libwebsockets-api-doc.html

This answer will address this question:
How can I receive unlimited size websocket message on server side?
It's relatively simple, actually. And you don't need to change your rx_buffer_size like it was suggested before.
Check out the function size_t lws_remaining_packet_payload(struct lws *wsi) documented in here: https://libwebsockets.org/libwebsockets-api-doc.html
You can use this function in your LWS_CALLBACK_RECEIVE callback handler to determine if the data your callback was given finishes a complete WebSocket "packet" (aka, message). If this function returns nonzero, then there is more data coming for this packet in a future callback. So your application should buffer this data until lws_remaining_packet_payload(wsi) returns 0. At that point, you have read a complete message and can handle the complete message as appropriate.

Related

Why does UDPSocket.send always call getaddrinfo in Ruby?

I just solved a latency issue in our infrastructure that was triggered because this code snippet here triggered a call to getaddrinfo on every run of the code:
sock = UDPSocket.open
sock.send("#{key}|#{value}", 0,
GRAPHITE_SERVER,
STATSD_PORT)
sock.close
Because we use statsd and graphite for high-volume event and stats monitoring, we were effectively triggering numerous calls getaddrinfo on every API call, and potentially tens of thousands every minute.
I modified this code to use the internal IP address, not the DNS name, of our graphite server, and was able to resolve the latency issue (presumably because the internal AWS VPC DNS server was not equipped to handle such a high volume of requests).
Now that my issue is resolved, I would love to know why the UDP implementation in Ruby is not using a cached IP address value (presumably based on the TTL of the domain name entry). Here is the relevant line and the function in full, you can see the call to rsock_addrinfo just at the end:
static VALUE
udp_send(int argc, VALUE *argv, VALUE sock)
{
VALUE flags, host, port;
struct udp_send_arg arg;
VALUE ret;
if (argc == 2 || argc == 3) {
return rsock_bsock_send(argc, argv, sock);
}
rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);
StringValue(arg.sarg.mesg);
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
return ret;
}
I assume this decision is intentional and would love to learn more about the reasons why.
getaddrinfo does not return data about the TTL... because it may not have it at all in fact, as the resolution may not necessarily be done over the DNS (could be hosts file, LDAP, etc. see /etc/nsswitch.conf)
From its manual here is the structure returned:
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
struct addrinfo {
int ai_flags; /* input flags */
int ai_family; /* protocol family for socket */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol for socket */
socklen_t ai_addrlen; /* length of socket-address */
struct sockaddr *ai_addr; /* socket-address for socket */
char *ai_canonname; /* canonical name for service location */
struct addrinfo *ai_next; /* pointer to next in list */
};
After a successful call to getaddrinfo(), *res is a pointer to a linked list of one or more addrinfo structures.
So it is up to the thing "behind" getaddrinfo to do some caching or not, because getaddrinfo may have used the DNS to retrieve data, or not.
Some specific API for DNS, like getdnsapi will give back to the caller some information on the TTL, see https://getdnsapi.net/documentation/spec/ and example 6.2
6ยท2 Get IPv4 and IPv6 Addresses for a Domain Name
This example is similar to the previous one, except that it retrieves more information than just the addresses, so it traverses the replies_tree. In this case, it gets both the addresses and their TTLs.
Without any cache layer anywhere, since UDP is stateless, any new send must trigger resolution in some way or form.
You said:
"modified this code to use the internal IP address, not the DNS name"
You should instead install a local (on the box) recursive caching nameserver, such as unbound. All your local applications will benefit from it, and a faster DNS resolution (depending on how /etc/nsswitch.conf, /etc/resolv.conf and /etc/hosts are setup also).
For the associated bug report hinted by #Casper it seems at its core more an issue about IPv6 vs IPv4 which could be solved either by adjusting /etc/gai.conf or equivalent or doing some more clever programming around opening the connection, with the so called "happy eyeball algorithm" where you try to resolve both A and AAAA at the same time which means two parallel DNS queries (because you can not combine them into one per the protocol) and try to use the fastest one coming back, with a slight preference for AAAA if you want to be in the modern camp so you would fire the A one only some given amount of milliseconds after the AAAA to catch the case where you do not get a reply at all for AAAA or a negative one. See RFC6555 for details.

Can't pass OVERLAPPED object to WSAGetOverlappedResult

I'm trying to develop req/res server by using overlapped io according to this example.
The problem is that in the same time there could be multiple sends to the same socket and I can't pass overlapped structure to the WSAGetOverlappedResult to manage send event properly. The main loop looks like:
while (TRUE) {
index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, TRUE);
if (index == WSA_WAIT_FAILED) {
printf("Wait failed w/err %d\n", WSAGetLastError());
continue;
}
index -= WSA_WAIT_EVENT_0;
if (!WSAEnumNetworkEvents(SocketArray[index]->Socket, EventArray[index], &NetworkEvents)) { // Multiple events max exist
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
ManageAccept(index, NetworkEvents);
if (NetworkEvents.lNetworkEvents & FD_READ)
ManageRead(index, NetworkEvents);
if (NetworkEvents.lNetworkEvents & FD_WRITE)
ManageWrite(index, NetworkEvents);
}
}
Then I send messages from method ManageRead to the client socket with
WSASend(SocketArray[index]->Socket, &(over->wsabuf), 1, &SendBytes, 0, over, NULL)
And when overlapped send completed I can't really realize in the method ManageSend which of the overlapped structures was actually sent with the call WSAGetOverlappedResult:
WSAGetOverlappedResult(SocketArray[index]->Socket, over, &SendBytes, FALSE, &flags)
I have to use WorkerRoutine temporary to gain control over sending but perhaps somebody knows how to address the issue. Or may there is some different method which returns the overlapped structure which was completed?

CAPL Multiframe handling

I am writting a CAPL for Diagnostic request and response, I can get response if the data is up to 8 bytes, if data is multiframe I am not getting respone and the message on the trace is "Breaking connection between server and tester", how to handle this? I know about the CANTP frames but in this case it should handle by CAN/Canoe .
Please read CANoe ISO-TP protocol. In case of multiframe response, the tester has to send the flow control frame which provides synchronization between Sender and Receiver, which is usually 0x30. It also has fields for Block size of continous frames and seperation time. Try the below CAPL code.
variables
{
message 0x710 msg = { dlc=8,dir = rx };
byte check_byte0;
}
on message 0x718
{
check_byte0 = this.byte(0) & 0x30;
if(check_byte0 == 0x10)
{
msg.dword(0)=0x30;
msg.dword(4)=0x00;
output(msg2);
}
}
I was trying to send the request over a message ID in most gross form like 22 XX YY , which is a read DID request,this works well if the response is less than 8 bytes, if response is more than 8 bytes this wont work. so we need to use the Diagnostic objects for the request and response as defined in the CDD(or any description file) as used in the project.
If you are not using CDD, in such cases you need to use CCI (Capl call back interfaces), mostly that is necessary for simulation setups.

sending sms using pic16f877a and sim 300

Hi I have a problem in sending message in project, I am using pic16f877a and sim300. the main function runs repeatedly. Some characters are missed in the sent sms.
my program is like this...
void main()//main function
{
Serial_init(); // initialization of serial communication
Send_SMS();
}
void Serial_init()
{
TRISC=0XC0;
TXSTA=0x24;
SPBRG=129; // set baud rate 9600 Hz for 20MHz fosc
RCSTA=0x90;
TXIF=1;
}
void Send_SMS(void)
{
USART_puts("AT\0");
putch1(0x0D);
Delay_ms4M(200);
USART_puts("AT+CMGF=1\0"); // switch into text mode
putch1(0x0D);// ascii of Carriage Return
Delay_ms4M(200);
USART_puts("AT+CMGS=\"9741153218\"\0"); // send sms to the number
putch1(0x0D);
Delay_ms4M(200);
USART_puts("Hi this is working LOL\0"); // SMS text
putch1(0x0A); // new line
Delay_ms4M(200);
putch1(0x0D);
Delay_ms4M(100);
putch1(0x1A); // ascii of 'substitute' i.e end of file
}
void USART_puts(const unsigned char *string)
{
while(*string)
putch1(*string++);
}
void putch1(unsigned char data)
{
while(TXIF==0);
TXREG=data;
}
Please help
additional details: all other programs run properly, but if I call send_sms function, "main" runs repeatedly and several messages are sent with missed characters.
IMHO :
Your chip is resetting. This is the highest probable cause.
Either it is faulty or you have set Watchdog Timer to on somewhere.
For missing characters :
a) Chip resets in the midst of a data transfer.
b) Roule of thumb for usart:
Stop stuffing bytes to usart. Send each byte with a small leading delay like 10-20 microseconds.
The communication is asynchronous, which means the receiver has to synchronize at the beginning of each communication unit which is a byte. To do that receiver brutely uses resources to detect start bit, the length (in time) of it etc. So if you try to send a byte train, you will stall the receiver.
Have you tried the code with another 16F877a ? (to check chip failure)...

Sockets - sending more data after reciving answer from server

I have a client/server application.
The client sends a question to the server and receives an answer.
This works great - but when I'm trying to use the same socket again to send another question (without closing the socket - after receiving an answer) the server doesn't get the second question.
Here's the code for sending and receiving answer (this should work in a loop of some-sort):
char* buf = "GET /count.htm HTTP/1.1\r\nHost: 127.0.0.1:666\r\nAccept: text/html,application/xhtml+xml\r\nAccept-Language: en-us\r\nAccept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/5.0\r\n\r\n";
int nBytesToSend= strlen(buf);
int iPos=0;
while(nBytesToSend)
{
int nSent=send(hClientSocket,buf,nBytesToSend,0);
assert(nSent!=SOCKET_ERROR);
nBytesToSend-=nSent;
iPos+=nSent;
}
//prepare buffer for incoming data
char serverBuff[256];
int nLeft=sizeof(serverBuff);
iPos=0;
do //loop till there are no more data
{
int nNumBytes=recv(hClientSocket,serverBuff+iPos,nLeft,0);
//check if cleint closed connection
if(!nNumBytes)
break;
assert(nNumBytes!=SOCKET_ERROR);
//update free space and pointer to next byte
nLeft-=nNumBytes;
iPos+=nNumBytes;
}while(1);
With this code it is impossible that you can ever send the second question, as you can never get out off the loop that reads the reply (except when you get a segmentation violation because your offset overflows the buffer, or when the peer closes the connection, in which case you can't send and he can't receive either).
And just asserting the absence of an error is never adequate. If you get an error you need to see what was and react accordingly. At the least you need to print it.

Resources