int main (int argc, char *argv[])
{
- int c; /*Getopt parameter*/
+ int c; /*Getopt parameter*/
/*Default values*/
- char *avalue = IPADDRESS; /*Address: numeric value or hostname*/
- int pvalue = PORT; /*TCP port*/
- int qvalue = QUEUE; /*TCP listen queue*/
+ char *avalue = IPADDRESS; /*Address: numeric value or hostname*/
+ int pvalue = PORT; /*TCP port*/
+ int qvalue = QUEUE; /*TCP listen queue*/
/*This process is intended to be used as a daemon, it sould be launched by the INIT process, because of that*/
return 1;
}
- if (main_child(avalue, pvalue, qvalue) < 0)
+ if (main_daemon (avalue, pvalue, qvalue) < 0)
return 1;
return 0;
-int main_child (char *address, int port, int queue)
+int main_daemon (char *address, int port, int queue)
{
- struct protoent *protocol; /*Network protocol*/
+ struct protoent *protocol; /*Network protocol*/
struct sockaddr_in addr_server; /*struct with the server socket address*/
struct sockaddr_in addr_client; /*struct with the client socket address*/
- int sockclient = -1; /*File descriptor for the accepted socket*/
- pthread_t idThread; /*Thread identifier number*/
+ int sockclient = -1; /*File descriptor for the accepted socket*/
+ pthread_t idThread; /*Thread identifier number*/
socklen_t clilen;
int optval;
- int returnValue = 0; /*The return value from this function, OK by default*/
+ int returnValue = 0; /*The return value from this function, OK by default*/
/*Retrieve protocol number from /etc/protocols file */
int fd = -1; /*Temporaly store for the /dev/tty and /dev/null file descriptors*/
if ((fd = TEMP_FAILURE_RETRY(open( "/dev/tty", O_RDWR, 0))) == -1) {
- /*We already have no tty control*/
- closeSafely(fd);
- return 0;
+/*We already have no tty control*/
+closeSafely(fd);
+return 0;
}
/*Sending messages to log*/
{
int socket = -1; /*Open socket by the Java client*/
long timeout, utimeout; /*Timeout for reading data from client: secs and usecs respectively*/
- int len; /*Control parameter used while receiving data from the client*/
- char buffer[1025]; /*This buffer is intended to store the data received from the client*/
- char *command = NULL; /*The command sent by the client, to be executed by this process*/
+ int len; /*Control parameter used while receiving data from the client*/
+ char buffer[1025]; /*This buffer is intended to store the data received from the client*/
+ char *command = NULL; /*The command sent by the client, to be executed by this process*/
uint32_t *commandLength = NULL; /*Store the command length*/
socket = (int) arg;
goto err;
- /************************************************************************************************************/
- /* Just over 1 TCP connection */
- /* COMMAND_LENGTH: Java integer 4 bytes, BIG-ENDIAN (the same as network order) */
- /* COMMAND: locale character set encoding */
- /* RESULTS: locale character set encoding */
- /* */
- /* JAVA CLIENT: ------------ COMMAND_LENGTH -------> :SERVER */
- /* JAVA CLIENT: -------------- COMMAND ------------> :SERVER */
- /* JAVA CLIENT: <-------------- RESULTS ------------ :SERVER */
- /* JAVA CLIENT: <---------- CLOSE CONNECTION ------- :SERVER */
- /* */
- /************************************************************************************************************/
+ /****************************************************************************************/
+ /* Just over 1 TCP connection */
+ /* COMMAND_LENGTH: Java integer 4 bytes, BIG-ENDIAN (the same as network order) */
+ /* COMMAND: locale character set encoding */
+ /* RESULTS: locale character set encoding */
+ /* */
+ /* JAVA CLIENT: ------------ COMMAND_LENGTH -------> :SERVER */
+ /* JAVA CLIENT: -------------- COMMAND ------------> :SERVER */
+ /* JAVA CLIENT: <-------------- RESULTS ------------ :SERVER */
+ /* JAVA CLIENT: <---------- CLOSE CONNECTION ------- :SERVER */
+ /* */
+ /****************************************************************************************/
/*Wait max 2 seconds for data coming from client, otherwise exits with error.*/
timeout = 2;
utimeout = 0;
+ /*1. COMMAND LENGTH*/
+ /*First of all we receive the command size as a Java integer (4 bytes primitive type)*/
+ if ((commandLength = (uint32_t *) malloc(sizeof(uint32_t))) == NULL) {
+ syslog (LOG_ERR, "commandLength malloc failed: %m");
+ goto err;
+ }
- /*1. COMMAND LENGTH*/
- /*First of all we receive the command size as a Java integer (4 bytes primitive type)*/
- if ((commandLength = (uint32_t *) malloc(sizeof(uint32_t))) == NULL) {
- syslog (LOG_ERR, "commandLength malloc failed: %m");
- goto err;
- }
-
- bzero(buffer, sizeof(buffer));
- len = sizeof(uint32_t);
+ bzero(buffer, sizeof(buffer));
+ len = sizeof(uint32_t);
if (receive_from_socket (socket, buffer, len, timeout, utimeout) < 0)
goto err;
- /*Retrieve integer (4 bytes) from buffer*/
- memcpy (commandLength, buffer, sizeof(uint32_t));
- /*Java sends the primitive integer using big-endian order (it is the same as network order)*/
- *commandLength = be32toh (*commandLength);
-
+ /*Retrieve integer (4 bytes) from buffer*/
+ memcpy (commandLength, buffer, sizeof(uint32_t));
+ /*Java sends the primitive integer using big-endian order (it is the same as network order)*/
+ *commandLength = be32toh (*commandLength);
-
- /*2. COMMAND*/
- /*Reserving commandLength + 1 because of the string end character*/
- if ((command = (char *) malloc(*commandLength + 1)) == NULL) {
- syslog (LOG_ERR, "command malloc failed: %m");
- goto err;
- }
+ /*2. COMMAND*/
+ /*Reserving commandLength + 1 because of the string end character*/
+ if ((command = (char *) malloc(*commandLength + 1)) == NULL) {
+ syslog (LOG_ERR, "command malloc failed: %m");
+ goto err;
+ }
- bzero(command, ((*commandLength) + 1));
+ bzero(command, ((*commandLength) + 1));
len = *commandLength;
- /*Wait max 2 seconds for data coming from client, otherwise exits with error.*/
- if (receive_from_socket (socket, command, len, timeout, utimeout) < 0)
+ /*Wait max 2 seconds for data coming from client, otherwise exits with error.*/
+ if (receive_from_socket (socket, command, len, timeout, utimeout) < 0)
goto err;
-
- /*3. RESULTS*/
- pre_fork_system(socket, command);
-
+ /*3. RESULTS*/
+ pre_fork_system(socket, command);
-
- /*4. CLOSE CONNECTION AND FINISH*/
+ /*4. CLOSE CONNECTION AND FINISH*/
err:
- free(command);
+ free(command);
closeSafely(socket);
- free(commandLength);
+ free(commandLength);
- pthread_exit(0);
+ pthread_exit(0);
}
int receive_from_socket (int socket, char *data, int len, long timeout, long utimeout)
{
int nData, iPos; /*Control variables.*/
- int ret; /*Store return value from select.*/
+ int ret; /*Store return value from select.*/
- nData = iPos = 0;
- do {
+ nData = iPos = 0;
+ do {
ret = readable_timeout(socket, timeout, utimeout);
if (ret == 0) {
return -1;
}
- len -= nData;
- iPos += nData;
+ len -= nData;
+ iPos += nData;
} while (len > 0);
return 0;
int pre_fork_system(int socket, char *command)
{
- /*Required variables in order to share memory between processes*/
- key_t keyvalue;
- int idreturnstatus = -1;
- /*Store the return status from the process launched using system or execve*/
- /*Using shared memory between the child and parent process*/
- int *returnstatus = NULL;
-
- /*Required variables in order to share the semaphore between processes*/
- key_t keysemaphore;
- int idsemaphore = -1;
- sem_t *semaphore = NULL; /*Used as a barrier: the child process just can start after sending the XML init code*/
-
- int returnValue = -1; /*Return value from this function can be caught by upper layers, NOK by default*/
+ /*Required variables in order to share memory between processes*/
+ key_t keyvalue;
+ int idreturnstatus = -1;
+ /*Store the return status from the process launched using system or execve*/
+ /*Using shared memory between the child and parent process*/
+ int *returnstatus = NULL;
+
+ /*Required variables in order to share the semaphore between processes*/
+ key_t keysemaphore;
+ int idsemaphore = -1;
+ sem_t *semaphore = NULL; /*Used as a barrier: the child process just can start after sending the XML init code*/
+
+ int returnValue = -1; /*Return value from this function can be caught by upper layers, NOK by default*/
- /*Allocate shared memory because we can not use named semaphores*/
- /*We are using this semaphore as a barrier, because we just want to start the child process when the parent process has sent*/
- /*the XML header (see: for_system function)*/
+ /*Allocate shared memory because we can not use named semaphores*/
+ /*We are using this semaphore as a barrier, because we just want to start the child process when the parent process has sent*/
+ /*the XML header (see: for_system function)*/
keysemaphore=ftok("/bin/ls", SHAREMEMSEM); /*the /bin/ls must exist otherwise this does not work... */
if (keysemaphore == -1) {
- /*Allocate shared memory for the return status code from the process which is going to be launched by the system function.*/
- /*We want to share the returnstatus variable between this process and the child that is going to be created in the fork_system method.*/
- /*The goal is to store in this variable the return status code received from the process launched with the system method by the child process,*/
- /*then the parent process can retrieve that return status code and send it by TCP to the Java client.*/
- /*There are not concurrency issues because the parent process will just try to read this variable when the child process is dead, taking*/
- /*in that moment its last value and sending it to the Java client.*/
+ /*Allocate shared memory for the return status code from the process which is going to be launched by the system function.*/
+ /*We want to share the returnstatus variable between this process and the child that is going to be created in the fork_system method.*/
+ /*The goal is to store in this variable the return status code received from the process launched with the system method by the child process,*/
+ /*then the parent process can retrieve that return status code and send it by TCP to the Java client.*/
+ /*There are not concurrency issues because the parent process will just try to read this variable when the child process is dead, taking*/
+ /*in that moment its last value and sending it to the Java client.*/
keyvalue=ftok("/bin/ls", SHAREMEMKEY); /*the /bin/ls must exist otherwise this does not work... */
goto end_release_mem;
}
+ /*After allocating and attaching shared memory we reach this code if everything went OK.*/
- /*After allocating and attaching shared memory we reach this code if everything went OK.*/
-
- returnValue = fork_system(socket, command, semaphore, returnstatus);
+ returnValue = fork_system(socket, command, semaphore, returnstatus);
end_release_mem:
-int fork_system(int socket, char *command, sem_t *semaphore, int *returnstatus) {
- int pid;
- int out[2], err[2]; /*Store pipes file descriptors. Write ends attached to the stdout and stderr streams.*/
- char buf[2000]; /*Read data buffer.*/
- char string[100];
- /*We are going to use a poll in order to find out if there are data coming from the*/
- /*pipes attached to the stdout and stderr streams.*/
- struct pollfd polls[2];
- int n;
- int childreturnstatus;
- int returnValue = 0; /*eturn value from this function can be caught by upper layers, OK by default*/
-
-
- /*Value by default*/
+int fork_system(int socket, char *command, sem_t *semaphore, int *returnstatus)
+{
+ int pid;
+ int out[2], err[2]; /*Store pipes file descriptors. Write ends attached to the stdout and stderr streams.*/
+ char buf[2000]; /*Read data buffer.*/
+ char string[100];
+ /*We are going to use a poll in order to find out if there are data coming from the*/
+ /*pipes attached to the stdout and stderr streams.*/
+ struct pollfd polls[2];
+ int n;
+ int childreturnstatus;
+ int returnValue = 0; /*return value from this function can be caught by upper layers, OK by default*/
+
+
+ /*Value by default*/
(*returnstatus) = 0;
- out[0] = out[1] = err[0] = err[1] = -1;
+ out[0] = out[1] = err[0] = err[1] = -1;
- /*Creating the pipes, they will be attached to the stderr and stdout streams*/
- if (pipe(out) < 0 || pipe(err) < 0) {
- syslog (LOG_ERR, "pipe failed: %m");
- goto err;
+ /*Creating the pipes, they will be attached to the stderr and stdout streams*/
+ if (pipe(out) < 0 || pipe(err) < 0) {
+ syslog (LOG_ERR, "pipe failed: %m");
+ goto err;
}
-
-
- if ((pid=fork()) == -1) {
- syslog (LOG_ERR, "fork failed: %m");
- goto err;
- }
-
- if (pid == 0) {
- /*Child process*/
- /*It has to launch another one using system or execve*/
- if ((TEMP_FAILURE_RETRY(dup2(out[1],1)) < 0) || (TEMP_FAILURE_RETRY(dup2(err[1],2)) < 0)) {
- syslog (LOG_ERR, "child dup2 failed: %m");
+
+ if ((pid=fork()) == -1) {
+ syslog (LOG_ERR, "fork failed: %m");
+ goto err;
+ }
+
+ if (pid == 0) {
+ /*Child process*/
+ /*It has to launch another one using system or execve*/
+ if ((TEMP_FAILURE_RETRY(dup2(out[1],1)) < 0) || (TEMP_FAILURE_RETRY(dup2(err[1],2)) < 0)) {
+ syslog (LOG_ERR, "child dup2 failed: %m");
/*Going to zombie state, hopefully waitpid will catch it*/
- exit(-1);
- }
- if (TEMP_FAILURE_RETRY(sem_wait(semaphore)) < 0) {
- syslog (LOG_ERR, "child semaphore wait failed: %m");
+ exit(-1);
+ }
+
+ if (TEMP_FAILURE_RETRY(sem_wait(semaphore)) < 0) {
+ syslog (LOG_ERR, "child semaphore wait failed: %m");
/*Going to zombie state, hopefully waitpid will catch it*/
- exit(-1);
- }
-
- *returnstatus=system(command);
-
- if (WIFEXITED(returnstatus) == 1)
- (*returnstatus) = WEXITSTATUS(*returnstatus);
- else
- (*returnstatus) = -1;
- exit(0);
- }
- else {
- /*Parent process*/
- /*It sends data to the Java client using a TCP connection.*/
- polls[0].fd=out[0];
- polls[1].fd=err[0];
- polls[0].events=POLLIN;
- polls[1].events=POLLIN;
- sprintf(string,"<?xml version=\"1.0\"?>");
- send(socket,string,strlen(string),0);
- sprintf(string,"<streams>");
- send(socket,string,strlen(string),0);
-
- /*Releasing barrier, the child process can keep running*/
- if (sem_post(semaphore) < 0 ) {
- syslog (LOG_ERR, "parent error releasing barrier: %m");
- /*TODO: May I kill a child process if it is already dead? I mean,*/
- /* what could happen if the child process is dead?*/
- /* Should I implement a SIGCHILD handler?*/
- /*TODO: Should I have a SIGTERM handler in the child process?*/
- kill(pid, SIGTERM);
- goto err;
- }
+ exit(-1);
+ }
- while(1) {
- if(poll(polls,2,100)) {
- if(polls[0].revents&&POLLIN) {
- bzero(buf,2000);
- n=read(out[0],buf,1990);
- sprintf(string,"<out><![CDATA[");
- send(socket,string,strlen(string),0);
- send(socket,buf,n,0);
- sprintf(string,"]]></out>");
- send(socket,string,strlen(string),0);
- }
- if(polls[1].revents&&POLLIN) {
- bzero(buf,2000);
- n=read(err[0],buf,1990);
- sprintf(string,"<error><![CDATA[");
- send(socket,string,strlen(string),0);
- send(socket,buf,n,0);
- sprintf(string,"]]></error>");
- send(socket,string,strlen(string),0);
- }
- if(!polls[0].revents&&POLLIN && !polls[1].revents&&POLLIN) {
- syslog (LOG_ERR, "parent error polling pipes: %m");
- /*TODO: May I kill a child process if it is already dead? I mean,*/
- /* what could happen if the child process is dead?*/
- /* Should I implement a SIGCHILD handler?*/
- /*TODO: Should I have a SIGTERM handler in the child process?*/
- kill(pid, SIGTERM);
- /*I want to send an error status to the remote calling process*/
- /*TODO: Before giving this value I should make sure the child process is dead*/
- /* otherwise I could finish having in *returnstatus the value from the child process*/
- (*returnstatus) = -1;
- break;
- }
- }
- else {
- /*When timeout*/
- if(waitpid(pid, &childreturnstatus, WNOHANG)) {
- /*Child is dead, we can finish the connection*/
- /*First of all, we check the exit status of our child process*/
- /*In case of error send an error status to the remote calling process*/
- if (WIFEXITED(childreturnstatus) != 1)
- (*returnstatus) = -1;
- break;
- }
- /*The child process is not dead, keep polling more data from stdout or stderr streams*/
- }
- }
+ *returnstatus=system(command);
+ if (WIFEXITED(returnstatus) == 1)
+ (*returnstatus) = WEXITSTATUS(*returnstatus);
+ else
+ (*returnstatus) = -1;
+ /*Going to zombie state, hopefully waitpid will catch it*/
+ exit(0);
+ }
+ else {
+ /*Parent process*/
+ /*It sends data to the Java client using a TCP connection.*/
+ polls[0].fd=out[0];
+ polls[1].fd=err[0];
+ polls[0].events=POLLIN;
+ polls[1].events=POLLIN;
+ sprintf(string,"<?xml version=\"1.0\"?>");
+ send(socket,string,strlen(string),0);
+ sprintf(string,"<streams>");
+ send(socket,string,strlen(string),0);
+
+ /*Releasing barrier, the child process can keep running*/
+ if (sem_post(semaphore) < 0 ) {
+ syslog (LOG_ERR, "parent error releasing barrier: %m");
+ /*TODO: May I kill a child process if it is already dead? I mean, */
+ /* what could happen if the child process is dead? */
+ /* Should I implement a SIGCHILD handler? */
+ /*TODO: Should I have a SIGTERM handler in the child process? */
+ kill(pid, SIGTERM);
+ goto err;
+ }
- }
- /*Reaching this code when child finished or if error while polling pipes*/
- sprintf(string,"<ret><![CDATA[%d]]></ret>", (*returnstatus));
- send(socket,string,strlen(string),0);
- sprintf(string,"</streams>");
- send(socket,string,strlen(string),0);
+ while(1) {
+ if(poll(polls,2,100)) {
+ if(polls[0].revents&&POLLIN) {
+ bzero(buf,2000);
+ n=read(out[0],buf,1990);
+ sprintf(string,"<out><![CDATA[");
+ send(socket,string,strlen(string),0);
+ send(socket,buf,n,0);
+ sprintf(string,"]]></out>");
+ send(socket,string,strlen(string),0);
+ }
+
+ if(polls[1].revents&&POLLIN) {
+ bzero(buf,2000);
+ n=read(err[0],buf,1990);
+ sprintf(string,"<error><![CDATA[");
+ send(socket,string,strlen(string),0);
+ send(socket,buf,n,0);
+ sprintf(string,"]]></error>");
+ send(socket,string,strlen(string),0);
+ }
+
+ if(!polls[0].revents&&POLLIN && !polls[1].revents&&POLLIN) {
+ syslog (LOG_ERR, "parent error polling pipes: %m");
+ /*TODO: May I kill a child process if it is already dead? I mean, */
+ /* what could happen if the child process is dead? */
+ /* Should I implement a SIGCHILD handler? */
+ /*TODO: Should I have a SIGTERM handler in the child process? */
+ kill(pid, SIGTERM);
+ /*I want to send an error status to the remote calling process */
+ /*TODO: Before giving this value I should make sure the child process is dead */
+ /* otherwise I could finish having in *returnstatus the value from the child process */
+ (*returnstatus) = -1;
+ break;
+ }
+ }
+ else {
+ /*When timeout*/
+ if(waitpid(pid, &childreturnstatus, WNOHANG)) {
+ /*Child is dead, we can finish the connection*/
+ /*First of all, we check the exit status of our child process*/
+ /*In case of error send an error status to the remote calling process*/
+ if (WIFEXITED(childreturnstatus) != 1)
+ (*returnstatus) = -1;
+ break;
+ }
+ /*The child process is not dead, keep polling more data from stdout or stderr streams*/
+ }
+ }
+ }
+ /*Reaching this code when child finished or if error while polling pipes*/
+ sprintf(string,"<ret><![CDATA[%d]]></ret>", (*returnstatus));
+ send(socket,string,strlen(string),0);
+ sprintf(string,"</streams>");
+ send(socket,string,strlen(string),0);
- /*Stuff just done by the Parent process. The child process ends with exit*/
-
+ /*Stuff just done by the Parent process. The child process ends with exit*/
end:
closeSafely (out[0]);
closeSafely (out[1]);
closeSafely (err[0]);
closeSafely (err[1]);
+ return returnValue;
err:
returnValue = -1;
goto end;