NWEthernetChannel not working as expected - swift

The "Advances in Networking" talk for WWDC2019 featured a new class, introduced in Mac OS X 10.15 called NWEthernetChannel to monitor a custom (non-IP) protocol. This is for MacOS.
I am interested in monitoring Cisco Discovery Protocol (CDP) packets, however, the class is not working as expected - the receiveHandler is not receiving any data.
What I verified:
NWEthernetChannel is alive and in the ready state, monitoring the active NWInterface called eth0.
As per the documentation, the com.apple.developer.networking.custom-protocol entitlement is set.
I verified the same logic using sudo tcpdump -nn -v -i en0 -s 1500 'ether[20:2] == 0x2000'. This returned the expected result.
Please see my implementation below:
self._ethernetChannel = NWEthernetChannel(on: self._ethernetInterface!, etherType: 0x2000)
self._ethernetChannel!.stateUpdateHandler = {state in switch state {
case .ready:
NSLog("ready");
break;
case .waiting(let error as NWError):
print("Waiting:", error);
break;
case .failed(let error as NWError):
print("Failed:", error);
break;
case .cancelled:
print("cancelled");
break;
case .preparing:
print("preparing");
break;
case .setup:
print("setup");
default:
NSLog("default");
break;
}}
self._ethernetChannel!.receiveHandler = {(packetData, vlanTag, localAddress, remoteAddress) in
print("received data");
};
self._ethernetChannel!.start(queue: .main);
Can someone shed some light?

Related

How to handle connection loss uploading to Firebase iOS?

I have a frontend Swift application in which users are to upload large videos and photos to Firebase Storage. I am currently working on error handling. The documentation does a good job of explaining error handling from Google's sever side of things, however it does not cover how to deal with connection loss.
This is the error handling directly from the documentation:
...
// Upload file and metadata to the object 'images/mountains.jpg'
let uploadTask = storageRef.putFile(from: localFile, metadata: metadata)
uploadTask.observe(.failure) { snapshot in
if let error = snapshot.error as? NSError {
switch (StorageErrorCode(rawValue: error.code)!) {
case .objectNotFound:
// File doesn't exist
break
case .unauthorized:
// User doesn't have permission to access file
break
case .cancelled:
// User canceled the upload
break
/* ... */
case .unknown:
// Unknown error occurred, inspect the server response
break
default:
// A separate error occurred. This is a good place to retry the upload.
break
}
}
}
I have done some tests on my device where the upload begins with no network connection. The following gets automatically printed to the console every second or so after the network goes down:
2020-07-06 01:38:28.361559-0700 Rage[12281:1978025] Connection 9: failed to connect 1:50, reason -1
2020-07-06 01:38:28.361648-0700 Rage[12281:1978025] Connection 9: encountered error(1:50)
2020-07-06 01:38:28.366906-0700 Rage[12281:1978025] Task <320E9387-F725-4AEA-B3BE-76425F73F9F7>.<6> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2020-07-06 01:38:28.368381-0700 Rage[12281:1978042] Task <320E9387-F725-4AEA-B3BE-76425F73F9F7>.<6> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x280a581e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <320E9387-F725-4AEA-B3BE-76425F73F9F7>.<6>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <320E9387-F725-4AEA-B3BE-76425F73F9F7>.<6>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://firebasestorage.googleapis.com/v0/b/rage-5940.appspot.com/o/event%2FBEC3B24F-5F97-4B6A-8FD3-5DC2F7D37AFB.mp4?uploadType=resumable&name=event%2FBEC3B24F-5F97-4B6A-8FD3-5DC2F7D37AFB.mp4, NSErrorFailingURLKey=https://firebasestorage.googleapis.com/v0/b/rage-5940.appspot.com/o/event%2FBEC3B24F-5F97-4B6A-8FD3-5DC2F7D37AFB.mp4?uploadType=resumable&name=event%2FBEC3B24F-5F97-4B6A-8FD3-5DC2F7D37AFB.mp4, _kCFStreamErrorDomainKey=1}
Is this Firebase throwing these errors? If so they are probably being thrown trying to create a storageRef before the uploadTask could even begin, and thus escape any provided error handling.
Is there anyway to catch these network errors?
Did you try this?
if error._code == NSURLErrorNetworkConnectionLost {
}
there are a couple of more you can check with them:
NSURLErrorTimedOut
NSURLErrorNotConnectedToInternet
NSURLErrorCannotConnectToHost

Yii2 cli and pcntl_fork

I have a Yii2 script that runs forever to execute tasks on request.
Some tasks (as task2) should be performed in a seperate forked process:
switch ($command) {
case 'task1':
echo "hello";
break;
case 'task2':
if ( ($pid=pcntl_fork()) == -1 )
throw new Exception("fork failed");
if ($pid==0) {
// we are child process
// perform task here
...
exit(0);
}
break;
}
}
Doing such a fork, the database connection goes lost in the parent. There are some workarounds on the PHP level, but how to handle this on the Yii2 level?
Can we activate auto-reconnect in Yii2 by configuration?

libpcap error pcap_open_live(): BIOCSRTIMEOUT: Invalid argument

With the following code, I get this error when I run the executable file:
...
dev = pcap_lookupdev(errbuf);
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
printf("DEV: %s\n",dev);
descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
if(descr == NULL)
{
printf("pcap_open_live(): %s\n",errbuf);
exit(1);
}
packet = pcap_next(descr,&hdr);
if(packet == NULL)
{
printf("Didn't grab packet\n");
exit(1);
}
...
And the error:
pcap_open_live(): gbeth0: BIOCSRTIMEOUT: Invalid argument
When I change
descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
to
descr = pcap_open_live(dev,BUFSIZ,0,1,errbuf);
sniffer does not grab anything and the program exit with this error: Didn't grab packet
and when I change 1 to 0 it does not grab anything but with errors.
What should I do?
-1 is NOT a valid timeout argument to pcap_open_live() on any platform.
0, as a timeout argument, may behave differently on different platforms, and is not recommended.
And pcap_next() is not guaranteed to wait forever for a packet to arrive; it might return NULL if the timeout expires. If you want to capture at least one packet, try looping until pcap_null() doesn't return NULL.

How do I judge whether the socket is connected or not?

I'm using the HP Loadrunner to test socket protocol program,now I send some hexadecimal number system to the server,but I have no idea to judge whether the socket is connected or not,I paste my script below down here
#define _EOF '#'
#include "lrs.h"
Action()
{
char *recvbuf;
int recvlen=0;
int rc;
lr_think_time(1000);
lr_start_transaction("Trans_socket");
lrs_set_recv_timeout (1,500);
lr_start_transaction("Conn_socket");
rc = lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=192.168.10.110:10001", LrsLastArg);
lr_output_message("rc=%d",rc);
if (rc != 0 )
{
lr_end_transaction("Conn_socket", LR_FAIL);
lr_end_transaction("Trans_socket", LR_FAIL);
return 0;
}
lr_end_transaction("Conn_socket", LR_PASS);
lr_rendezvous("trace");
lrs_send("socket0","buf0", LrsLastArg);
lrs_receive ("socket0","buf1",LrsLastArg);
lrs_get_last_received_buffer ("socket0",&recvbuf,&recvlen);
if(recvlen==58)
lr_end_transaction("Trans_socket", LR_PASS);
else
lr_end_transaction ("Trans_socket", LR_FAIL);
lrs_send("socket0", "buf2", LrsLastArg);
lrs_receive("socket0", "buf3", LrsLastArg);
lrs_send("socket0", "buf4", LrsLastArg);
lrs_receive("socket0", "buf5", LrsLastArg);
lr_think_time(100);
lrs_send("socket0", "buf6", LrsLastArg);
lr_think_time(1000);
lrs_receive("socket0", "buf7", LrsLastArg);
lr_think_time(1000);
lrs_send("socket0", "buf8", LrsLastArg);
lrs_receive("socket0", "buf9", LrsLastArg);
lrs_close_socket("socket0");
return 0;
}
,but I have no idea to judge whether the socket is connected
It is time to hire a sockets programmer who has been there and done that.
You also have some extremely odd conventions in your code from a loadrunner perspective. You appear to be treating user think time as delays while waiting for a server response in your code which would indicate conceptual issues in the use of the tool. Your use of a rendezvous is a key indicator of a model violation in its common use, where the tool is being used to break the chaotic nature of end users arriving and departing at different points in time.
You can do the following:
Enable continue on error
Check socket attributes
Disable continue on error
For example
char* peer;
lr_continue_on_error(1);
lrs_create_socket("socket1", "TCP", "LocalHost=0", "RemoteHost=fakehost", LrsLastArg);
peer =lrs_get_socket_attrib("socket1", REMOTE_ADDRESS );
if (peer == NULL){
lr_message("Not connected");
}else{
lr_message("Connected");
}
lr_continue_on_error(0);

connect and send on the socket succeeds, even if WIFI not enabled and server is only reacheable in the wireless network - Windows Mobile 6.5 - C/C++

I wrote a small C/C++ Windows Mobile 6.5 client-application that is connecting to a server and sends some data to this server. The server is in my internal wireless network and is not reacheable outside.
The weird behaviour I'm having:
1) Even if the WIFI is not started on my mobile device, the connect() from the client-application returns success (!= SOCKET_ERROR), which is not the case b/c the server is reacheable only in the wireless network.
2) If the WIFI is not started on my mobile device, if there is a Sleep(1000) between the connect() and the send(), the send() fails with WSAECONNRESET, BUT if there is no Sleep() between the connect() and send() the send() succeeds! (only when doing the read() I finally get the WSAECONNRESET error).
Can somebody pls point me some tips why do I have this behaviour. It's pretty scary that without actually being able to reach the server I still get success for the connect() and for the send() :(
As requested, here is a sample code:
#include <windows.h>
#include <Winsock2.h>
#include "dbgview.h"
# define FxMemZero(buf,len) RtlZeroMemory ((VOID*)(buf),(SIZE_T)(len))
# define FxMemCopy(dst,src,len) RtlCopyMemory ((VOID*)(dst),(CONST VOID*)(src),(SIZE_T)(len))
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
SOCKET proxy_connection;
WSADATA wsadata;
if( 0 != WSAStartup (MAKEWORD(1, 1), &wsadata))
return -1;
proxy_connection = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if(proxy_connection == INVALID_SOCKET) {
// error creating the socket
DbgViewTraceError((L"main", L"error creating socket."));
return -1;
}
// try to connect
UINT proxy_ip_ = 0x00000000;
CHAR* proxy_0_ = "192.168.1.105";
UINT proxy_port = 3100;
// get the proxy ip
{
struct hostent *he_;
if((he_ = gethostbyname(proxy_0_)) == NULL) {
DbgViewTraceWarning((L"main", L"error %d resolving hostname %hs", WSAGetLastError(), proxy_0_));
return -1;
}
FxMemCopy((PBYTE)&proxy_ip_, (PBYTE)he_->h_addr, he_->h_length);
}
// prepare the connection data
sockaddr_in saddr_;
FxMemZero(&saddr_,sizeof(sockaddr_in));
saddr_.sin_family = AF_INET;
saddr_.sin_addr.S_un.S_addr = proxy_ip_;// address
saddr_.sin_port = htons((USHORT)proxy_port);
// do the conection
if(SOCKET_ERROR == connect(proxy_connection, (SOCKADDR*) &saddr_, sizeof(saddr_))) {
// error connecting to the proxy
DbgViewTraceWarning(( L"main", L"error %d connecting to %hs:%d", WSAGetLastError(), proxy_0_, proxy_port));
closesocket(proxy_connection);
proxy_connection = INVALID_SOCKET;
return -1;
}
DbgViewTraceInfo(( L"main", L"SUCCESS. connected to %hs:%d.", proxy_0_, proxy_port));
CHAR* buffer_ = "Momo";
UINT count_ = strlen(buffer_);
DWORD total_ = 0;
DWORD sent_ = 0;
while(total_ < count_) {
// ISSUE: IF the WIFI is not started on the mobile, the connect returns success AND the send() returns success, even though with putty
// on the mobile, a telnet on 192.168.1.105:3100 will fail with: "Network error: Connection reset by peer"
// IF I add a long-enough Sleep() between the connect() and the send(), the send() will fail with: WSAECONNRESET
//Sleep(5000);
if(SOCKET_ERROR == (sent_ = send(proxy_connection, (const char*)buffer_ + total_, count_ - total_, 0))) {
// error sending data to the socket
DbgViewTraceError((L"main", L"error %d sending data to proxy", WSAGetLastError()));
return -1;
}
total_ += sent_;
}
DbgViewTraceInfo((L"main", L"send() SUCCESS"));
return 0;
}
The results are:
1) Without Sleep():
main [INFO ] SUCCESS. connected to 192.168.1.105:3100.
main [INFO ] send() SUCCESS
2) With Sleep():
main [INFO ] SUCCESS. connected to 192.168.1.105:3100.
main [ERROR ] error 10054 sending data to proxy
So the questions are:
1) Why the connect() succeeds? How can I be sure that there is actually a real connection?
2) Why the send() succeeds?
3) Why with a Sleep() in between connect() and send() the behaviour is different?
The problem seems to be ActiveSync. If ActiveSync is running, I get the behavior described above (connect() and send() report success, even though they are not). If ActiveSync is not running, gethostbyname() fails with:
WSAENETDOWN -> if WIFI is disabled
WSAHOST_NOT_FOUND -> if WIFI is enabled
which is correct!
How can this be? What is ActiveSync doing that is ruining everything? How can I avoid this problem? I mean, I can't be sure that the user is running my application when there is no ActiveSync running, so what can I do to avoid this behavior when ActiveSync is running?
Thx,
MeCoco
Looks like you are at least misusing struct sockaddr_in. Try more modern API for address conversion - Windows has InetPton - and see if that fixes the issues.