Perl process crashes after handling signal - perl

I'm trying to make rereading config file for simple perl daemon on SIGHUP.
I'm trying
use sigtrap qw/handler rereadconf HUP/;
but after executing "rereadconf" procedure process stops
i'm also trying
%SIG{HUP} = \&rereadconf;
sub rereadconf{
.... mycode
print "procedure executed\n";
};
but result was the same, after executing procedure program stops.
So how can i make that process continue execution after signal handling?

Your program exits because the accept returns false because it got interrupted by a signal. You want
while (1) {
my $client = $srv->accept();
if (!$client) {
next if $!{EINTR};
die(sprintf(STDERR "[%s] accept: %s\n", basename($0), $!));
}
print(STDERR "accepted new client\n");
serve_client($client);
}

Related

An error in my code to be a simple ftp

I met an error when running codes at the bottom. It's like a simple ftp.
I use python2.6.6 and CentOS release 6.8
In most linux server, it gets right results like this:(I'm very sorry that I have just sign up and couldn't )
Clinet:
[root#Test ftp]# python client.py
path:put|/home/aaa.txt
Server:
[root#Test ftp]# python server.py
connected...
pre_data:put|aaa.txt|4
cmd: put
file_name: aaa.txt
file_size: 4
upload successed.
But I get errors in some server(such as my own VM in my PC). I have done lots of tests(python2.6/python2.7, Centos6.5/Centos6.7) and found this error is not because them. Here is the error imformation:
[root#Lewis-VM ftp]# python server.py
connected...
pre_data:put|aaa.txt|7sdfsdf ###Here gets the wrong result, "sdfsdf" is the content of /home/aaa.txt and it shouldn't be sent here to 'file_size' and so it cause the "ValueError" below
cmd: put
file_name: aaa.txt
file_size: 7sdfsdf
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 10699)
Traceback (most recent call last):
File "/usr/lib64/python2.6/SocketServer.py", line 570, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib64/python2.6/SocketServer.py", line 332, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib64/python2.6/SocketServer.py", line 627, in __init__
self.handle()
File "server.py", line 30, in handle
if int(file_size)>recv_size:
ValueError: invalid literal for int() with base 10: '7sdfsdf\n'
What's more, I found that if I insert a time.sleep(1) between sk.send(cmd+"|"+file_name+'|'+str(file_size)) and sk.send(data) in client.py, the error will disappear. I have said that I did tests in different system and python versions and the error is not because them. So I guess that is it because of some system configs? I have check about socket.send() and socket.recv() in python.org but fount nothing helpful. So could somebody help me to explain why this happend?
The code are here:
#!/usr/bin/env python
#coding:utf-8
################
#This is server#
################
import SocketServer
import os
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
base_path = '/home/ftp/file'
conn = self.request
print 'connected...'
while True:
#####receive pre_data: we should get data like 'put|/home/aaa|7'
pre_data = conn.recv(1024)
print 'pre_data:' + pre_data
cmd,file_name,file_size = pre_data.split('|')
print 'cmd: ' + cmd
print 'file_name: '+ file_name
print 'file_size: '+ file_size
recv_size = 0
file_dir = os.path.join(base_path,file_name)
f = file(file_dir,'wb')
Flag = True
####receive 1024bytes each time
while Flag:
if int(file_size)>recv_size:
data = conn.recv(1024)
recv_size+=len(data)
else:
recv_size = 0
Flag = False
continue
f.write(data)
print 'upload successed.'
f.close()
instance = SocketServer.ThreadingTCPServer(('127.0.0.1',9999),MyServer)
instance.serve_forever()
#!/usr/bin/env python
#coding:utf-8
################
#This is client#
################
import socket
import sys
import os
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)
while True:
input = raw_input('path:')
#####we should input like 'put|/home/aaa.txt'
cmd,path = input.split('|')
file_name = os.path.basename(path)
file_size=os.stat(path).st_size
sk.send(cmd+"|"+file_name+'|'+str(file_size))
send_size = 0
f= file(path,'rb')
Flag = True
#####read 1024 bytes and send it to server each time
while Flag:
if send_size + 1024 >file_size:
data = f.read(file_size-send_size)
Flag = False
else:
data = f.read(1024)
send_size+=1024
sk.send(data)
f.close()
sk.close()
The TCP is a stream of data. That is the problem. TCP do not need to keep message boundaries. So when a client calls something like
connection.send("0123456789")
connection.send("ABCDEFGHIJ")
then a naive server like
while True;
data = conn.recv(1024)
print data + "_"
may print any of:
0123456789_ABCDEFGHIJ_
0123456789ABCDEFGHIJ_
0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_G_H_I_J_
The server has no chance to recognize how many sends client called because the TCP stack at client side just inserted data to a stream and the server must be able to process the data received in different number of buffers than the client used.
Your server must contain a logic to separate the header and the data. All of application protocols based on TCP use a mechanism to identify application level boundaries. For example HTTP separates headers and body by an empty line and it informs about the body length in a separate header.
Your program works correctly when server receives a header with the command, name and size in a separate buffer it it fails when client is fast enough and push the data into stream quickly and the server reads header and data in one chunk.

Celery task subprocess stdout to log

I have a celery task which calls other python script external to Django application with subprocess. This program have some print's in it, and I want to have these print's in my celery log file or in my database. When I set CELERY_ALWAYS_EAGER = True in Django settings.py file, everything works fine. If I don't set this setting, celery task log subprocess stdout only when it exit. It seems like p.stdout.readline() is blocking.
run-test.py is a long process, couple of minutes, but it print what it's doing. I want to capture this.
#shared_task
def run_tests(scenario_path, vu):
basedir = os.path.abspath(os.path.dirname(__file__))
config_path = '%s/../../scripts/config.ini' % basedir
cmd = ['python', '%s/../../scripts/aws/run-test.py' % basedir, '%s' % config_path, scenario_path, str(vu), str(2)]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
while True:
line = p.stdout.readline()
if line != '':
logger.info(line)
else:
return
I found this to be very useful, using select for polling instead of blocking on readline.
https://gist.github.com/bgreenlee/1402841
child = subprocess.Popen(popenargs, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, **kwargs)
log_level = {child.stdout: stdout_log_level,
child.stderr: stderr_log_level}
def check_io():
ready_to_read = select.select([child.stdout, child.stderr], [], [], 1000)[0]
for io in ready_to_read:
line = io.readline()
logger.log(log_level[io], line[:-1])
# keep checking stdout/stderr until the child exits
while child.poll() is None:
check_io()
check_io() # check again to catch anything after the process exits

read / write on socket descriptors linux c

I am trying to send the contents of a file from the server to the client , I am reading the file line by line using fgets and writing to the socket descriptor line by line , on the client side , i am in an a while loop , reading the sent contents.I am not being able to terminate the server sending sequence , i.e the client keeps reading the buffer and the next program line is not executed , I think thers something wrong with my way of sending or recieving . here is the code :
server :
filefd = fopen("clients.txt","a+");
while(fgets(filcont,300,filefd) != NULL)
{// write whole file contents to client
n=write(newsockfd,filcont,strlen(filcont));
if(n==0) break;
memset(filcont,'\0',300);
}
fclose(filefd);
client side :
while(n>0){
n = read(sockfd,buffer,sizeof(buffer)-1);
if(n==0) break;
printf("%s\nbytes read :%d \n",buffer,n);
memset(buffer,'\0',256);
}
printf("Enter peer name ( except yours ) to send connection request : \n");
the above line ( printf , peer name doesnot get executed until i terminate the server)
I was able to figure it out , I sent the file contents from the server using fread instead of fgets ( line by line ) and used a single read() at the client . this was the quick fix.
But I also figured out another technique when in case you have to compulsorily use fgets , where the while loop at the client side makes the socket nonblocking for read and then blocking again , the code is pasted below.
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
while(n>0){
n = read(sockfd,buffer,sizeof(buffer)-1);
if(n==0) break;
if(n==-1) printf("\nNon blocking read failed congrats");
printf("%s\n",buffer);
memset(buffer,'\0',256);
}
printf("\nbytes read :%d \n",n);
val = fcntl(sockfd, F_GETFL, 0);
flags = O_NONBLOCK;
val &= ~flags; // makes it blocking again
fcntl(sockfd,F_SETFL,val);
The code from stackoverflow was refered to make the socket blocking

how to receive a vlc flow in a socket?

I'm developping a streaming application with tcl.
I have a vlc sever that broadcast a flow in http mode. what I'm trying to do is to develop a client who will try to connect to server with a particular ip adress and port number, and then try to save the flow in a file.
the code that i'm using is simple:
set server localhost
set sockChan [socket $server 1234]
set line [read $sockChan 1000]
puts " vidéo: $line"
close $sockChan
the problem when i try to test my script, I see that I realise the connection, but I can't read the flow!
the 'puts' doesn't show anything in the console...
Have you any ideas!
thank you..
If you're just wanting to save the contents of a URL to a file, the standard http package has a -channel option which lets you dump directly. For example:
package require http
set f [open video.dump w]
fconfigure $f -translation binary
set tok [http::geturl "http://server:port/url" -channel $f]
close $f
if {[http::ncode $tok] != 200} {
# failed somehow...
} else {
# succeeded
}
http::cleanup $tok
Edit: Doing it asynchronously (requires the event loop going, e.g. via vwait forever):
package require http
set f [open video.dump w]
fconfigure $f -translation binary
proc done {f tok} {
close $f
if {[http::ncode $tok] != 200} {
# failed somehow...
} else {
# succeeded
}
http::cleanup $tok
}
http::geturl "http://server:port/url" -channel $f -command "done $f"
# Your code runs here straight away...
Note that the code's recognizably similar, but now in a slightly different order! If you've got Tcl 8.5 — if not, why not? — then you can use a lambda application instead to make the apparent order of the code even more similar:
package require http
set f [open video.dump w]
fconfigure $f -translation binary
http::geturl "http://server:port/url" -channel $f -command [list apply {{f tok} {
close $f
if {[http::ncode $tok] != 200} {
# failed somehow...
} else {
# succeeded
}
http::cleanup $tok
}} $f]
# Your code runs here straight away...
Since you are working with HTTP, I would suggest looking at libcurl bindings for TCL.

stream_socket_server: Client browser randomly aborting?

Below is partial code to an experimental http server app I'm building from scratch from a PHP CLI script (Why? Because I have too much time on my hands). The example below more closely matches PHP's manual page on this function. The problem I'm getting is when connecting to this server app via a browser (Firefox or IE8 from two separate systems tested so far), the browser sends an empty request payload to the server and aborts roughly every 1 in 6 page loads.
The server console displays the "Connected with [client info]" each time. However, about 1 in 6 connections will result in a "Client request is empty" error. No error is given telling the header/body response write to the socket failed. The browser will generally continue to read what I give it, but this isn't usable as I can't fulfill the client's intended request without knowing what it is.
<?php
$s_socket_uri = 'tcp://localhost:80';
// establish the server on the above socket
$s_socket = stream_socket_server($s_socket_uri, $errno, $errstr, 30) OR
trigger_error("Failed to create socket: $s_socket_uri, Err($errno) $errstr", E_USER_ERROR);
$s_name = stream_socket_get_name($s_socket, false) OR
trigger_error("Server established, yet has no name. Fail!", E_USER_ERROR);
if (!$s_socket || !$s_name) {return false;}
/*
Wait for connections, handle one client request at a time
Though to not clog up the tubes, maybe a process fork is
needed to handle each connection?
*/
while($conn = stream_socket_accept($s_socket, 60, $peer)) {
stream_set_blocking($conn, 0);
// Get the client's request headers, and all POSTed values if any
echo "Connected with $peer. Request info...\n";
$client_request = stream_get_contents($conn);
if (!$client_request) {
trigger_error("Client request is empty!");
}
echo $client_request."\n\n"; // just for debugging
/*
<Insert request handling and logging code here>
*/
// Build headers to send to client
$send_headers = "HTTP/1.0 200 OK\n"
."Server: mine\n"
."Content-Type: text/html\n"
."\n";
// Build the page for client view
$send_body = "<h1>hello world</h1>";
// Make sure the communication is still active
if ((int) fwrite($conn, $send_headers . $send_body) < 1) {
trigger_error("Write to socket failed!");
}
// Response headers and body sent, time to end this connection
stream_socket_shutdown($conn, STREAM_SHUT_WR);
}
?>
Any solution to bring down the number of unintended aborts down to 0, or any method to get more stable communication going? Is this solvable on my server's end, or just typical browser behavior?
I tested your code and it seems I got better results reading the socket with fread(). You also forgot the main loop(while(1), while(true) or for(;;).
Modifications to your code:
stream_socket_accept with #stream_socket_accept [sometimes you get warnings because "the connected party did not properly respond", which is, of course, the timeout of stream_socket_accept()]
Added the big while(1) { } loop
Changed the reading from the socket from $client_request = stream_get_contents($conn);
to while( !preg_match('/\r?\n\r?\n/', $client_request) ) { $client_request .= fread($conn, 1024); }
Check the source code below (I used 8080 port because I already had an Apache listening on 80):
<?php
$s_socket_uri = 'tcp://localhost:8080';
$s_socket = stream_socket_server($s_socket_uri, $errno, $errstr, 30) OR
trigger_error("Failed to create socket: $s_socket_uri, Err($errno) $errstr", E_USER_ERROR);
$s_name = stream_socket_get_name($s_socket, false) OR
trigger_error("Server established, yet has no name. Fail!", E_USER_ERROR);
if (!$s_socket || !$s_name) {return false;}
while(1)
{
while($conn = #stream_socket_accept($s_socket, 60, $peer))
{
stream_set_blocking($conn, 0);
echo "Connected with $peer. Request info...\n";
// $client_request = stream_get_contents($conn);
$client_request = "";
// Read until double \r
while( !preg_match('/\r?\n\r?\n/', $client_request) )
{
$client_request .= fread($conn, 1024);
}
if (!$client_request)
{
trigger_error("Client request is empty!");
}
echo $client_request."\n\n";
$headers = "HTTP/1.0 200 OK\n"
."Server: mine\n"
."Content-Type: text/html\n"
."\n";
$body = "<h1>hello world</h1><br><br>".$client_request;
if ((int) fwrite($conn, $headers . $body) < 1) {
trigger_error("Write to socket failed!");
}
stream_socket_shutdown($conn, STREAM_SHUT_WR);
}
}
Add sleep(1) after stream_set_blocking