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$
Programa IRPF - Guia de Instalação e Resolução de alguns Problemas
Criando uma Infraestrutura para uma micro Empresa
Criar entrada (menuentry) ISO no Grub
Como gerar qualquer emoji ou símbolo unicode a partir do seu teclado
O Que Fazer Após Instalar Ubuntu 25.04
O Que Fazer Após Instalar Fedora 42
Debian 12 -- Errata - Correções de segurança
Instalando o Pi-Hole versão v5.18.4 depois do lançamento da versão v6.0