I'm currently working on creating tests for specific use cases one of which is Init WF200 -> connect to AP -> send TCP data -> Deinit WF200. The application is very energy critical so I have to ensure that the WF200 is enabled as short as possible.
The hardware I use is a EFM32GG11 MCU together with a WF200 WIFI transceiver, both from SiliconLabs. I'm using an RTOS and the lwip stack with the netconn API for TCP communication.
The problem is that I can't find a way to know if the TCP transaction was completed, which I need to know before putting the WF200 into shutdown. Currently the task is faster then the actual transmission which leads to data loss and incomplete TCP communication.
Currently I have a working work around which is adding a delay. But that doesn't seem like an elegant solution to me, especially because the delay is dependent on the amount of data being sent.
I have already tried checking the tcp pcb state but with no success. Is there some way I can block the thread until the transaction is completed?
Thanks in advance!
static void tcp_thread(void *p_arg) {
struct netconn *conn;
err_t err;
LWIP_UNUSED_ARG(p_arg);
// needed, otherwise netconn_connect fails
KAL_Dly(1);
conn = netconn_new(NETCONN_TCP);
if (conn != NULL) {
struct ip4_addr broker_ip;
IP_ADDR4(&broker_ip, SERVER_IP_0, SERVER_IP_1, SERVER_IP_2, SERVER_IP_3);
err = netconn_connect(conn, &broker_ip, 65432);
if (err == ERR_OK) {
// NOCOPY only safe when data is static and const
err = netconn_write(conn, test_data, strlen(test_data), NETCONN_NOCOPY);
printf("Data sent\n");
netconn_close(conn);
netconn_delete(conn);
} else {
printf("No TCP connection\n");
}
} else {
printf("No netconn\n");
}
KAL_Dly(200);
sl_wfx_deinit();
OSTaskDel(0, &err);
}
netconn will execute a call back, you can add while(1){osDelay(2);} to your code and wait for that callback to finish. Maybe post a flag in the callback you can check for. For example you can use that data RX callback (or error callback, etc), inspect for an ack, then write to a var you can check in your code's while loop.
Related
I'm trying to trigger an interrupt function each time I receive a broadcast message on a given port of an STM32 board (Nucleo f429zi). The communication protocol I use is UDP and the mbed library is UDPSocket which inherits from Socket.
Does anyone have an idea how to achieve it?
Edit:
Thanks to PeterJ's comment I found an interesting (but deprecated) member function of the class Socket which is called attach(). This method registers a callback on state change of the socket (recv/send/accept).
Since I have an incoming broadcast on the socket, there is no state change in my case (only receiving data, never sending). Is there a way I could use this attach() method to detect every message received?
// Open Ethernet connection
EthernetInterface eth;
eth.connect();
// Create an UDP socket for listening to the broadcast
UDPSocket broadcastSocket;
broadcastSocket.open(ð);
broadcastSocket.bind(BROADCAST_PORT);
// Function to call when a broadcast message is received
broadcastSocket.attach(&onUDPSocketEvent);
void onUDPSocketEvent(){
printf("UDP event detected\n");
}
attach has been replaced by sigio, but I don't think it's going to do what you want. A nice way would be to spin up a new thread, and use this thread to handle the socket.
void onUDPSocketEvent(void* buffer, size_t size) {
printf("UDP event detected\n");
}
void udp_main() {
// Open Ethernet connection
EthernetInterface eth;
eth.connect();
// Create an UDP socket for listening to the broadcast
UDPSocket broadcastSocket;
broadcastSocket.open(ð);
broadcastSocket.bind(BROADCAST_PORT);
void* recvBuffer = malloc(1024);
while (1) {
// this blocks until next packet comes in
nsapi_size_or_error_t size = broadcastSocket.recvfrom(NULL, recvBuffer, 1024);
if (size < 0) {
printf("recvfrom failed with error code %d\n", size);
}
onUDPSocketEvent(recvBuffer, size);
}
}
int main() {
Thread t; // can pass in the stack size here if you run out of memory
t.start(&udp_main);
while (1) {
wait(osWaitForever);
}
}
(note that the callback function does not run in an ISR - so not in an interrupt context - but I assume you don't actually want that).
Edit: I have created mbed-udp-ping-pong which shows how to listen for UDP messages on a separate thread.
I'm writing code that sends an UDP packet using CoreFoundation. Here is the code
CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0u, NULL, NULL);
// ... (handle error if socket is NULL)
struct sockaddr_in sockaddr;
// ... (set fields of sockaddr)
NSData *addressData = [NSData dataWithBytes: &sockaddr length: sockaddr.sin_len];
if (CFSocketSendData(self.socket, (__bridge CFDataRef) addressData, (__bridge CFDataRef) data, 0) != kCFSocketSuccess) {
// ... (handle error)
}
However, I am not sure, how to complete this flow, i.e. I have the following questions:
Should I close / release the socket somehow if I am not going to send more data? If so, is CFSocketInvalidate the appropriate function?
The documentation to CFSocketSendData says: "If this function returns kCFSocketSuccess, then by the time it returns, the data has been queued in the socket buffer for delivery." Can I invalidate the socket right after calling CFSocketSendData or should I wait until the data are send?
If there is a need to wait, how can I find out that the data are already sent? Can I find out if there were any errors? (Of course, I have no guarantee that receiver gets the data with UDP. However, can I detect some errors which occur on my side during sending?)
Thanks.
Should I close / release the socket somehow if I am not going to send more data? If so, is CFSocketInvalidate the appropriate function?
Yes. Call CFSocketInvalidate followed by CFRelease.
Can I invalidate the socket right after calling CFSocketSendData or should I wait until the data are send?
In the source code, CFSocketSendData calls sendto with the SO_SNDTIMEO option set.
There's no need to wait. If CFSocketSendData returns kCFSocketSuccess, you're done.
Note that this situation can be more complicated for a TCP connection.
However, can I detect some errors which occur on my side during sending?
You can. Using errno. The possible errors for sendto are listed here.
Before you decide its a tl:dr (too long, didnt read) post try to read at least some, since Its a question broken down in a lot of small pieces. Some of which you can probably answer and help me.
Please try to help me as much as you can. These types of problems are very common on the internet and I think you will help me and much more people after me.
I am currently researching HTTP services and the protocol itself so that I can discover if it is useful to me.
I have some basic questions as well as some code that needs to be discussed.
First I would like to know how does the communication start? I have discovered that the client sends a message in which it requests a resource (is this correct?). Then what happens? I (as a server) have to reply with what?
Do I need to append a carriage return and a line feed after every response? Somewhere it says there even need to be two (\r\n\r\n).
How can an asynchronous writing be established? (I hope this question is understandable) My primary goal is to achieve a connection between a client and a server and then a continuous data stream from server to the client. Does the client need to reply for every message it gets?
I hope I made my questions clear, since I'm not an expert in these things (yet, I am very interested in it).
And for the programming part of my problem.
I have managed to put together a simple program in Qt in C++ (server side) and a simple client in Objective C (iOS). The client connects and I can read the request header. It is like this:
Data available, incoming: "GET / HTTP/1.1
Host: localhost:9990
Connection: close
User-Agent: CFStream%20test/1.0 CFNetwork/609 Darwin/12.2.0
Should I reply to this header manually? And if so, what?
The client side code looks like this (i know its not pseudo but i think its pretty self-explanatory):
- (void)setupStream
{
NSURL *url = [NSURL URLWithString:#"http://localhost:9990"];
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)#"GET", (CFURLRef)url, kCFHTTPVersion1_1);
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
CFRelease(message);
if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
{
NSLog(#"Some error.");
}
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
if (!CFReadStreamOpen(stream))
{
CFRelease(stream);
NSLog(#"Error opening stream.");
}
CFStreamClientContext context = {0, self, NULL, NULL, NULL};
CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred, readStreamCallback, &context);
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
NSLog(#"Done");
}
This is the setup stream method. The stream variable is a class variable of type CFReadStreamRef.
The callback looks like this:
static void readStreamCallback(CFReadStreamRef aStream, CFStreamEventType event, void *client)
{
ViewController *controller = (ViewController*)client;
[controller handleEvent:event forStream:aStream];
}
And the handle event like this:
- (void)handleEvent:(CFStreamEventType)event forStream:(CFReadStreamRef)aStream
{
if (aStream != stream)
{
return;
}
NSLog(#"Handle event callback");
switch (event)
{
case kCFStreamEventHasBytesAvailable:
NSLog(#"Work log");
UInt8 bytes[11];
CFIndex length;
length = CFReadStreamRead(stream, bytes, 11); //I know 11 bytes is hard coded, its in testing stage now. Feel free to suggest me how to do it better.
if (length == -1)
{
NSLog(#"Error, data length = -1");
return;
}
NSLog(#"Len: %li, data: %s", length, bytes);
break;
default:
NSLog(#"Other event");
break;
}
}
And thats practically all the client code that is worth mentioning. The Qt Server part (I will only post the important parts) is done like this: (this is a subclassed QTcpServer class). First the startServer(); is called:
bool Server::startServer()
{
if (!this->listen(QHostAddress::Any, 9990))
return false;
return true;
}
When there is a connection incoming the incomingConnection is fired off with the socket descriptor as a parameter:
void Server::incomingConnection(int handle)
{
qDebug("New client connected");
ServerClient *client = new ServerClient(handle, this); //The constructor takes in the socket descriptor needed to set up the socket and the parent (this)
client->setVectorLocation(clients.count()); //This is a int from a Qvector in which i append the clients, its not important for understanding right now.
connect(client, SIGNAL(clientDisconnected(int)), this, SLOT(clientDisconnected(int)), Qt::QueuedConnection); //When the client socket emits a disconnected signal the ServerClient class emits a client disconnected signal which the server uses to delete that client from the vector (thats why I use "setVectorLocation(int)") - not important right now
clients.push_back(client); //And then I append the client to the QVector - not important right now
}
The ClientServer class constructor just creates a new socket and connects the required methods:
ServerClient::ServerClient(int handle, QObject *parent) :
QObject(parent)
{
socket = new QTcpSocket(this); //Socket is a class variable
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
socket->setSocketDescriptor(handle);
}
Ready read just writes me the data incoming (it wont be much user later i think):
void ServerClient::readyRead()
{
qDebug() << "Data available, incoming: " << socket->readAll();
}
And finally the write data:
void ServerClient::writeData(QByteArray *data)
{
data->append("\r\n\r\n"); //I have read this must be appended to all outgoing data from a HTTP server
socket->write(*data);
socket->flush();
qDebug() << "Written data to client: " << *data;
}
This code however does not always work. Sometimes when I write message like "Message" the client recieves all the data and some things that shouldnt be there (the new line and a wierd symbol - can NSLog cause this?). Sometimes when I send "Hellow" the client only gets "Hel" and some other funky stuff.
What are the problems? What should I pay more attention about? Anything that will help me will be MUCH appreciated. And please dont paste in some links that contain a book with a few hundred pages, Im sure this can be solved just by explaining things to me.
THANKS A LOT!
Jan.
You asked many questions ... and that's a perfectly legitimate thing to do :)
I confess - it was too long, I didn't read :(
BUT ...
1) Yes, the HTTP protocol does expect na "CRLF" ("\r\n"). Many servers and many clients are "forgiving", but strictly speaking - yes, you need them.
REFERENCE: RFC 2616
2) Wanting to understand HTTP "internals" is also perfectly legitimate - I applaud you.
One good way is to read the RFC(s).
Another is to use a "telnet" client: http://blog.tonycode.com/tech-stuff/http-notes/making-http-requests-via-telnet
Yet another is to study requests and responses in FF Firebug
3) Socket programming is another issue - which explains why sometimes you might read "hello world", and other times you might just get "hel".
Strong recommendation: Beej's Guide to Network Programming
4) Finally, no way would I actually write a server in Qt with C++ (except maybe as a toy "science experiment", or for some really off-the-wall requirement)
I would definitely write server code in C# (for Windows servers), Java (for everything else) or a scripting language I felt comfortable with (Perl, Ruby/RoR, Python and Lua all come to mind).
IMHO .. and hope that helps!
Your questions pretty much amount to "how does HTTP work", and the full answer lies in the specification.
we have more than dozon of wcf services and being called using TCP binding. There are a lots of calls to same wcf service at various places in code.
AdminServiceClient client = FactoryS.AdminServiceClient();// it takes significant time. and
client.GetSomeThing(param1);
client.Close();
i want to cache the client or produce it from singleton. so that i can save some time, Is it possible?
Thx
Yes, this is possible. You can make the proxy object visible to the entire application, or wrap it in a singleton class for neatness (my preferred option). However, if you are going to reuse a proxy for a service, you will have to handle channel faults.
First create your singleton class / cache / global variable that holds an instance of the proxy (or proxies) that you want to reuse.
When you create the proxy, you need to subscribe to the Faulted event on the inner channel
proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyFaulted);
and then put some reconnect code inside the ProxyFaulted event handler. The Faulted event will fire if the service drops, or the connection times out because it was idle. The faulted event will only fire if you have reliableSession enabled on your binding in the config file (if unspecified this defaults to enabled on the netTcpBinding).
Edit: If you don't want to keep your proxy channel open all the time, you will have to test the state of the channel before every time you use it, and recreate the proxy if it is faulted. Once the channel has faulted there is no option but to create a new one.
Edit2: The only real difference in load between keeping the channel open and closing it every time is a keep-alive packet being sent to the service and acknowledged every so often (which is what is behind your channel fault event). With 100 users I don't think this will be a problem.
The other option is to put your proxy creation inside a using block where it will be closed / disposed at the end of the block (which is considered bad practice). Closing the channel after a call may result in your application hanging because the service is not yet finished processing. In fact, even if your call to the service was async or the service contract for the method was one-way, the channel close code will block until the service is finished.
Here is a simple singleton class that should have the bare bones of what you need:
public static class SingletonProxy
{
private CupidClientServiceClient proxyInstance = null;
public CupidClientServiceClient ProxyInstance
{
get
{
if (proxyInstance == null)
{
AttemptToConnect();
}
return this.proxyInstance;
}
}
private void ProxyChannelFaulted(object sender, EventArgs e)
{
bool connected = false;
while (!connected)
{
// you may want to put timer code around this, or
// other code to limit the number of retrys if
// the connection keeps failing
AttemptToConnect();
}
}
public bool AttemptToConnect()
{
// this whole process needs to be thread safe
lock (proxyInstance)
{
try
{
if (proxyInstance != null)
{
// deregister the event handler from the old instance
proxyInstance.InnerChannel.Faulted -= new EventHandler(ProxyChannelFaulted);
}
//(re)create the instance
proxyInstance = new CupidClientServiceClient();
// always open the connection
proxyInstance.Open();
// add the event handler for the new instance
// the client faulted is needed to be inserted here (after the open)
// because we don't want the service instance to keep faulting (throwing faulted event)
// as soon as the open function call.
proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyChannelFaulted);
return true;
}
catch (EndpointNotFoundException)
{
// do something here (log, show user message etc.)
return false;
}
catch (TimeoutException)
{
// do something here (log, show user message etc.)
return false;
}
}
}
}
I hope that helps :)
In my experience, creating/closing the channel on a per call basis adds very little overhead. Take a look at this Stackoverflow question. It's not a Singleton question per se, but related to your issue. Typically you don't want to leave the channel open once you're finished with it.
I would encourage you to use a reusable ChannelFactory implementation if you're not already and see if you still are having performance problems.
I am finding the doc for CFStreamCreatePairWithSocketToCFHost confusing:
Specifically, its not clear to me how the function can set the readStream pointer to null on error.
as far as I understand, the pointer is passed by value - so the function can only change the objected pointed to by the pointer.
Right now I can't figure out how to detect connection errors.
Relevant doc snippet:
Creates readable and writable streams connected to a given CFHost object.
void CFStreamCreatePairWithSocketToCFHost (
CFAllocatorRef alloc,
CFHostRef host,
SInt32 port,
CFReadStreamRef *readStream,
CFWriteStreamRef *writeStream
);
readStream
Upon return, contains a CFReadStream object connected to the host host on port port, or NULL if there is a failure during creation. If you pass NULL, the function will not create a readable stream. Ownership follows the Create Rule.
This is my connecting code, it goes all the way to NSLog(#"Connected") even when the server is down.
NSLog(#"Attempting to (re)connect to %#:%d", m_host, m_port);
while(TRUE)
{
CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)m_host);
if (!host)
{
NSLog(#"Error resolving host %#", m_host);
[NSThread sleepForTimeInterval:5.0];
continue;
}
CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host , m_port, &m_in, &m_out);
CFRelease(host);
if (!m_in)
{
NSLog(#"Error");
}
CFStreamClientContext context = {0, self,nil,nil,nil};
if (CFReadStreamSetClient(m_in, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkReadEvent, &context))
{
CFReadStreamScheduleWithRunLoop(m_in, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
if (CFWriteStreamSetClient(m_out, kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkWriteEvent, &context))
{
CFWriteStreamScheduleWithRunLoop(m_out, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
BOOL success = CFReadStreamOpen(m_in);
CFErrorRef error = CFReadStreamCopyError(m_in);
if (!success || (error && CFErrorGetCode(error) != 0))
{
NSLog(#"Connect error %s : %d", CFErrorGetDomain(error), CFErrorGetCode(error));
[NSThread sleepForTimeInterval:5.0];
}
else
{
NSLog(#"Connected");
break;
}
}
From the "CFNetwork Programming Guide":
Opening a stream can be a lengthy process, so the CFReadStreamOpen and CFWriteStreamOpen functions avoid blocking by returning TRUE to
indicate that the process of opening the stream has begun. To check
the status of the open, call the functions CFReadStreamGetStatus and
CFWriteStreamGetStatus, which returnkCFStreamStatusOpening if the open
is still in progress, kCFStreamStatusOpen if the open is complete,
orkCFStreamStatusErrorOccurred if the open has completed but failed.
In most cases, it doesn’t matter whether the open is complete because
the CFStream functions that read and write will block until the stream
is open.
Also check out the kCFStreamEventOpenCompleted,
(http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFStreamConstants/Reference/reference.html)
: a stream event that reports the successful completion of the opening
process. So to conclude, after calling CFReadStreamOpen (or Write),
which will probably succeed, register to listen to the "OpenCompleted"
event to identify a "real" success.
Surely after you call CFStreamCreatePairWithSocketToCFHost() just test readstream to see if it's NULL?
As you're passing in the memory location of the readstream pointer, the function can easily set that to whatever value it chooses (either a reference to a created object, or alternatively NULL).
Edit
I've tried your code, and I agree, it's very confusing. It appears that the CFReadStreamRef is readily created and opened, even for a nonsense host (I literally used "nonsense"). I don't believe this function will return NULL pointers for an unreachable host.
I suppose this makes sense, in as far as until one tries to open the stream, whether it will work or not is unknown.
So, the readStream param is a pointer to the CFReadStreamRef and, as such, can definitely be set to NULL by the function. &foo means "address of foo" and if you have the address you can set the value.
My reading of the documentation for CFStreamCreatePairWithSocketToCFHost is that they will be set to NULL on failure, but that failure is not about connection failure, but other kinds of failure (memory, etc). So not likely you'll get an error there.
Looks to me like the issue is that CFReadStreamOpen can return immediately with true when it can open the stream in the background and so this code is not really opening the stream or testing that it's been opened, merely queuing it for opening). From the documentation for CFReadStreamOpen:
" If the stream can open in the background without blocking, this function always returns true."
So I think you will need to follow the rest of the instructions for CFReadStreamOpen and schedule the stream on a run loop, or perhaps poll (though obviously polling in a tight loop isn't likely to work).
In the documentation for CFReadStreamOpen we see:
Opening a stream causes it to reserve all the system resources it requires. If the stream can open in the background without blocking, this function always returns true.
I suspect that the stream is opening in the background, and thus you are saying "Connected" before it actually opens. You've already scheduled the stream with a runloop, so if you let the run loop run, you'll probably get a callback with the event type set to kCFStreamEventErrorOccurred, and from there you can process the error appropriately.