/** * Programa Servidor de Eco para una conexion SCTP * Peer - to - Peer (multistreams) * Similar al caso de TCP pero con Multistream * Programado por Benjamin Ginouves * Para el proyecto de fin de ramo ELO330, 2s2010. */ #include #include #include #include #include // requiere instalar el paquete correspondiente y compilar con la libreria sctp #include #include #include //#include #include #include //#include //#include #include #define PUERTO "12345" #define MAXBUFFER 256 int main(int argc, char *arg[]) { int sd; // descriptor del socket reusable para conexiones entrantes por el mismo puerto. int s; // descriptor socket conexion struct addrinfo hints, *servinfo, *p; // estructura getaddrinfo struct sockaddr_storage addrfrom; // estructura para alojar datos de conexion para la recepcion y envio al cliente SCTP. socklen_t addrfromlen, statuslen; // estructura para almacenar largos de datos del cliente SCTP y su estatus. int res, n, nf, flags; char str[MAXBUFFER]; int one=1; fd_set readfds; struct timeval tiempo; struct sctp_initmsg initmsg; struct sctp_status status; struct sctp_sndrcvinfo info; memset(&hints, 0, sizeof(hints)); // se inicia la estructura en cero hints.ai_family = AF_UNSPEC; // para IPv4 o IPv6 hints.ai_socktype = SOCK_STREAM; // tipo de transmision de datos hints.ai_protocol = IPPROTO_SCTP; // definimos el protocolo SCTP hints.ai_flags = AI_PASSIVE; // localhost, con addr en NULL if ((res = getaddrinfo(NULL, PUERTO, &hints, &servinfo)) != 0) { printf("getaddrinfo: %s\n", gai_strerror(res)); return -1; } // hacemos bind a la lista de direcciones que corresponden a la llamada de getaddrinfo for (p = servinfo; p != NULL; p = p->ai_next) { if ((sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { // no se pudo abrir el socket perror("socket"); continue; // trata otra estructura en la lista } if (setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(char *) &one,sizeof(one)) == -1 ) { perror("setsockopt"); continue; // trata otra estructura en la lista } // servidor if (sctp_bindx(sd, p->ai_addr, 1, SCTP_BINDX_ADD_ADDR) == -1) { // no se pudo close(sd); perror("sctp_bindx"); continue; // trata otra estructura en la lista } break; // bind listo. } if (p == NULL) { // Se sale de la lista sin bind establecido fprintf(stderr, "fallo en sctp_bindx.\n"); return -1; } freeaddrinfo(servinfo); // eliminamos la estructura, para liberar la memoria, no se utilizara luego //fcntl(sd, F_SETFL, ~O_NONBLOCK); memset(&initmsg, 0, sizeof(initmsg)); initmsg.sinit_max_instreams = 6; printf("Streams de entrada máximos: %d.\n", initmsg.sinit_max_instreams); initmsg.sinit_num_ostreams = 5; printf("Streams de salida: %d.\n", initmsg.sinit_num_ostreams); if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) { perror("Error en setsockop\n"); } // espera una conexion del cliente listen(sd, 5); for (;;) { printf("accepta conexiones...\n"); addrfromlen = sizeof(addrfrom); if ((s = accept(sd, (struct sockaddr *)&addrfrom, &addrfromlen)) == -1) { perror("accept sctp"); continue; } memset(&status, 0, sizeof(status)); statuslen = sizeof(status); status.sstat_assoc_id = 1; if (getsockopt(s, IPPROTO_SCTP, SCTP_STATUS, &status, &statuslen) == -1) { perror("getsockopt"); continue; } printf("Se estabecieron %d streams de entrada y %d streams de salida.\n", status.sstat_instrms, status.sstat_outstrms); printf("Inicia Echo: \n"); memset(&info, 0, sizeof(info)); for (;;) { //memset(&info, 0, sizeof(info)); //bzero(&info, sizeof(info)); FD_ZERO(&readfds); // iniciamos en cero el arrglo FD_SET(s, &readfds); // hay datos para leer desde UDP tiempo.tv_sec = 10; // timeout 10 segundos tiempo.tv_usec = 0; nf = select(sizeof(readfds)*2, &readfds, (fd_set *) 0, (fd_set *) 0, &tiempo); switch (n) { case -1: // Error close(s); continue; case 0: // Timeout continue; default: if (FD_ISSET(s, &readfds)) { info.sinfo_stream = 1; n = sctp_recvmsg(s, str, MAXBUFFER, (struct sockaddr*)&addrfrom, &addrfromlen, &info, &flags); printf("Se recibió del Cliente %d bytes por el canal %hd : %s\nCon los flags: %d\n", n, info.sinfo_stream, str, info.sinfo_flags); info.sinfo_flags = 0; sctp_sendmsg(s, str, n, (struct sockaddr*)&addrfrom, addrfromlen, 0, 0, 1, 0, 0); // info.sinfo_flags = SCTP_EOF; // sctp_send(s, NULL, 0, &info, 0); // if ((n=send(s, str, MAXBUFFER, 0)) <0) { // printf("Error, conexión perdida.\n"); // break; // } sprintf(str, " "); } } // while ((n=sctp_recvmsg(s, str, MAXBUFFER, (struct sockaddr*)&addrfrom, &addrfromlen, &info, &flags)) < 1); // //n = recv(s, str, MAXBUFFER, 0); // printf("Se recibió del Cliente %d bytes por el canal %hd : %s\nCon los flags: %d\n", n, info.sinfo_stream, str, info.sinfo_flags); // if (sctp_send(s, str, strlen(str), &info, 0) < 0 ) { // //if ((n=send(s, str, MAXBUFFER, 0)) <0) { // printf("Error, conexión perdida.\n"); // break; // } // sprintf(str, " "); } close(s); } return 0; }