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$
tux-gpt - Assistente de IA para o Terminal
Instalação e configuração do Chrony
Programa IRPF - Guia de Instalação e Resolução de alguns Problemas
Instalando o Team Viewer no Debian Trixie - problema no Policykit
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
Música que eu compus, será que ficou boa? (6)
VPN Site to site mantendo wifi da operadora (0)
Alguém poderia me ajudar a escolher peças pra montar um desktop? (24)
Copiar Layout do Teclado para aplicar em outra Distribuição (3)