I'm working on a system that doesn't run unix / linux / windows or any familiar OS.
Yet, there are some libraries for sockets, one of them is socket.h.
The thing is that there is setsockopt function there, and some options, but there isn't fcntl.h library. I saw that this is the only way to get and set the socket's flags (O_NONBLOCK is what i seek).
Also, I saw that It is possible to use setsockopt with so_rcvtimeo and so_sndtimeo. I tried it and it is still blocking. The connect function was stuck when I was unplugging the ethernet cable right before the execution reached the connect line (in debug mode of course).
Is there a way to do it with the socket.h library only ?
Thanks,
Edit:
I'm using a system with Texas Instruments chip.
This is my current code, which doesn't work. "connect" returns -1 and I don't have errno to check what went wrong.
if (setsockopt(s, SOL_SOCKET, SO_BLOCKING, (char *)&isBlockingOption, sizeof(isBlockingOption)) < 0) {
/* closing the socket and exiting */
}
connect(s, &controlAddressStruct, sizeof(controlAddressStruct));
FD_ZERO(&conSocketSet);
FD_SET(s, &conSocketSet);
connectTimeout.tv_sec = 5;
connectTimeout.tv_usec = 0;
selectRet = fdselect( (int)s + 1, NULL, &conSocketSet, NULL, &connectTimeout);
if (selectRet == 1) {
socketLen = sizeof(so_error);
getsockopt(s, SOL_SOCKET, SO_ERROR, &so_error, &socketLen);
if (so_error == 0) {
return s;
}
}
return INVALID_SOCKET;
now, when the ethernet cable is plugged between the two systems, so_error = 0 and s is returned. Then when I read the FTP server reply, I get error so I exit the program.
But, if I removed the setsockopt for the SO_BLOCKING, everything is fine and the FTP server sends me the requested file.
If the send() and recv() interfaces are similar to the BSD sockets interface at all, the fourth parameter should correspond to flags. If so, you may be able to pass in MSG_DONTWAIT to the fourth parameter to effect non-blocking I/O.
Related
app A and app B created Unix domain datagram socket,A call connect to connect B,so A can use read and write 0r send and recv to communicate with B.but if B crashed,A will block at recv.B restart,sending msg to A will get error 1 operation not permitted.is there any way A can detect B crashed ?
OS:Ubuntu 18.04 kernel 4.18.0
If you want to detect connection errors, a connection-orientated socket might be more appropriate, like SOCK_STREAM or SOCK_SEQPACKET
From the man page of socket:
...
If a piece of data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, then the connection is considered to be dead. When SO_KEEPALIVE is enabled on the socket the protocol checks in a protocol-specific manner if the other end is still alive.
...
SOCK_SEQPACKET sockets employ the same system calls as SOCK_STREAM sockets.
Nonblocking reads can be achieved via the O_NONBLOCK flag (on the descriptor) or the recv flag MSG_DONTWAIT.
Connection error detection on connectionless protocols has to be implemented in the application. You could implement a simple ping/heartbeat mechanism, where a client has to send (empty) packets within a specific time interval to indicate that it is still alive or still participating in the communication.
Edit: I've used TCP/UDP synonymously for SOCK_STREAM/SOCK_DGRAM (as the user Shawn pointed out in the comments below).
I had the same problem recently, and the solutions that I found on the web did not entirely convince me. Therefore, I came up with this:
// Client: replace every close() with this close_dgram_socket():
int close_dgram_socket(int fd)
{
if (send(fd, "Bye-bye.", 8) == -1)
perror("send");
close(fd)
}
// Server loop:
do
{
fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds);
struct timeval timeout = { 0, 300000 }; // 300 ms
if (select(fd+1, &readfds, 0, 0, &timeout) == 0) // nothing reveived
{
if (kill(getppid(), 0)
break; // client has died
else
continue;
}
rx_len = recv(fd, buf, sizeof(buf), 0);
} while(rx_len != 8 || strncmp(buffer, "Bye-bye.", 8));
close(fd); // peer has closed, so do we.
The idea is that (1) the server sends a Bye-bye datagram if she closes the socket orderly and (2) the client checks with kill() if the server is still alive to handle the case where the server crashes and cannot send the Bye-bye datagram. Works fine for socketpair() but not for UDP.
I am trying to use a Pi to emulate a Bluetooth device using the BlueZ C api. I am able to separately 1) configure the SDP server to advertise the correct service and 2) listen for and establish an L2CAP connection. However, I'm unable to do both at the same time.
The issue is that sdp_record_register() will segfault unless bluetoothd is both running and in compatibility mode. However, accept() won't return for the Bluetooth socket if bluetoothd is running, because bluetoothd will steal the request.
So I can either:
Register/advertise my service with SDP, but not be able to accepting incoming connections, by running bluetoothd (in compatibility mode).
Be able to accept incoming connections, but not able to register/advertise my service, by not running bluetoothd.
Setting up the SDP service
int deviceID = hci_get_route(NULL);
if (deviceID < 0) {
printf("Error: Bluetooth device not found\n");
exit(1);
}
int bluetoothHCISocket = hci_open_dev(deviceID);
if (bluetoothHCISocket < 0) {
perror("hci_open_device");
exit(2);
}
/* some HCI config */
sdp_session_t *session = sdp_connect(&myBDAddrAny, &myBDAddrLocal, SDP_RETRY_IF_BUSY);
sdp_record_t record;
bzero(&record, sizeof(sdp_record_t));
record.handle = 0x10000;
/* register all of the attributes for my service */
printf("Might segfault\n");
if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
perror("sdp_record_register");
exit(7);
}
printf("Didn't segfault\n");
This works when bluetoothd is running in compatibility mode, but will segfault when it's either not running or running in default mode.
Accepting a Bluetooth connection
int btSocket = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (btSocket < 0) {
perror("socket");
exit(3);
}
struct sockaddr_l2 loc_addr = { 0 };
loc_addr.l2_family = AF_BLUETOOTH;
loc_addr.l2_bdaddr = myBDAddrAny;
loc_addr.l2_psm = htobs(0x11);
if (bind(btSocket, (struct sockaddr *)&loc_addr, sizeof(loc_addr))) {
perror("bind");
exit(4);
}
if (listen(btSocket, 1)) {
perror("listen");
exit(6);
}
struct sockaddr_l2 remoteAddress;
socklen_t socketSize = sizeof(remoteAddress);
printf("Waiting for connection\n");
int clientSocket = accept(btSocket, (struct sockaddr *)&remoteAddress, &socketSize);
This will properly accept an incoming connection when bluetoothd is not running, but accept() will never return if bluetoothd is running (in any mode).
I haven't been unable to reconcile these two issues. It seems like the ideal solution would be to somehow tell bluetoothd to ignore connections on PSM 0x11 (since that means its agent can still handle pairing), but I can't figure out how to do that.
The (unsatisfying but correct) answer is to not use the hci* API. That API is apparently deprecated, so bugs like that segfault are not going to be fixed. The correct way to do this is to use the DBus API. That API is almost as cumbersome as the hci API, but at least it's documented.
After swapping out the massive amount of hci-based code I'de written with the gdbus API offered by glib-2.0 to set up the SDP service, I was finally able to advertise the service and connect at the same time. My socket code worked without modification.
So how do you do this properly?
I know how to do it by creating socket, then setting IFF_PROMISC flag using ioctl (as explained in "howto check a network devices status in C?" and elsewhere), but this looks flawed at least in theory.
you read flags via ioctl
you update flags
someone else modified flags
you set updated flags via ioctl
Is there a better way or do I simply worry too much?
Later I found that one should add interface to PACKET_MR_PROMISC via setsockopt (which also does not have a race) like this:
void set_promisc(const char *ifname, bool enable)
{
struct packet_mreq mreq = {0};
int sfd;
int action;
if ((sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("unable to open socket");
return;
}
mreq.mr_ifindex = if_nametoindex(ifname);
mreq.mr_type = PACKET_MR_PROMISC;
if (mreq.mr_ifindex == 0) {
perror("unable to get interface index");
return;
}
if (enable)
action = PACKET_ADD_MEMBERSHIP;
else
action = PACKET_DROP_MEMBERSHIP;
if (setsockopt(sfd, SOL_PACKET, action, &mreq, sizeof(mreq)) != 0) {
perror("unable to enter promiscouous mode");
return;
}
close(sfd);
}
Unfortunately this has no effect whatsoever on interface, although it should, if I unserstand the doc correctly. Possibly broken since 2001 (tm)?
Comments in pcap source also complain about this.
PACKET_MR_PROMISC turns on promiscuous mode for the device. That will not be reflected in the status shown by ifconfig as it does not modify the state of the global IFF_PROMISC flag on the device. That does not mean it hasn't been done though. This is how the pcap library works now and the fact that wireshark (and a dozen other utilities) can open a device and see packets not addressed to the local system shows that it works.
There is an internal counter on each device that is incremented each time a process uses PACKET_MR_PROMISC, and decremented when that process goes away. That solves the race you originally described.
From the last link you provided:
> IFF_PROMISC is not set,
It's not supposed to be set.
The correct way to put into promiscuous mode the device to which a
PF_PACKET socket is to do a SOL_PACKET/PACKET_ADD_MEMBERSHIP
"setsockopt()" call with PACKET_MR_PROMISC as the argument (see the
"packet(7)" man page), and that's what libpcap is doing.
The old way of directly setting IFF_PROMISC had problems - to quote the
comment at the front of "pcap-linux.c":
[snipped]
What is the right (portable, stable) way to get the ToS byte of a received packet? I'm doing UDP with recvmsg() and on linux I can get the ToS if I setsockopt() IP_RECVTOS/IPV6_RECVTCLASS, but IP_RECVTOS doesn't seem to be available on my BSD systems. What is the right way to do this?
I primarily want this to work on the BSDs and Solaris.
Edit:
To clarify:
I currently use recvmsg() where I get the TTL and TOS in the msg_control field on Linux, but in order to get TTL and TOS I need to setsockopt()-enable IP_RECVTTL and IP_RECVTOS. And since Solaris and BSD (working with FreeBSD at the moment) don't have IP_RECVTOS from what I can see I don't get TOS when looping over the CMSG data.
I tried enabling IP_RECVOPTS and IP_RECVRETOPTS, but I still don't get any IP_TOS type CMSG.
Edit 2:
I want ToS to be able to verify (as much as possible) that it wasn't overwritten in transit. If for example a VoIP app all of a sudden notices that it's not getting EF tagged packets, then something is wrong and there should be an alarm. (and no, I'm not expecting EF to be respected or preserved over the public internet)
I want TTL basically just because I can. Hypothetically this could be used to trigger "something changed in the network between me and the other side" alerts, which can be useful to know if somethings stops working at the same time.
I was thinking if you can create two sockets.
One socket of type DGRAM used exclusively for sending
One Raw socket used exclusively for receiving.
Since you are using UDP, you can call a bind + recvFrom on the Raw Sock Fd and then manually unpack the IP header to determine the TOS or TTL.
When you want to send, use the DGRAM sockFd so you dont have to bother to actually create the UDP & IP packet yourself.
There may be issues like the kernel may pass the received buffer to both sockets or to the UDP socket instead of Raw socket or just to the Raw socket. If that is the case (or if it is implementation dependent) then we are back to square one. However, you can try calling bind on the Raw socket and see if it helps. I am aware this maybe a hack but searching on the net for a setsockopt for BSD returned nothing.
EDIT: I wrote a sample program
It kind of achieves the objective.
The code below creates two sockets (one raw & one udp). The udp socket is bound on the actual port I am expecting to receive data whereas the raw socket is bound on Port 0. I tested this on Linux and like I expected any data for port 2905 is received by both the sockets. I am however able to retrieve the TTL & TOS values. Dont downvote for the quality of the code. I am just experimenting whether it will work.
Further EDIT: Disabled the receive by UDP socket.
I have further enhanced the code to disable the receive by the UDP packet. Using setsockopt, I set the UDP's socket receive buffer to 0. This ensures the kernel does not pass the packet to the UDP socket. IMHO,You can now use the UDP socket exclusively for sending and the raw socket for reading. This should work for you in BSD and Solaris also.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<arpa/inet.h>
#include<string.h>
#include "protHeaders.x"
#include "gen.h"
int main(void)
{
S32 rawSockFd;
S32 udpSockFd;
struct sockaddr_in rsin;
struct sockaddr_in usin;
S32 one = 1;
const S32* val = &one;
struct timeval tv;
fd_set rfds;
S32 maxFd;
S16 ret;
S8 rawBuffer[2048];
S8 udpBuffer[2048];
struct sockaddr udpFrom,rawFrom;
socklen_t rLen,uLen;
memset(rawBuffer,0,sizeof(rawBuffer));
memset(udpBuffer,0,sizeof(udpBuffer));
memset(udpFrom,0,sizeof(udpFrom));
memset(rawFrom,0,sizeof(rawFrom));
if ((rawSockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
/* doing the IP_HDRINCL call */
if (setsockopt(rawSockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
{
perror("Server:setsockopt");
RETVALUE(RFAILED);
}
rsin.sin_family = AF_INET;
rsin.sin_addr.s_addr = htonl(INADDR_ANY);
rsin.sin_port = htons(0);
usin.sin_family = AF_INET;
usin.sin_addr.s_addr = htons(INADDR_ANY);
usin.sin_port = htons(2905);
if(bind(rawSockFd,(struct sockaddr *)&rsin, sizeof(rsin)) < 0 )
{
perror("Server: bind failed");
RETVALUE(RFAILED);
}
if ((udpSockFd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETVALUE(RFAILED);
}
if(bind(udpSockFd,(struct sockaddr *)&usin, sizeof(usin)) < 0 )
{
perror("Server: bind failed on udpsocket");
RETVALUE(RFAILED);
}
/*set upd socket receive buffer to 0 */
one = 0;
if (setsockopt(udpSockFd,SOL_SOCKET,SO_RCVBUF,(char *)&one,sizeof(one)) < 0)
{
perror("Server:setsockopt on udpsocket failed");
RETVALUE(RFAILED);
}
tv.tv_sec = 0;
tv.tv_usec = 0;
maxFd = (rawSockFd > udpSockFd)? rawSockFd:udpSockFd;
while(1)
{
FD_ZERO(&rfds);
FD_SET(rawSockFd,&rfds);
FD_SET(udpSockFd,&rfds);
ret = select(maxFd+1,&rfds,0,0,&tv);
if ( ret == -1)
{
perror("Select Failed");
RETVALUE(RFAILED);
}
if(FD_ISSET(rawSockFd,&rfds))
{
printf("Raw Socked Received Message\n");
if(recvfrom(rawSockFd,rawBuffer,sizeof(rawBuffer),0,&rawFrom,&rLen) == -1)
{
perror("Raw socket recvfrom failed");
RETVALUE(RFAILED);
}
/*print the tos */
printf("TOS:%x\n",*(rawBuffer+1));
printf("TTL:%x\n",*(rawBuffer+8));
}
if(FD_ISSET(udpSockFd,&rfds))
{
printf("UDP Socked Received Message\n");
if(recvfrom(udpSockFd,udpBuffer,sizeof(udpBuffer),0,&udpFrom,&uLen) == -1)
{
perror("Udp socket recvfrom failed");
RETVALUE(RFAILED);
}
printf("%s\n",udpBuffer);
}
}
RETVALUE(ROK);
}
The "proper" and standard solution is probably to use cmsg(3). You'll find a complete description in Stevens' "Unix network programming" book, a must-read.
Google Code Search found me this example of use.
My understanding is that firstly BSD does not support IP_RECVTOS like functionality and secondly BSD raw sockets do not support the reception of UDP nor TCP packets. However there are two other ways of doing this, firstly by using the /dev/bpf interface - either directly or via libpcap. Or secondly by using DIVERT sockets which allow for diversion of specified traffic flows to userland.
Has anyone actually tested the code above on a BSD box? (it may work on Solaris...)
On Linux this approach will work but as mentioned it is also possible (and more convenient) to use setsockopt() with IP_TOS on the outgoing socket to set the outgoing TOS byte and setsockopt() with IP_RECVTOS on the incoming socket and use recvmsg() to retrieve the TOS byte.
Unfortuneatly this sort of thing usually varies across different *ixs. On Solaris you want to use getsockopt with IP_TOS; I don't know about BSD.
See man 7 ip for details.
I want to write a real-time analysis tool for wireless traffic.
Does anyone know how to read from a promiscuous (or sniffing) device in C?
I know that you need to have root access to do it. I was wondering if anyone knows what functions are necessary to do this. Normal sockets don't seem to make sense here.
On Linux you use a PF_PACKET socket to read data from a raw device, such as an ethernet interface running in promiscuous mode:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
This will send copies of every packet received up to your socket. It is quite likely that you don't really want every packet, though. The kernel can perform a first level of filtering using BPF, the Berkeley Packet Filter. BPF is essentially a stack-based virtual machine: it handles a small set of instructions such as:
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
BPF's exit code tells the kernel whether to copy the packet to the socket or not. It is possible to write relatively small BPF programs directly, using setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ). (WARNING: The kernel takes a struct sock_fprog, not a struct bpf_program, do not mix those up or your program will not work on some platforms).
For anything reasonably complex, you really want to use libpcap. BPF is limited in what it can do, in particular in the number of instructions it can execute per packet. libpcap will take care of splitting a complex filter up into two pieces, with the kernel performing a first level of filtering and the more-capable user-space code dropping the packets it didn't actually want to see.
libpcap also abstracts the kernel interface out of your application code. Linux and BSD use similar APIs, but Solaris requires DLPI and Windows uses something else.
I once had to listen on raw ethernet frames and ended up creating a wrapper for this. By calling the function with the device name, ex eth0 I got a socket in return that was in promiscuous mode.
What you need to do is to create a raw socket and then put it into promiscuous mode. Here is how I did it.
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
return raw_socket;
}
Then when you have your socket you can just use select to handle packets as they arrive.
You could use the pcap library (see http://www.tcpdump.org/pcap.htm) which is also used by tcpdump and Wireshark.
Why wouldn't you use something like WireShark?
It is open source, so at least you could learn a few things from it if you don't want to just use it.
WireShark on linux has the capability to capture the PLCP (physical layer convergence protocol) header information.