I have a simple server program that looks like the code below:
// create, bind, listen accept etc..
while(1)
{
UpdateData();
int ret = send(sock, data, dataLength , 0);
// Check if client sent "Abort" and if so, break.
}
Is it possible to check if any data has arrived from the client without blocking, so that the server can continuously dump data to the client?
Yes of course, there are a lot of solutions, AFAIK:
Thread
Non blocking mode
select()
poll()
epoll()
IOCP()
kqueue()
Not all available for all OS.
If your gonna define a non-blocking socket, you should add SOCK_NONBLOCK value in socket-type parameter when open a socket. for example this statement open a RAW socket in which can read and write TCP packets in non-blocking mode :
recv_socket = socket(AF_INET, SOCK_RAW | SOCK_NONBLOCK
, IPPROTO_TCP);
Then you can call read function as bellow :
typedef struct
{
struct iphdr ip;
struct tcphdr tcp;
char datagram[DATAGRAM_SIZE];
} TCP_PACKET;
int ret_read = 0;
TCP_PACKET recv_packet;
ret_read = read(recv_socket, reinterpret_cast<void*>(&received_packet)
, sizeof(received_packet));
if(ret_read >= 0)
{
// read occured in success
}
Notice : never use of const-size in read :
ret_read = read(recv_socket, reinterpret_cast<void*>(&received_packet)
, 65536); // makes segmentation fault
it makes segmentation fault while reading packets. just use of sizeof.
Related
I am trying to create a event driven multiple threads UDP/DTLS server. The design is based on the following concepts
Have a UDP socket where the Clients connects on
Use Epoll to ask for events on the UDP listen socket.
The UDP socket acts as a TCP listen socket and creates child fds that connect to the specific client. For this I have implemented a UDPAccept method for my object which has the pseudo code as shown below
UDPAccept(int fd,struct sockaddr * addr,
socklen_t * addr_len,void *sockBuf,size_t *read)
{
//sanity checks
int childfd = -1;
int error = 1;
socklen_t localLen,peerLen;
int family;
struct sockaddr_in local4,peer4;
struct sockaddr temp;
size_t maxLen = 65535;
getsockname(fd,(struct sockaddr *)&temp,&localLen);
family = temp.sa_family;
do
{
childfd = socket(family,SOCK_DGRAM,0);
//error handling
//handle IPV6
local4 = (sockaddr_in *)temp;
error = recvfrom( fd, sockBuf,
maxLen,0,(struct sockaddr *)&peer4,
&peerLen);
error = bind(childfd,(struct sockaddr *)&local4,sizeof local4);
error = connect(childfd,(struct sockaddr *)&peerV4,peerLen);
//handle error
}while(0);
if(addr != NULL && addr_len != NULL)
{
*addr_len = peerLen;
addr = &peerV4;
*read = error;
}
// error handling and cleanup
return childfd;
}
Add the child socket to Epoll table.
epoll_ctl(efd,EPOLL_CTL_ADD,newFd,&event);
Poll for events on the child and listen socket
currentSize = epoll_wait(efd,events,MAX_SOCKET_FD,timeout);
//handle errors
for(i = 0; i < currentSize;i++)
{
if(events[i].data.fd == listenUDP)
//call UDPAccept
// update local tables
else
//handle child fd events
}
Have multiple threads to the same thing, synchronize using locks during accept
Now my question is will epoll stop giving me POLLIN events on the listening socket because I have created a new UDP child connected socket to the client or will I have to handle it myself
It will deliver events on both sockets unless you remove the first socket from events.
But I'm wondering why you're doing this. You can use a single UDP socket for everything. It's much simpler.
Per the Linux man page on connect(), a filter will ensure only datagrams from the "connected" peer will be delivered to the new socket.
One caveat though... The bind() call will briefly take over the port from the listener until the connect call(). It's a small window, but can result in datagrams from other clients appearing on the "connected" socket. You can ignore them by validating the peer address.
I'm writing a very simple server application just for the purpose of testing some code.
After creating a socket and bind()ing it to my localhost and some port I'd like to use select() to know when an incoming connection arrives to the bound socket. After that the application should print the message up to a certain lenght and then exit().
My question is basically if I need to use listen() and accept() when I'm expecting only one connection (please remember this is just for testing). I believe these functions are not needed in this case and are only needed for accepting multiple incoming requests. Am I wrong?
With the above ideia in mind I wrote the following code
int main()
{
int fd = TCPcreate(atoh("127.0.0.1"), 15000); /*my localhost address*/
char *str = malloc(100);
int a;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
a = select(fd+1,&rfds,(fd_set*)NULL,(fd_set*)NULL,(struct timeval*)NULL);
// printf("select returns %d\nfd = %d\n", a, fd);
// printf("fd is set? %s\n", FD_ISSET(fd,&rfds) ? "yes" : "no");
a = TCPrecv(fd, str, 100); /*receive at most 100B */
// printf("%d\n", a);
printf("%s\n", str);
close(fd);
exit(0);
}
TCPcreate()
int TCPcreate(unsigned long IP, unsigned short port)
{
int fd;
struct sockaddr_in address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd==-1)
{
return -1;
}
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(IP);
address.sin_port = htons(port);
/* struct sockaddr_in is the same size as struct sockaddr */
if(bind(fd, (struct sockaddr*)&address, sizeof(address))==-1)
{
return -2;
}
return fd;
}
atoh() simply returns its argument in host byte order.
What happens when I run the program is that select() doesn't block waiting for a connection. Instead, it immediately returns 1. If I uncomment the printf()s what I get is
select returns 1
fd = 3
is set? yes
-1
(blank line)
What am I missing here?...
If you look at the POSIX specification of select(), the file descriptors returned are ready for reading, writing, or have an error condition on them. This does not list 'a socket on which listen() would succeed' as one of the detectable conditions. So, you will need to use listen() and accept(); only after you've accepted the connection can you use select() on the descriptors.
As Gonçalo Ribeiro notes, the specification for select() also says:
If the socket is currently listening, then it shall be marked as readable if an incoming connection request has been received, and a call to the accept() function shall complete without blocking.
That means you must have done a listen() on the bound socket, but you can wait on multiple sockets for incoming connections.
If you want blocking call - use listen().
The problem with the select is in your code is - keep the select in the loop. As it is a non-blocking call, it will only check once that someone is there to listen or not. So, you can use loop to check for listen many times.
I've been trying to write a POP3 client for yahoo, but whenever I send a valid command, I cannot read from socket . I know it's not safe to create applications that deal in plaintext over the web, but I'm just trying to learn more about POP3 for now.
I'm creating a graphic interface using QT , but I believe this is irrelevant for now.
First of all, I made sure that yahoo supports plaintext communication by running simple commands in the terminal:
telnet pop.mail.yahoo.com 110
+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com
user validuser
+OK password required.
pass validpassword
+OK maildrop ready, 100 messages (134513 octets) (13531)
This is how I handle opening the connection:
int openConnection(char ip[], int port)
{
//descriptor of socket
int sd;
struct sockaddr_in server;
//fill in server structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr (ip);
server.sin_port = htons (port);
//create communication socket
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
//if cannot create, return error
return -2;
}
if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
{
return -1;
}
return sd;
//values to be returned
//-2 - could not create socket
//-1 - could not connect to server
//socket descriptor in case of success
}
I get no problem with creating the socket and connecting when I call
int sd = openConnection ("188.125.68.106", 110)
(188.125.68.106 = ip of pop.mail.yahoo.com)
I can even read the welcoming message without using select or epoll.
char message[80];
read (sd, message, 80);
Message:
+OK hello from popgate-0.8.0.504347 pop011.mail.ir2.yahoo.com
I can also send all sorts of invalid commands, and read the error returned
int sd = openConnection ("188.125.68.106", 110)
write (sd,"this command is invalid",80);
char messageFromS [80];
bzero (messageFromS, 80);
read (sd,messageFromS,80);
And I get something between the lines of
-ERR invalid command
But whenever I send a valid command, my client just freezes up after calling read and I have to force quit
write (sd,"user validuser",80);
char messageFromS [80];
bzero (messageFromS, 80);
read (sd,messageFromS,80);
Afterwards, I decided to use select() because I know it's a good practice, and maybe it could give good results
//function returns true (1) if we can read from the socket
bool isClosed(int sock)
{
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(sock, &rfd);
timeval tv;
//timeout value is set to 5 seconds
tv.tv_sec = 5;
select(sock+1, &rfd, 0, 0, &tv);
if (!FD_ISSET(sock, &rfd))
return false;
int n = 0;
ioctl(sock, FIONREAD, &n);
return n == 0;
}
But it seems that whenever I call
isClosed(sd)
It always returns True.
This is the point where I cannot think of any other options. Is there anything that Telnet has that my miniature client doesn't ?
EDIT: Thank you for your answers.
I played around with reading all the messages received byte by byte, until it found a termination character (apparently it wasn't NULL), and, after re-reading the RFC for pop3 (https://www.rfc-editor.org/rfc/rfc1081) closely I realized that I wasn't ending my commands properly. I should have appended '\r' and '\n' to the end of all commands sent.
I also checked the select () command, which returned -1 and set the tv.tv_usec = 0 which pretty much solved it.
Thank you for your answers.
I played around with reading all the messages received byte by byte, until it found a termination character (apparently it wasn't NULL), and, after re-reading the RFC for pop3 (https://www.rfc-editor.org/rfc/rfc1081) closely I realized that I wasn't ending my commands properly. I should have appended '\r' and '\n' to the end of all commands sent.
I also checked the select () command, which returned -1 and set the tv.tv_usec = 0 which pretty much solved it.
– Shoshinsha purogurama
I have a TCP connection. Server just reads data from the client. Now, if the connection is lost, the client will get an error while writing the data to the pipe (broken pipe), but the server still listens on that pipe. Is there any way I can find if the connection is UP or NOT?
You could call getsockopt just like the following:
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);
To test if the socket is up:
if (retval != 0) {
/* there was a problem getting the error code */
fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
return;
}
if (error != 0) {
/* socket has a non zero error status */
fprintf(stderr, "socket error: %s\n", strerror(error));
}
The only way to reliably detect if a socket is still connected is to periodically try to send data. Its usually more convenient to define an application level 'ping' packet that the clients ignore, but if the protocol is already specced out without such a capability you should be able to configure tcp sockets to do this by setting the SO_KEEPALIVE socket option. I've linked to the winsock documentation, but the same functionality should be available on all BSD-like socket stacks.
TCP keepalive socket option (SO_KEEPALIVE) would help in this scenario and close server socket in case of connection loss.
There is an easy way to check socket connection state via poll call. First, you need to poll socket, whether it has POLLIN event.
If socket is not closed and there is data to read then read will return more than zero.
If there is no new data on socket, then POLLIN will be set to 0 in revents
If socket is closed then POLLIN flag will be set to one and read will return 0.
Here is small code snippet:
int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
perror("Unable to accept s1");
abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
perror("Unable to accept s2");
abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024];
while (true)
{
poll(pfd,2,5);
if (pfd[0].revents & POLLIN)
{
int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
if (sock_readden == 0)
break;
if (sock_readden > 0)
write(client_socket_2, sock_buf, sock_readden);
}
if (pfd[1].revents & POLLIN)
{
int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
if (sock_readden == 0)
break;
if (sock_readden > 0)
write(client_socket_1, sock_buf, sock_readden);
}
}
Very simple, as pictured in the recv.
To check that you will want to read 1 byte from the socket with MSG_PEEK and MSG_DONT_WAIT. This will not dequeue data (PEEK) and the operation is nonblocking (DONT_WAIT)
while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
sleep(rand() % 2); // Sleep for a bit to avoid spam
fflush(stdin);
printf("I am alive: %d\n", socket);
}
// When the client has disconnected, this line will execute
printf("Client %d went away :(\n", client->socket);
Found the example here.
I had a similar problem. I wanted to know whether the server is connected to client or the client is connected to server. In such circumstances the return value of the recv function can come in handy. If the socket is not connected it will return 0 bytes. Thus using this I broke the loop and did not have to use any extra threads of functions. You might also use this same if experts feel this is the correct method.
get sock opt may be somewhat useful, however, another way would to have a signal handler installed for SIGPIPE. Basically whenever you the socket connection breaks, the kernel will send a SIGPIPE signal to the process and then you can do the needful. But this still does not provide the solution for knowing the status of the connection. hope this helps.
You should try to use: getpeername function.
now when the connection is down you will get in errno:
ENOTCONN - The socket is not connected.
which means for you DOWN.
else (if no other failures) there the return code will 0 --> which means UP.
resources:
man page: http://man7.org/linux/man-pages/man2/getpeername.2.html
On Windows you can query the precise state of any port on any network-adapter using:
GetExtendedTcpTable
You can filter it to only those related to your process, etc and do as you wish periodically monitoring as needed. This is "an alternative" approach.
You could also duplicate the socket handle and set up an IOCP/Overlapped i/o wait on the socket and monitor it that way as well.
#include <sys/socket.h>
#include <poll.h>
...
int client = accept(sock_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
pollfd pfd = {client, POLLERR, 0}; // monitor errors occurring on client fd
...
while(true)
{
...
if(not check_connection(pfd, 5))
{
close(client);
close(sock[1]);
if(reconnect(HOST, PORT, reconnect_function))
printf("Reconnected.\n");
pfd = {client, POLLERR, 0};
}
...
}
...
bool check_connection(pollfd &pfd, int poll_timeout)
{
poll(&pfd, 1, poll_timeout);
return not (pfd.revents & POLLERR);
}
you can use SS_ISCONNECTED macro in getsockopt() function.
SS_ISCONNECTED is define in socketvar.h.
For BSD sockets I'd check out Beej's guide. When recv returns 0 you know the other side disconnected.
Now you might actually be asking, what is the easiest way to detect the other side disconnecting? One way of doing it is to have a thread always doing a recv. That thread will be able to instantly tell when the client disconnects.
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.