Broken Pipe signal on a DNS client - process

I'm building a DNS client. A child process handles the request through an UDP socket, while the parent handles the reply. I need the parent to know how many bytes were sent, in order to print the URLs. I tried the following approach with pipe()
childPID = fork();
pipe(fd);
if(childPID == 0){
close(fd[0]);
sent_bytes = sendDNS(sock_udp, &serverAddr, argv[2]);
memcpy(in_buf, &sent_bytes, sizeof(sent_bytes));
write(fd[1], in_buf, sizeof(sent_bytes));
exit(0);
}
else{
close(fd[1]);
int inBytes = -1;
struct sockaddr reply_addr;
n = sizeof(reply_addr);
while(inBytes < 0){
inBytes = recvfrom(sock_udp, buffer, DNS_MAX_RESPONSE, 0, &reply_addr, (socklen_t*)&n);
read(fd[0], out_buf, sizeof(sent_bytes));
memcpy(pipe_msg, out_buf, sizeof(sent_bytes));
printDNSmsg((struct dnsReply*)buffer);
}
}
But GDB shows a SIGPIPE received on the child process. What am I missing?
How would you print a DNS reply (variable length buffer)?

You need to call pipe() before fork(), of course. But you're not actually using the information anywhere. Why do you care how many bytes were sent, as long as you got a reply? And why would you do a UDP send in a separate thread, let alone a separate process? It all seems completely pointless.

Related

Sending and receiving UDP using the same port does not work with the asio library?

I'm trying to send and receive UDP packets through the same endpoint. As far as I know this should be possible. But I can not get it to work with the asio library (version 1.20.0).
This is what I do:
asio::io_context io_context;
asio::ip::udp::socket* udpSendRecvSocket = new asio::ip::udp::socket(io_context, asio::ip::udp::endpoint(asio::ip::udp::v4(), 7782));
asio::error_code ec;
char data[1000];
//
// send packet
//
std::string ipAddress = "127.0.0.1";
asio::ip::address ip_address = asio::ip::address::from_string(ipAddress);
asio::ip::udp::endpoint remoteTarget_endpoint(ip_address, 5500);
udpSendRecvSocket->send_to(asio::buffer(data, 50), remoteTarget_endpoint, 0, ec);
if (ec) {
return 0;
}
//
// receive packets
//
size_t avLen = udpSendRecvSocket->available(ec);
while (avLen) {
asio::ip::udp::endpoint remote_endpoint;
size_t length = udpSendRecvSocket->receive_from(asio::buffer(data, 1000), remote_endpoint, 0, ec);
int p = remote_endpoint.port();
if (ec) {
return 0;
}
avLen -= length;
}
The receive does not work correctly. I do receive a packet that I send (from some other app). I know because avLen gets the right value. But when executing the receive_from(), if fails. And the port number in p gets the value 5500. This is the value of the target port of the send_to() call that was executed before.
The strange thing is that when I remove the send_to() call, the receive does work correctly and the p will reflect the correct port number of the sending application.
Is this a bug?

How to receive data over Ethernet using LWIP, UDP

I'm trying to send data to and from my computer and an STM32H745 over Ethernet using LwIP and UDP. I have successfully configured the card and right now I can send data from the card to a Python script running on the computer. However, I don't understand how udp_recv works <udp,lwip> or how to receive data with UDP on LwIP in general, and I can't find examples that do just that. Where is the data being received? Should I even use udp_recv?
In the main loop I run MX_LWIP_Process, which runs ethernetif_input which somehow handles the received data, but I don't understand where it puts it.
Below is the main code, just for reference.
const char* message = "a";
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); // orange
ip_addr_t PC_IPADDR;
IP_ADDR4(&PC_IPADDR, 192, 168, 1, 200);
u16_t port = 8000;
struct udp_pcb* my_udp = udp_new();
struct pbuf* udp_buffer = NULL;
/* Infinite loop */
for (;; )
{
MX_LWIP_Process();
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); // orange
HAL_Delay(1000);
udp_buffer = pbuf_alloc(PBUF_TRANSPORT, strlen(message), PBUF_RAM);
if (udp_buffer != NULL)
{
memcpy(udp_buffer->payload, message, strlen(message));
udp_sendto(my_udp, udp_buffer,&PC_IPADDR, port);
pbuf_free(udp_buffer);
}
//udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
}
udp_recv() does not actually receive UDP datagrams (despite its name). It registers a callback function that will then be called by MX_LWIP_Process() when a datagram has been buffered. It would better be called udp_set_recv_callback(), but it is what it is.
To that end you should call it once before your executive loop:
udp_bind( my_udp, IP_ADDR_ANY, port ) ;
udp_recv( my_udp, udp_receive_callback, NULL ) ;
/* Infinite loop */
for (;; )
{
// Run the CubeMX LwIP stack
MX_LWIP_Process() ;
...
}
Where udp_receive_callback is a function that will be invoked on receipt of a datagram:
void udp_receive_callback( void* arg, // User argument - udp_recv `arg` parameter
struct udp_pcb* upcb, // Receiving Protocol Control Block
struct pbuf* p, // Pointer to Datagram
const ip_addr_t* addr, // Address of sender
u16_t port ) // Sender port
{
// Process datagram here (non-blocking code)
...
// Must free receive pbuf before return
pbuf_free(p);
}
Examples include:
https://gist.github.com/iwanbk/1399729
https://github.com/STMicroelectronics/STM32CubeF2/blob/master/Projects/STM322xG_EVAL/Applications/LwIP/LwIP_UDP_Echo_Client/Src/udp_echoclient.c
Documentation can be found at https://www.nongnu.org/lwip/2_0_x/group__udp__raw.html

Passing a pipefd through execlp in C

I have looked all over and I cannot seem to figure out how to do this.
I have a parent process that has created a pipe()
Now, I want to fork() the parent and then execlp() and pass the pipe() to the new program as a command line argument.
Then from inside the new program I need to be able to read the pipefd.
I've seen a bunch of stuff on how to do it from inside the same process, but nothing on how to do it like this.
Edit: Initial post is/was rather vague.
What I have so far is:
int pfd[2];
if(pipe(pfd) == -1) {
perror("Creating pipe\n");
exit(1);
}
pid_t pid = fork();
if(pid == -1) {
fprintf (stderr, "Initiator Error Message : fork failed\n");
return -1;
}
else if(pid == 0) { // child process
close(pipe0[1]); // close(write);
execlp("program", "program", pipe0[0], NULL);
}
but then I don't really understand what I should do from inside "program" to get the FD. I tried assigning it to all sorts of things, but they all seem to error.
Thank you in advance!
The forked and execed child automatically inherit the open pipe descriptors and the pipe output is usually fed as standard input so that a command line argument to find the pipe is pretty redundant:
if(!pipe(&pipefd))
switch(fork()) {
case 0: !dup2(pipefd[0],0)&&
execlp("cat","cat","-n","/dev/fd/0",0);
case -1: return perror("fork");
default: write(pipefd[1],"OK\n",3);
}

Share unnamed semaphore between processes in Mac OS

I'm trying to share a unnamed mach semaphore between two processes.
I can create one and wait on it in the same process.
semaphore_t semaphore = 0;
mach_error_t err = semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
...
semaphore_wait(semaphore);
But I want to send it to another process (of which I only have the mach_port_t) and then let it semaphore_signal my own process.
I already tried things like:
mach_port_allocate(target, MACH_PORT_RIGHT_RECEIVE, targetSemaphore)
mach_port_insert_right(target, targetSemaphore, semaphore, MACH_MSG_TYPE_COPY_SEND)
Which will yield an error because the port name already exists in the target process or a "unknown failure" if I don't allocate it in the target process.
And even:
mach_msg_send
mach_msg_receive
But I can't even get a port right form one process to anther to send anything.
What am I doing wrong and is it even possible?
I figured it out:
mach_port_extract_right
is correct way, instead of:
mach_port_insert_right
Then doing this, will do the job:
semaphore_t semaphore = 0;
mach_error_t err = semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
err = mach_port_allocate(target, MACH_PORT_RIGHT_RECEIVE, &receivePort);
mach_msg_type_name_t type;
semaphore_t sendPort = 0;
err = mach_port_extract_right(target, receivePort, MACH_MSG_TYPE_MAKE_SEND, &sendPort, &type);
//Send semaphore using port
mach_msg_send(&msg.header);

SSH fork and children

I have a program where i ssh into a server and gets data. Here is the code... I fork it and the child executes the query and the parent waits for the child for a predetermined amount of time (in function timeout) and then kills the child. I did that part because sometimes, i am not exactly sure why, but the ssh connection stops and doesnot exit. That is there is a "ssh -oConnectTimeout=60 blah blah" in the processes list for a long and the timeout function doesnt seem to work. What am i doing wrong here? The last time this problem occured, there was an ssh in process list for 5 days and still it didnot timeout and the program had stopped because it was waiting for the child. There are those extra wait() functions because previously i was getting a lot of defunct processes a.k.a zombies. So i took the easy way out..
c = fork();
if(c==0) {
close(fd[READ]);
if (dup2(fd[WRITE],STDOUT_FILENO) != -1)
execlp("ssh", "ssh -oConnectTimeout=60", serverDetails.c_str(), NULL);
_exit(1);
}else{
if(timeout(c) == 1){
kill(c,SIGTERM);
waitpid(c, &exitStatus, WNOHANG);
wait(&exitStatus);
return 0;
}
wait(&exitStatus);
}
This is the timeout function.
int timeout(int childPID)
{
int times = 0, max_times = 10, status, rc;
while (times < max_times){
sleep(5);
rc = waitpid(childPID, &status, WNOHANG);
if(rc < 0){
perror("waitpid");
exit(1);
}
if(WIFEXITED(status) || WIFSIGNALED(status)){
/* child exits */
break;
}
times++;
}
if (times >= max_times){
return 1;
}
else return 0;
}
SIGTERM just asks for a polite termination of the process. If it's got stuck, then it won't respond to that, and you'll need to use SIGKILL to kill it. Probably after trying SIGTERM and waiting a little while.
The other possibility is that it's waiting for the output pipe to the parent process to not be full - maybe there's enough output to fill the buffer, and the child is waiting on that rather than the network.