Limite de string enviado por un socket.

Iniciado por pacosn1111, 8 Noviembre 2016, 13:13 PM

0 Miembros y 1 Visitante están viendo este tema.

pacosn1111

Buenas, hace unos meses estaba viendo como redireccionar el stdout a otro socket y gracias al usuario "Arkangel_0x7C5" que respondió lo conseguí, pero ahora tengo otra duda, el código del servidor es:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include "ss.h"

#define buf_max 1000

int func_server();
char buf[buf_max];
int limit;

void main() {

if(getuid()!=0) exit(0);

system("iptables -A INPUT -p tcp --dport 3551 -j ACCEPT");
while(1) func_server();
}
int func_server() {
server(3551);

while(fd_client) {
limit=recv(fd_client,buf,buf_max,0);
if(buf[0]=='\0') break;
strcat(buf, "&");
buf[limit]='\0';
if((strcmp(buf, "exit"))==0) break;

if(fork()==0){
dup2(fd_client, STDOUT_FILENO);
dup2(fd_client, STDERR_FILENO);
system(buf);}
}
close(fd_client);
close(fd_server);
return 0;
}


y del cliente:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include "ss.h"

#define buf_max 1000
char array[999999];
int limit;

void main(int argc, char *argv[]) {
if(argc!=3) printf("USE: client address port\n");
char buf[buf_max];
if((client(argv[1], atoi(argv[2])))==1) {printf("Falló la conexión con el server\n"); exit(1);}
else printf("Conectado al server %s %d\n PRECAUCIÓN,!No ejecutar ningún comando remoto que requiera intervención!\n", argv[1], atoi(argv[2]));

while(fd) {

if(fork()==0) {while(fd) {memset(array,'\0',strlen(array)); recv(fd,array,999999,0); printf("%s", array);}}

fgets(buf, buf_max, stdin);
if(buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]='\0';
send(fd, buf, buf_max, 0);
if((strcmp(buf, "exit"))==0) {close(fd); exit(0);}
}
}



El problema es que el array donde se almacena en el cliente el stdout tiene un tope, fijo, y algunas veces aunque sea muy grande hace falta más ¿Cómo puedo hacer que se adapte al stdout que devuelve el servidor?

Gracias.

ivancea96

Si el problema es guardar uan cadena de tamaño variable, tendrás que hacerlo con memoria dinámica. malloc.
Necesitarás recibir primero la longitud de la cadena. En caso de que esto no sea posible, vas guardando el contenido, y cuando veas que necesitas más espacio, creas una nueva cadena, copias en ella los datos y sigues escribiendo ahí.

pacosn1111

Cita de: ivancea96 en  8 Noviembre 2016, 16:53 PM
Si el problema es guardar uan cadena de tamaño variable, tendrás que hacerlo con memoria dinámica. malloc.
Necesitarás recibir primero la longitud de la cadena. En caso de que esto no sea posible, vas guardando el contenido, y cuando veas que necesitas más espacio, creas una nueva cadena, copias en ella los datos y sigues escribiendo ahí.

Antes de nada gracias por responder.

Lo he intentado y estoy dándole vueltas pero sigo sin conseguirlo, lo que tengo hasta ahora es esto:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>  
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include "ss.h"

#define buf_max 1000
char * array;
int limit, limit2;

void main(int argc, char *argv[]) {
if(argc!=3) printf("USE: client address port\n");
char buf[buf_max];
if((client(argv[1], atoi(argv[2])))==1) {printf("Falló la conexión con el server\n"); exit(1);}
else printf("Conectado al server %s %d\n PRECAUCIÓN,!No ejecutar ningún comando remoto que requiera intervención!\n", argv[1], atoi(argv[2]));

while(fd) {

if(fork()==0) {

while(fd) {
array=(char *) malloc(sizeof(char));
memset(array,'\0',strlen(array));
while((limit2=recv(fd,array,sizeof(char),0))<0) {array=(char *)realloc(array,sizeof(char));}
limit=strlen(array-1);
array[limit]='\0';
printf("%s", array);
free(array);
}
   
}

fgets(buf, buf_max, stdin);
if(buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]='\0';
send(fd, buf, buf_max, 0);
if((strcmp(buf, "exit"))==0) {close(fd); exit(0);}
}
}


Lo que hago en resumen es:

Creo un puntero tipo Char. Después, como no tengo forma de saber que me va a devolver el recv, voy obteniendo del recv de caracter a caracter con "sizeof(char)" y cada vez voy asignandole al array un char más meto dato, reservo otro char y así... y en cada ciclo hago un free.

No se ejecuta el comando en el servidor y tampoco imprime nada en el lado del cliente. ¿Alguna sugerencia?

ivancea96

En primer lugar, no puedes hacer strlen d eun array que no has inicializado. El valor que te retorne es "aleatorio"
Código (cpp) [Seleccionar]
memset(array,'\0',strlen(array));

No sé qué hace el servidor. De todos modos te diré, que es preferible que empieces de 0, parte a parte, tratandod e hacer algo más básico.
¿Sabrías enviar y recibir una cadena de un tamaño fijo?
Si es así, entonces practica el manejo de memoria dinámica. (Bueno, en cualquier caso, deberías hacer esto último)
array=(char *) malloc(sizeof(char));
/* while */ realloc(array,sizeof(char));
free(array);

Ahí no estás haciendo nada. Estás con un punteor que apunta siempre a 1 char.

pacosn1111

Cita de: ivancea96 en 14 Noviembre 2016, 20:49 PM
En primer lugar, no puedes hacer strlen d eun array que no has inicializado. El valor que te retorne es "aleatorio"
Código (cpp) [Seleccionar]
memset(array,'\0',strlen(array));

No sé qué hace el servidor. De todos modos te diré, que es preferible que empieces de 0, parte a parte, tratandod e hacer algo más básico.
¿Sabrías enviar y recibir una cadena de un tamaño fijo?
Si es así, entonces practica el manejo de memoria dinámica. (Bueno, en cualquier caso, deberías hacer esto último)
array=(char *) malloc(sizeof(char));
/* while */ realloc(array,sizeof(char));
free(array);

Ahí no estás haciendo nada. Estás con un punteor que apunta siempre a 1 char.

Gracias por responder pero sigo hecho un lio, ahora se me ha ocurrido en vez de usar punteros, ir recibiendo de 100 en 100, y esa parte funciona, pero lo que estoy intentando hacer es una shell remota que reciba comandos, los ejecute y envie al cliente la salida de dicho comando, por eso necesito fork() para crear un proceso hijo.

Pero me estoy haciendo un lio del copón con el tema de fork(), he mirado ya bastante documentación y he probado de todo pero sigo sin enterarme.

Ahora mismo lo que tengo de momento es esto:

Cliente:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include "ss.h"
#include <signal.h>

#define buf_max 1000
char * array;
int limit, limit2;
pid_t id;
void main(int argc, char *argv[]) {
if(argc!=3) printf("USE: client address port\n");
char buf[buf_max];
if((client(argv[1], atoi(argv[2])))==1) {printf("Falló la conexión con el server\n"); exit(1);}
else printf("Conectado al server %s %d\n PRECAUCIÓN,!No ejecutar ningún comando remoto que requiera intervención!\n", argv[1], atoi(argv[2]));
char buffer[100];
id=fork();

while(fd) {
if(id>0) {

fgets(buf, buf_max, stdin);
if(buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]='\0';
send(fd, buf, buf_max, 0);
if((strcmp(buf, "exit"))==0) {close(fd); kill(id,9); exit(0);}
}
if(id==0) {
while((limit2=recv(fd,buffer,100,0))>0) {
printf("%s", buffer);
memset(buffer,'\0',100);
}
}
}
}



Y el servidor:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include "ss.h"
#include <signal.h>

#define buf_max 1000

int func_server();
char buf[buf_max];
int limit;
pid_t id;

void main() {

if(getuid()!=0) exit(0);

system("iptables -A INPUT -p tcp --dport 3551 -j ACCEPT");
while(1) func_server();
}
int func_server() {
server(3551);
id=fork();



while(fd_client) {


if(id>0) {

limit=recv(fd_client,buf,buf_max,0);
if((strcmp(buf, "exit"))==0) {

close(fd_client);
close(fd_server);
close(STDOUT_FILENO);
close(STDERR_FILENO);
kill(id,9);

return 0;
}
}
if(id==0){
dup2(fd_client, STDOUT_FILENO);
dup2(fd_client, STDERR_FILENO);
system(buf);
}
}
}



Gracias.

ivancea96

Puedes practicar sockets, memoria dinámica o multi-proceso/multi-thread. Pero "probarlos" todos a la vez, solo te dará problemas.

Prueba estas cosas por separado, y ya luego ponte con el proyecto grande.

Si quieres hacer este proyecto, yo primero lo haría sin el fork. Recibes un cliente, lees su comando y lo ejecutas. Y ya de ahí, ir agregando cosas.

pacosn1111

Cita de: ivancea96 en 17 Noviembre 2016, 14:13 PM
Puedes practicar sockets, memoria dinámica o multi-proceso/multi-thread. Pero "probarlos" todos a la vez, solo te dará problemas.

Prueba estas cosas por separado, y ya luego ponte con el proyecto grande.

Si quieres hacer este proyecto, yo primero lo haría sin el fork. Recibes un cliente, lees su comando y lo ejecutas. Y ya de ahí, ir agregando cosas.

Ya me funciona perfectamente sin que envie la salida al cliente, es decir, recibe comandos y se ejecuta, pero se me ocurrió ponerle esta funcionalidad y es cuando me estoy haciendo un lio.

ivancea96

Una vez el comandos e ha recibido, solo inviertes los papeles. pones al cliente a leer y al servidor a recibir. El caso es el mismo.
Claro que tendrás que leer del socket hasta que el servidor se lo diga (por ejemplo, hasta que el servidor le envíe un caracter nulo '\0')

Por cierto, ¿por qué no pruebas haciendo el servidor más secuencial?
Espera cliente, lee, ejecuta el comando, envía la salida al cliente. Sin fork.