Enviado em 16/08/2019 - 11:23h
Seguinte, desenvolvi um pequeno servidor em C usando POSIX Sockets e gostaria de obter algumas opiniões e sugestões para melhoria de código.
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define RCVTIMEO 3
static int set_socket_opts(int sockfd, bool use_only_ipv6){
int rv;
const int optval=1;
socklen_t optlen=sizeof(optval);
struct timeval rcv;
socklen_t tvlen=sizeof(rcv);
rcv.tv_sec=RCVTIMEO;
rcv.tv_usec=0;
do{
if((rv=setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen))!=0){
break;
}
if((rv=setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &rcv, tvlen))!=0){
break;
}
if(use_only_ipv6==true){
rv=setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, optlen);
}
}while(false);
return rv;
}
static int make_server_socket(char *argv[]){
bool use_only_ipv6;
int af, ecode, sockfd;
struct addrinfo hints, *rp=NULL, *res=NULL;
memset(&hints, 0, sizeof(hints));
if(strcmp(argv[1], "-4")==0){
af=AF_INET;
use_only_ipv6=false;
}else if(strcmp(argv[1], "-M")==0){
af=AF_INET6;
use_only_ipv6=false;
}else{
af=AF_INET6;
use_only_ipv6=true;
}
hints.ai_flags=AI_PASSIVE;
hints.ai_family=af;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
hints.ai_addr=NULL;
hints.ai_canonname=NULL;
hints.ai_next=NULL;
if((ecode=getaddrinfo(NULL, argv[2], &hints, &res))!=0){
fprintf(stderr, "* getaddrinfo() -> ERROR(ecode: %d): %s\n", ecode, gai_strerror(ecode));
exit(EXIT_FAILURE);
}
for(rp=res; rp!=NULL; rp=rp->ai_next){
sockfd=socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd<0){
continue;
}else{
if(set_socket_opts(sockfd, use_only_ipv6)!=0){
continue;
}
}
if(bind(sockfd, rp->ai_addr, rp->ai_addrlen)==0){
break;
}
close(sockfd);
}
if(rp==NULL){
fprintf(stderr, "* bind() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}else{
if(listen(sockfd, 10)!=0){
close(sockfd);
fprintf(stderr, "* listen() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
freeaddrinfo(res);
res=NULL;
rp=NULL;
return sockfd;
}
static int check_addr(char **buff_addr_table, const char *buff_addr, int af, size_t count){
int rv=0;
size_t addrlen;
if(af==AF_INET){
struct sockaddr_in *addr4_from_table=NULL;
struct sockaddr_in *addr4=(struct sockaddr_in*)buff_addr;
addrlen=sizeof(addr4->sin_addr.s_addr);
for(size_t i=0; i<count; i++){
addr4_from_table=(struct sockaddr_in*)buff_addr_table[i];
if(memcmp(&addr4_from_table->sin_addr.s_addr, &addr4->sin_addr.s_addr, addrlen)==0){
rv=-1;
break;
}
}
}else if(af==AF_INET6){
struct sockaddr_in6 *addr6_from_table=NULL;
struct sockaddr_in6 *addr6=(struct sockaddr_in6*)buff_addr;
addrlen=sizeof(addr6->sin6_addr.s6_addr);
for(size_t i=0; i<count; i++){
addr6_from_table=(struct sockaddr_in6*)buff_addr_table[i];
if(memcmp(&addr6_from_table->sin6_addr.s6_addr, &addr6->sin6_addr.s6_addr, addrlen)==0){
rv=-1;
break;
}
}
}else{
rv=-2;
}
return rv;
}
static void show_addr(const struct sockaddr *addr){
char *str_addr=NULL;
if(addr->sa_family==AF_INET){
str_addr=malloc(INET_ADDRSTRLEN*sizeof(*str_addr));
if(str_addr==NULL){
fprintf(stderr, "Memory allocation for %ld bytes failed\n", INET_ADDRSTRLEN*sizeof(*str_addr));
fprintf(stderr, "malloc() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
if(inet_ntop(AF_INET, &addr4->sin_addr.s_addr, str_addr, INET_ADDRSTRLEN)==NULL){
fprintf(stderr, "* inet_ntop() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
}else{
fprintf(stdout, "%s\n", str_addr);
}
}else{
str_addr=malloc(INET6_ADDRSTRLEN*sizeof(*str_addr));
if(str_addr==NULL){
fprintf(stderr, "Memory allocation for %ld bytes failed\n", INET6_ADDRSTRLEN*sizeof(*str_addr));
fprintf(stderr, "malloc() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
if(inet_ntop(AF_INET6, addr6->sin6_addr.s6_addr, str_addr, INET6_ADDRSTRLEN)==NULL){
fprintf(stderr, "* inet_ntop() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
}else{
fprintf(stdout, "%s\n", str_addr);
}
}
free(str_addr);
}
static char **realloc_addr_table(char **buff_addr_table, socklen_t addrlen, size_t count){
buff_addr_table=realloc(buff_addr_table, count*sizeof(*buff_addr_table));
if(buff_addr_table==NULL){
fprintf(stderr, "Memory allocation for %ld bytes failed\n", count*sizeof(*buff_addr_table));
fprintf(stderr, "realloc() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
buff_addr_table[count-1]=malloc(addrlen*sizeof(**buff_addr_table));
if(buff_addr_table[count-1]==NULL){
fprintf(stderr, "Memory allocation for %ld bytes failed\n", addrlen*sizeof(**buff_addr_table));
fprintf(stderr, "malloc() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
return buff_addr_table;
}
static void free_addr_table(char **buff_addr_table, size_t count){
for(size_t i=0; i<count; i++){
free(buff_addr_table[i]);
}
free(buff_addr_table);
}
static void search(char *argv[]){
socklen_t addrlen;
char *buff_addr=NULL;
char **buff_addr_table=NULL;
struct sockaddr *addr=NULL;
char *eptr;
size_t i=0, max_connections=strtoll(argv[3], &eptr, 10);
int sockfd, new_sockfd;
char message[512];
sockfd=make_server_socket(argv);
if(strcmp(argv[1], "-4")==0){
addrlen=sizeof(struct sockaddr_in);
}else{
addrlen=sizeof(struct sockaddr_in6);
}
buff_addr=calloc(addrlen, sizeof(*buff_addr));
if(buff_addr==NULL){
fprintf(stderr, "Memory allocation for %ld bytes failed!\n", addrlen*sizeof(*buff_addr));
fprintf(stderr, "calloc() -> ERROR(errno: %d): %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}
addr=(struct sockaddr*)buff_addr;
while(i<max_connections){
new_sockfd=accept(sockfd, addr, &addrlen);
if(new_sockfd!=-1){
if(check_addr(buff_addr_table, buff_addr, addr->sa_family, i)==0){
show_addr(addr);
if(recv(new_sockfd, message, sizeof(message), 0)==-1){
fprintf(stderr, "recv() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
}else{
fprintf(stdout, "Client says: %s\n\n", message);
}
i++;
buff_addr_table=realloc_addr_table(buff_addr_table, addrlen, i);
memcpy(buff_addr_table[i-1], buff_addr, addrlen*sizeof(*buff_addr));
}
close(new_sockfd);
}
}
free(buff_addr);
free_addr_table(buff_addr_table, i);
}
int main(int argc, char *argv[]){
char *eptr;
long long int res;
if(argc<4){
fprintf(stdout, "Usage: %s [-option] [port/service] [max_connections] \n", argv[0]);
fprintf(stdout, " -4 Use IPv4 \n");
fprintf(stdout, " -6 Use IPv6 \n");
fprintf(stdout, " -M Use IPv4 and IPv6 (IPv4-mapped IPv6 address) \n");
fprintf(stdout, " -h Show this page \n");
exit(EXIT_SUCCESS);
}
res=strtoll(argv[3], &eptr, 10);
if(res==0 || res==LONG_MAX || res==LONG_MIN){
if(errno==EINVAL || errno==ERANGE){
fprintf(stderr, "* strtoll() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
}else{
fprintf(stderr, "* Invalid value for max_connections!\n");
}
}else{
int opt=getopt(argc, argv, "46Mh");
switch(opt){
case '4':
case '6':
case 'M':
search(argv);
break;
case '?':
/*getopt() output*/
break;
case 'h':
default:
fprintf(stdout, "Usage: %s [-option] [port/service] [max_connections] \n", argv[0]);
fprintf(stdout, " -4 Use IPv4 \n");
fprintf(stdout, " -6 Use IPv6 \n");
fprintf(stdout, " -M Use IPv4 and IPv6 (IPv4-mapped IPv6 address) \n");
fprintf(stdout, " -h Show this page \n");
break;
}
}
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
static int try_connect(char *argv[]){
int ecode, sockfd;
struct addrinfo *rp=NULL, *res=NULL, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
hints.ai_addr=NULL;
hints.ai_canonname=NULL;
hints.ai_next=NULL;
if((ecode=getaddrinfo(argv[1], argv[2], &hints, &res))!=0){
fprintf(stderr, "* getaddrinfo() -> ERROR(ecode: %d): %s\n", ecode, gai_strerror(ecode));
exit(EXIT_FAILURE);
}
for(rp=res; rp!=NULL; rp=rp->ai_next){
if((sockfd=socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))<0){
continue;
}
if(connect(sockfd, rp->ai_addr, rp->ai_addrlen)==0){
break;
}
close(sockfd);
}
if(rp==NULL){
fprintf(stderr, "* socket()/conncet() -> ERROR(errno: %d): %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
freeaddrinfo(res);
return sockfd;
}
int main(int argc, char *argv[]){
const char message[]="Real Muthaphuckkin G's";
int sockfd=try_connect(argv);
if(send(sockfd, message, sizeof(message), 0)!=sizeof(message)){
fprintf(stderr, "* send() -> ERROR(errno: %d): %s\n", errno, message);
}else{
printf("send() -> OK\n");
}
return EXIT_SUCCESS;
}
zherkezhi@zherkezhi:~/Documents$ gcc -Wall server.c -o server
zherkezhi@zherkezhi:~/Documents$ ./server -h
Usage: ./server [-option] [port/service] [max_connections]
-4 Use IPv4
-6 Use IPv6
-M Use IPv4 and IPv6 (IPv4-mapped IPv6 address)
-h Show this page
zherkezhi@zherkezhi:~/Documents$ ./server -M 9009 2
::ffff:192.168.50.202
Client says: Real Muthaphuckkin G's
::ffff:127.0.0.1
Client says: Real Muthaphuckkin G's
zherkezhi@zherkezhi:~/Documents$ ./server -4 9009 2
127.0.0.1
Client says: Real Muthaphuckkin G's
192.168.50.202
Client says: Real Muthaphuckkin G's
zherkezhi@zherkezhi:~/Documents$
zherkezhi@zherkezhi:~/Documents$ gcc -Wall client.c -o client
zherkezhi@zherkezhi:~/Documents$ ./client 192.168.50.202 9009
send() -> OK
zherkezhi@zherkezhi:~/Documents$ ./client 127.0.0.1 9009
send() -> OK
zherkezhi@zherkezhi:~/Documents$ ./client 127.0.0.1 9009
send() -> OK
zherkezhi@zherkezhi:~/Documents$ ./client 192.168.50.202 9009
send() -> OK
zherkezhi@zherkezhi:~/Documents$
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Como renomear arquivos de letras maiúsculas para minúsculas
Imprimindo no formato livreto no Linux
Vim - incrementando números em substituição
Efeito "livro" em arquivos PDF
Como resolver o erro no CUPS: Unable to get list of printer drivers
Melhorando a precisão de valores flutuantes em python[AJUDA] (9)
GLPI - Configuração de destinatário com conta Microsoft Exchange (0)
Vou voltar moderar conteúdos de Dicas e Artigos (3)
OpenVPN no MACBOOK conecta mas não pinga pastas de rede compartilhada ... (1)
[Python] Automação de scan de vulnerabilidades
[Python] Script para analise de superficie de ataque
[Shell Script] Novo script para redimensionar, rotacionar, converter e espelhar arquivos de imagem
[Shell Script] Iniciador de DOOM (DSDA-DOOM, Doom Retro ou Woof!)
[Shell Script] Script para adicionar bordas às imagens de uma pasta