How to send Protocol Buffer object using Winsock2? - sockets

I am creating a client server app using a simple socket to transfer Protocol Buffer objects between C++ and Java. I have it created on the Java side both as the client and receiver. I even got the Java to send to C++ but I am having trouble with sending from C++ to Java. Not sure how to write it. First I am sending the size and then reading the proto object.
I am using Visual Studio C++ 2008. DataGram and Bookmartlet are my proto objects.
Here is my C++ Sender Client
int loopt = 99;
do {
DataGram dataGram;
dataGram.set_state("ACK");
time ( &rawtime );
dataGram.set_status(ctime(&rawtime));
Bookmarklet* bookmarklet = dataGram.mutable_bookmarklet();
bookmarklet->set_name("TEST");
bookmarklet->set_utl("TEST");
dataGram.SerializeToArray(recvbuf,recvbuflen);
dataGram.ByteSize();
//Trouble SPOT
send(ConnectSocket,size,1,0);
send(ConnectSocket,recvbuf,recvbuflen,0);
} while (loopt > 0);
This is what I am trying to replicate from Java.
OutputStream output = socket.getOutputStream();
try {
int testtimes = 99;
while (socket.isConnected() && testtimes > 0) {
Thread.sleep(1000); // do nothing for 1000 miliseconds (1
// second)
DataGram dataGram = null;
Bookmarklet bookmarklet = Bookmarklet.newBuilder()
.setName("TEST").setUtl("TEST").build();
if (testtimes % 2 == 0) {
dataGram = DataGram.newBuilder().setState("ACK")
.setBookmarklet(bookmarklet)
.setStatus(new Date().toGMTString()).build();
} else {
dataGram = DataGram.newBuilder().setState("ACK")
.setStatus(new Date().toGMTString()).build();
}
output.write(dataGram.getSerializedSize());
output.write(dataGram.toByteArray());
testtimes--;
}
} catch (Exception e) {
e.printStackTrace();
}
Any help would be great. Thanks.
Client in Java for Reference:
InputStream input = socket.getInputStream();
int count = input.read();
int counter = 0;
while (count > 0) {
byte[] buffer = new byte[count];
count = input.read(buffer);
DataGram dataGram = DataGram.parseFrom(buffer);
Bookmarklet bookmarklet = null;
if ((bookmarklet = dataGram.getBookmarklet()) != null) {
System.out.println(bookmarklet.toString());
}
System.out.println(dataGram.getState() + " "
+ dataGram.getStatus());
count = input.read();
System.out.println(++counter);
}

Related

Under what circumstances, if any, can ReadFile hang after WSAEventSelect said it was ready?

This is rather ugly. We're getting weird hangups caused (read: triggered) by some security scanning software. I suspect it has a nonstandard TCP/IP stack, and the customer is asking why hangups.
Static analysis suggests only two possible locations for the hangup. The hangup either has to be in ReadFile() or WriteFile() on a socket; and WriteFile() cannot hang here unless the scanner is designed to make WriteFile() hang by setting the window size to zero. If WriteFile() were to return at all even if it didn't make progress I'd be able to knock the thing out of its wedged state. I also don't think the log state is consistent with WriteFile() returning.
So onto ReadFile(): this is the calling sequence:
SOCKET conn;
HANDLE unwedgeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE listenEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (listenEvent == NULL) return;
//...
conn = accept(lstn);
for (;;) {
HANDLE wakeup[2];
wakeup[0] = unwedgeEvent;
wakeup[1] = listenEvent;
if (WSAEventSelect(conn, socket, FD_READ | FD_CLOSE) == 0) {
// Log error
break;
}
which = WaitForMultipleObjects(2, wakeup, FALSE, INFINITE);
if (which < 0) {
// Log error
break;
}
if (which == 1) {
DWORD read;
r = ReadFile(conn, chunk, 4096, &read, NULL);
if (r == 0) {
// Handle error -- not stuck here
} else {
// Handle data -- not stuck here either
}
}
if (which == 0) break;
}
Where signalling unwedgeEvent doesn't manage to accomplish anything and the thread remains stuck forever.
So the real question is have I gone nuts or is this really a thing that can happen?
So this has gone somewhat off the deep end; I don't need non-blocking sockets at all. I need a select() that takes handle arguments to things that are sockets and things that are not sockets.
The following API sequences do not hang in ReadFile:
---------------------------------------------------------------
Sender B Receiver
WSAEventSelect
* WaitForMultipeObjects
send(buffer size = 1)
ReadFile(size = 1)
WSAEventSelect
* WaitForMultipeObjects
send(buffer size = 1)
ReadFile(size = 1)
................................................................
WSAEventSelect
* WaitForMultipeObjects
send(buffer size = 2)
ReadFile(size = 1)
WaitForMultipeObjects
ReadFile(size = 1)
................................................................
WSAEventSelect
* WaitForMultipeObjects
send(buffer size = 1)
send(buffer size = 1)
ReadFile(size = 1)
WaitForMultipeObjects
ReadFile(size = 1)
................................................................
WSAEventSelect
send(buffer size = 1)
WaitForMultipeObjects
send(buffer size = 1)
ReadFile(size = 1)
WaitForMultipeObjects
ReadFile(size = 1)
................................................................
WSAEventSelect
send(buffer size = 1)
WaitForMultipeObjects
send(buffer size = 1)
ReadFile(size = 2)
* WaitForMultipeObjects
send(buffer size = 1)
ReadFile(size = 1)
................................................................
WSAEventSelect
send(buffer size = 1)
WaitForMultipeObjects
ReadFile(size = 1)
send(buffer size = 1)
WaitForMultipeObjects
ReadFile(size = 1)
I see a number of issues with your code:
You should use WSACreateEvent() and WSAWaitForMultipleEvents() instead of CreateEvent() and WaitForMultipleObjects(). Although the current implementation is that the former APIs simply map to the latter APIs, Microsoft is free to change that implementation at any time without breaking code that uses the former APIs properly.
In your call to WSAEventSelect(), socket should be listenEvent instead.
WSAEventSelect() returns SOCKET_ERROR (-1) on failure, not 0 like you have coded.
You are not calling WSAEnumNetworkEvents() at all, which you need to do in order to determine if FD_READ was the actual type of event triggered, and to clear the socket's event state and reset the event object. So, you may be acting on a stale read state, which could explain why you end up calling ReadFile() when there is actually nothing available to read.
WSAEventSelect() puts the socket into non-blocking mode (per its documentation), so it is actually not possible for ReadFile() (or any other reading function) to block on the socket. However, it could fail immediately with a WSAEWOULDBLOCK error, so make sure you are not treating that condition as a fatal error.
The WSAEventSelect() documentation does not list ReadFile() as a supported function for re-enabling events when calling WSAEnumNetworkEvents(). Although the Socket Handles documentation does say that a Winsock SOCKET can be used with non-Winsock I/O functions like ReadFile(), it recommends that a SOCKET should only be used with Winsock functions. So, you should use send()/recv() or WSASend()/WSARecv() instead of WriteFile()/ReadFile().
With that said, try something more like the following:
HANDLE unwedgeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (unwedgeEvent == NULL) {
// Log error
return;
}
...
SOCKET conn = accept(lstn, NULL, NULL);
if (conn == INVALID_SOCKET) {
// Log error
return;
}
...
WSAEVENT listenEvent = WSACreateEvent();
if (listenEvent == NULL) {
// Log error
}
else if (WSAEventSelect(conn, listenEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR) {
// Log error
}
else {
WSAEVENT wakeup[2];
wakeup[0] = (WSAEVENT) unwedgeEvent;
wakeup[1] = listenEvent;
char chunk[4096];
int read;
do {
DWORD which = WSAWaitForMultipleEvents(2, wakeup, FALSE, WSA_INFINITE, FALSE);
if (which == WSA_WAIT_FAILED) {
// Log error
break;
}
if (which == WSA_WAIT_EVENT_0) {
break;
}
if (which == (WSA_WAIT_EVENT_0+1)) {
WSANETWORKEVENTS events = {};
if (WSAEnumNetworkEvents(conn, listenEvent, &events) == SOCKET_ERROR) {
// Log error
break;
}
if (events.lNetworkEvents & FD_READ) {
read = recv(conn, chunk, sizeof(chunk), 0);
if (read == SOCKET_ERROR) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
// Log error
break;
}
}
else if (read == 0) {
break;
}
else {
// Handle chunk up to read number of bytes
}
}
if (events.lNetworkEvents & FD_CLOSE) {
break;
}
}
}
while (true);
WSACloseEvent(listenEvent);
}
closesocket(conn);

Plc4x library Modbus serial (RTU) get is not retrieving data

I am trying to write a sample program to retrieve temperature data from SHT20 temperature sensor using serial port with apache plc4x library.
private void plcRtuReader() {
String connectionString =
"modbus:serial://COM5?unit-identifier=1&baudRate=19200&stopBits=" + SerialPort.ONE_STOP_BIT + "&parityBits=" + SerialPort.NO_PARITY + "&dataBits=8";
try (PlcConnection plcConnection = new PlcDriverManager().getConnection(connectionString)) {
if (!plcConnection.getMetadata().canRead()) {
System.out.println("This connection doesn't support reading.");
return;
}
PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
builder.addItem("value-1", "holding-register:258[2]");
PlcReadRequest readRequest = builder.build();
PlcReadResponse response = readRequest.execute().get();
for (String fieldName : response.getFieldNames()) {
if (response.getResponseCode(fieldName) == PlcResponseCode.OK) {
int numValues = response.getNumberOfValues(fieldName);
// If it's just one element, output just one single line.
if (numValues == 1) {
System.out.println("Value[" + fieldName + "]: " + response.getObject(fieldName));
}
// If it's more than one element, output each in a single row.
else {
System.out.println("Value[" + fieldName + "]:");
for (int i = 0; i < numValues; i++) {
System.out.println(" - " + response.getObject(fieldName, i));
}
}
}
// Something went wrong, to output an error message instead.
else {
System.out.println(
"Error[" + fieldName + "]: " + response.getResponseCode(fieldName).name());
}
}
System.exit(0);
} catch (PlcConnectionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
Connection is established with the device using serial communication. But it fails to get data and instead prints the below warning messages continously.
debugger hangs at below line:
PlcReadResponse response = readRequest.execute().get();
with below logs printing continuously.
2021-06-03-17:41:48.425 [nioEventLoopGroup-2-1] WARN io.netty.channel.nio.NioEventLoop - Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector#131f8986.
2021-06-03-17:41:55.080 [nioEventLoopGroup-2-1] WARN io.netty.channel.nio.NioEventLoop - Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector#48c328c5.
With same URL data (i.e baudrate,stopBits etc..) using modpoll.exe it works and returns the data over RTU. I am not sure what is missing here.
Kindly shed some light here.

Server sends Welcome message more than once using select()

I'm currently having an issue with pop3 server which is based on select() function. Basically server holds multiple clients at once, but Welcome message sends as many times as is the number of connected client.
This is an example of messages sent to clients.
//file descriptor, array of clients
fd_set readset;
int sock_arr[30];
int max_fd, rc;
servsock = socket(AF_INET, SOCK_STREAM, 0);
/*...*/
max_fd = servsock;
do
{
FD_ZERO(&readset);
FD_SET(servsock, &readset);
for (int i = 0; i < 30; i++) {
rc = sock_arr[i];
if (rc > 0)
FD_SET(rc, &readset);
if (rc > max_fd)
max_fd = rc;
}
activity = select(max_fd + 1, &readset, NULL, NULL, &timeout);
if (activity < 0)
{
perror(" select() failed");
break;
}
if (activity == 0)
{
printf(" select() timed out. End program.\n");
break;
}
Message is sent as many times as is the number of connected client e.g.
if first client is connected the message is sent once
if second client is connected the message is sent twice etc.
//here server accepts new connections
if (FD_ISSET(servsock, &readset)) {
serv_socket_len = sizeof(addr);
peersoc = accept(servsock,(struct sockaddr *) &addr, &serv_socket_len);
if (peersoc < 0) {
error("Accept failed!\n", ERR_SCK);
}
else {
char message[256];
strcat(message, reply_code[1]);
strcat(message, reply_code[3]);
strcat(message, reply_code[0]);
//Welcome message
send(peersoc, message, strlen(message), 0);
for (int i = 0; i < 30; i++) {
if (sock_arr[i] == 0) {
sock_arr[i] = peersoc;
break;
}
}
}
}
//server processing input messages from clients using threads
/*...*/
I have no idea what causes I assume something with file descriptors. Please give me some advice if possible.
Solved I have forgotten to clear buffer for sending message
...
char message[256];
memset(message, 0, sizeof(message));
...

TCP Socket receiving only a part of the message

I am using the following code to perform a tcp socket connection and send a string to an IP. But sometimes in the response, I not receiving the entire file
Socket m_socClient;
IPSelected ="1.1.2.3"
Port = "80"
string query ="My Query"
m_socClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPAddress remoteIPAddress = System.Net.IPAddress.Parse(IPSelected);
System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(remoteIPAddress, Port);
m_socClient.Connect(remoteEndPoint);
try
{
if (m_socClient.Connected)
{
var reQuestToSend = "";
reQuestToSend = string.Format("POST /TMHP/Request HTTP/1.1\r\nHost:{0}\r\nContent-Length:{1}\r\n\r\n{2}", "edi-webtest.tmhp.com", Query270.Length, Query270);
byte[] bytesToSend = Encoding.ASCII.GetBytes(reQuestToSend);
byteCount = m_socClient.Send(bytesToSend, SocketFlags.None);
byte[] bytesReceived = new byte[3000];
byteCount = m_socClient.Receive(bytesReceived, SocketFlags.None);
Response271 = Encoding.ASCII.GetString(bytesReceived);
}
}
catch (Exception ex)
{
EVCommon.Log(ex.Message);
}
finally
{
m_socClient.Disconnect(false);
m_socClient.Close(5000);
}
I think the problem is with byte[] bytesReceived = new byte[3000];
Is there a way to not hardcode this number 3000. It works most of the time but for longer strings it gets only half of it.
I want it be handling variable sized messages instead of setting the byte size to 30000
Thank you
Read RFC 2616 Section 4.4. It tells you how to determine the end of the server's response so you know how many bytes to read. You have to read and process the server's response headers first in order to know how the remaining data, if any, is being transmitted. Then you can keep reading from the socket accordingly, potentially parsing what you have read, until the end of the response has actually been reached. Your current reading code is not even close to satisfying that requirement.
For example (pseudo code):
line = read a CRLF-delimited line;
responseNum = extract from line;
httpVer = extract from line;
do
{
line = read a CRLF-delimited line;
if (line == "") break;
add line to headers list;
}
while (true);
if (((responseNum / 100) != 1) &&
(responseNum != 204) &&
(responseNum != 304) &&
(request was not "HEAD"))
{
if ((headers has "Transfer-Encoding") &&
(headers["Transfer-Encoding"] != "identity"))
{
do
{
line = read a CRLF-delimited line;
chunkLen = extract from line, decode hex value;
if (chunkLen == 0) break;
read exactly chunkLen number of bytes;
read and discard a CRLF-delimited line;
}
while (true);
do
{
line = read a CRLF-delimited line;
if (line == "") break;
add line to headers list, overwrite if exists;
}
while (true);
decode/transform read data based on headers["Transfer-Encoding"] values if more than just "chunked"
}
else if (headers has "Content-Length")
{
read exactly headers["Content-Length"] number of bytes
}
else if (headers["Content-Type"] == multipart/byteranges)
{
boundary = headers["Content-Type"]["boundary"];
read and parse MIME encoded data until "--"+boundary+"--" line is reached;
}
else
{
read until disconnected;
}
}
if (((httpVer >= 1.1) && (headers["Connection"] == "close)) ||
((httpVer < 1.1) && (headers["Connection"] != "keep-alive")))
{
disconnect;
}
I leave it as an exercise for you to actually implement this in your code.

Unable to send a big list over TCP Sockets - Blackberry

I'm trying to send a list of 600 records over TCP/IP sockets using a java server and a Blackberry client. But every time it reaches the 63th record it stops, the odd thing about this is that if I only send 200 records they are sent ok.
I haven't been able to understand why it happens, only that 63 records equals aprox to 4kB, basically it sends:
an integer with the total number of records to be sent
And for every record
an integer with the length of the string
the string
a string terminator "$$$"
Since i need to send the whole 600 i have tried to close the InputStreamReader and reopen it, also reset it but without any result.
Does anybody else have experienced this behaviour? thanks in advanced.
EDIT
Here the code that receives:
private String readfromserver() throws IOException {
int len=_in.read(); // receives the string length
if (len==0) // if len=0 then the string was empty
return "";
else {
char[] input = new char[len+1];
for (int i = 0; i < len; ++i)
input[i] = (char)_in.read();
StringBuffer s = new StringBuffer();
s.append(input);
return s.toString();
}
}
private void startRec(String data) throws IOException
{
boolean mustcontinue=true;
int len=_in.read(); // read how many records is about to receive
if (len==0) {
scr.writelog("There is no data to receive");
}
else {
for(int i=0; i<len; i++)
if (mustcontinue) {
mustcontinue=mustcontinue && showdata(readfromserver());
}
else {
scr.writelog("Inconsistency error #19");
}
}
}
the function showdata only shows the received string in a LabelField.
The code in the server:
try {
_out.write(smultiple.size()); // send the number of records
_out.flush();
for (int x=0; x<smultiple.size(); x++)
{
int l=smultiple.elementAt(x).length();
_out.write(l); // send string length
if (l>0)
_out.write(smultiple.elementAt(x)); // send string
}
_out.flush();
} catch (Exception e) {
principal.dblog(e.toString());
}
smultiple is a vector containing the strings and everyone already have the terminator $$$.
Thanks.
I think 200 goes fine and 600 -not, because the latter number is bigger than 255 :-) Your code
int len=_in.read();
probably reads a byte and not an integer (4 bytes)