void listGames(player p) { int j; if(nb_game == 0) { sendack(p->fd, CMD_LIST, NULL); return; } // initialize message char * msg = malloc(sizeof(char)*(nb_game*(5+MAX_NAME_SIZE)+nb_game - 1)); *msg = 0; // for each game for(j=0;j<nb_game;j++) { char tmp[6]; // print id and game master's name sprintf(tmp, "#%05d", games[j]->id); strcat(msg, tmp); if(games[j]->game_master != NULL) strcat(msg, games[j]->game_master->name); } sendack(p->fd, CMD_LIST, msg); free(msg); }
// Parse the answers of the child processes transferring files void parseFileProcessesRequest(int i, char * buffer) { // if the fd closed if(readline(fileprocesses[i]->in, buffer, MAXBUF-1) == 0) { printf("\rChild process MIA...\n"); senderror(fileprocesses[i]->sender->fd, CMD_FILE, ERR_INTERNAL); removeChildProcess(i); return; } if(buffer[3] != '#') { printf("\rChild process is sending strange commands... Better check that, bro.\n"); senderror(fileprocesses[i]->sender->fd, CMD_FILE, ERR_INTERNAL); removeChildProcess(i); return; } buffer[3] = 0; if(strcmp(buffer, CMD_ERR) == 0) { printf("\rChild process failed with error: %s\n", buffer+4); senderror(fileprocesses[i]->sender->fd, CMD_FILE, ERR_INTERNAL); removeChildProcess(i); return; } if(strcmp(buffer, CMD_PORT) == 0 && buffer[9] == '#') { char * msg = malloc(sizeof(char)*(6+strlen(buffer+4))); buffer[9] = 0; printf("\rChild process waiting on port %s\n", buffer+4); sprintf(msg, "%s#%s#%s\n", CMD_PORT, buffer+4, buffer+10); sendline(fileprocesses[i]->sender->fd, msg); free(msg); return; } if(strcmp(buffer, CMD_READY) == 0) { printf("\rFile successfully uploaded !\n"); int j; char * msg = malloc(sizeof(char)*(6+strlen(buffer+4))); sprintf(msg, "%s#%s\n", CMD_FILE, buffer+4); for(j=0; j<fileprocesses[i]->sender->game->nb_players; j++) if(fileprocesses[i]->sender->game->players[j] != fileprocesses[i]->sender) sendline(fileprocesses[i]->sender->game->players[j]->fd, msg); sprintf(msg, "%05d", fileprocesses[i]->sender->game->nb_players); sendack(fileprocesses[i]->out, NULL, msg); free(msg); return; } if(strcmp(buffer, CMD_ACK) == 0) { printf("\rFile successfully broadcasted !\n"); sendack(fileprocesses[i]->sender->fd, CMD_FILE, buffer+4); removeChildProcess(i); return; } }
// send an available game id void getAvailableId(player p) { int j,k; int r=rand()%99999; int id; for(k=0;k<99999;k++) { int exist = 0; id = (r+k)%99999+1; for(j=0;j<nb_game; j++) if(games[j]->id == id) { exist = 1; break; } if(!exist) break; } // No available id found if(k == 99999) { sendline(p->fd, "ERR#WTF ?? No more ids available ?!\n"); return; } char msg[6]; sprintf(msg, "%05d\n", id); sendack(p->fd, CMD_CREATE, msg); }
// bind to a game void bindToGame(player p, char * buffer) { int j; buffer[9] = 0; // already in a game if(p->game) { senderror(p->fd, NULL, ERR_ALREADY_IN_GAME); return; } // id of the game int id = atoi(buffer+4); // search for the game game g = NULL; for(j=0; j<nb_game; j++) if(games[j]->id == id) { g = games[j]; break; } // if it doesn't exist, if(!g) { senderror(p->fd, CMD_BIND, ERR_GAME_DOESNT_EXIST); return; } // update the name of the player strncpy(p->name, buffer+10, MAX_NAME_SIZE); // if game is already full if(g->nb_players >= MAX_PLAYER_GAME) { printf("\rToo many players in this game !\n"); senderror(p->fd, CMD_BIND, ERR_TOO_MANY_PLAYERS_IN_GAME); return; } // check if the name is already used for(j=0; j<g->nb_players; j++) if(strcmp(g->players[j]->name, p->name) == 0) { printf("\rName already used !\n"); senderror(p->fd, CMD_BIND, ERR_NAME_USED); return; } // send notification to players in the game char * msg = malloc(sizeof(char)*(6+strlen(p->name))); sprintf(msg, "%s#%s\n", CMD_CONNECTED, p->name); for(j=0;j<g->nb_players; j++) if(g->players[j] != p) sendline(g->players[j]->fd, msg); free(msg); // update player, game and table of games p->game = g; g->players[g->nb_players] = p; g->nb_players++; sendack(p->fd, CMD_BIND, buffer+4); }
/* * Receives TCP data until socket breaks or File is completely received * int recvsock -> The listening UDP socket * int tcpsock -> The TCP ACK port * FILE *fout -> The file to write data too * FILE *log -> The log file to write received packet data */ size_t recv_tcp(int recvsock, int tcpsock, FILE *fout, FILE *log) { /* No more data to read */ if (finflag) { finflag = 0; return 0; } struct timeval tv; ssize_t len = 0; uint16_t src, dst; struct sockaddr_storage src_addr; socklen_t src_len = sizeof(src_addr); /* Packet and ACK bookkeeping */ uint32_t expected_seq = 0; uint32_t totalsent = 0; uint32_t lastpkt_len = 0; /* Packet Priority Queue for packet buffering */ std::priority_queue<Packet *, std::vector<Packet *>, PacketCompare> pq; for(;;) { if (finflag && pq.empty()) { return totalsent; } uint8_t packet_data[MSS + HEADLEN]; if ((len = recvfrom(recvsock, packet_data, MSS + HEADLEN, NOFLAG, (struct sockaddr *) &src_addr, &src_len)) <= 0) { if (errno == EAGAIN) { continue; } else { perror("recvfrom() failed"); return 0; } } Packet *pkt = new Packet(packet_data, (size_t) len); src = pkt->get_srcport(); dst = pkt->get_dstport(); gettimeofday(&tv, NULL); char *logtime = ctime(&(tv.tv_sec)); logtime[strlen(logtime) - 1] = '\0'; /* Checksum doesn't match */ if (!(pkt->check_checksum((size_t) len))) { if(log != nullptr) { fprintf(log, "FAILURE %s %u %u %u %u %d\n", logtime, src, dst, pkt->get_seq(), pkt->get_ack(), pkt->get_flags()); } /* Update Timeout */ check_timeout(&tv); /* Send old ack for fast retransmit */ if (sendack(tcpsock, dst, src, expected_seq) != HEADLEN) { if (!finflag) { die_with_err("send failed"); } } delete pkt; continue; } if(log != nullptr) { fprintf(log, "SUCCESS %s %u %u %u %u %d\n", logtime, src, dst, pkt->get_seq(), pkt->get_ack(), pkt->get_flags()); } if (!finflag) { finflag = (pkt->get_flags() & FINFLAG); /* Sets the length of the last packet for final packet handeling */ lastpkt_len = (uint32_t)len-HEADLEN; } if (expected_seq == pkt->get_seq()) { /* Writes data to file output skipping the header */ fwrite(pkt->get_data()+HEADLEN, sizeof(uint8_t), (size_t)len - HEADLEN, fout); expected_seq += len - HEADLEN; totalsent += len - HEADLEN; delete pkt; /* Writes buffered data to file if the sequence number matches */ while (!pq.empty() && (pq.top())->get_seq() == expected_seq) { pkt = pq.top(); size_t size = (size_t)((pkt->get_flags() & FINFLAG) ? lastpkt_len : MSS); fwrite(pkt->get_data()+HEADLEN, sizeof(uint8_t), size, fout); totalsent += size; expected_seq += size; delete pkt; pq.pop(); } } else if(expected_seq < pkt->get_seq()) { // Out of order packet pq.push(pkt); } else { // Already written, delete delete pkt; } if (sendack(tcpsock, dst, src, expected_seq) != HEADLEN) { if (!finflag) { die_with_err("send failed"); } } } return totalsent; }
/** * @breaf initialize the pfon comunication * * @param no parametrs */ int8_t FON_INIT() { enum fbus_frametype ftype; char buffer[24]; memset(buffer, 0, sizeof(buffer)); //write mesage in EEPPROM /* eeprom_read_block(buffer, (int*) 486, 18); if (strlen(buffer) == 0) { strcpy_P(buffer, CMD_ERR); eeprom_write_block(buffer, (int*) 486, 18); //strcpy_P(buffer, 0x00); } */ SetPort(); strcpy_P(buffer, CMD_ERR); eeprom_update_block(buffer, (int*) 486, 18); uint8_t init[] = { 0x00, 0x01, 0x64, 0x01, 0x01, 0x40 }; fbus_init(); sendframe(0x40, init, 6); ftype = fbus_readack(); if (ftype == FRAME_UNKNOWN) { sendframe(0x40, init, 6); ftype = fbus_readack(); if (ftype == FRAME_UNKNOWN) { sendframe(0x40, init, 6); ftype = fbus_readack(); if (ftype == FRAME_UNKNOWN) { PORTB |= (1 << PB5); //eror return 0; } } } //save smsc number if is not saved char smsc_nr[18]; memset(smsc_nr, 0, sizeof(smsc_nr)); _delay_ms(1000); fbus_getsmsc(smsc_nr); /* eeprom_read_block(buffer, (int*) 360, 18); if ((strcmp(smsc_nr, buffer) != 0) && (strlen(smsc_nr) != 0)) eeprom_write_block(smsc_nr, (int*) 360, 18); */ if (strlen(smsc_nr) != 0) eeprom_update_block(smsc_nr, (int*) 360, 18); sendack(0x02, 0x04); uint8_t init_sms[] = { 0x00, 0x01, 0x00, 0x07, 0x02, 0x01, 0x01, 0x64, 0x01, 0x47 }; sendframe(0x02, init_sms, 0x0a); //fbus_readack(); sendack(0x14, 0x00); //uart_sendsms("+40744946000", "+40745183841", smsc_nr); return 1; }
// transfer a file // for the son, never return void transfer_file(player p, char * buffer) { int out[2], in[2]; int childpid; int size; char * filepath; buffer[10] = 0; // if in a game if(!p->game) { senderror(p->fd, CMD_FILE, ERR_NOT_IN_GAME); return; } // if there is no game master or if the player is not game master if(p->game->game_master != p) { senderror(p->fd, CMD_FILE, ERR_ONLY_GM); return; } // check for file size if((size = atoi(buffer+4)) > MAX_FILE_SIZE) { senderror(p->fd, CMD_FILE, ERR_FILE_TOO_BIG); return; } // path of the file is specified if(strlen(buffer+11) == 0) { senderror(p->fd, NULL, ERR_NOT_RECOGNIZED); return; } filepath = malloc(sizeof(char)*(strlen(buffer+11)+1)); strcpy(filepath, buffer+11); printf("\rPlayer %s is trying to broadcast the file : %s (%dB)\n", p->name, filepath, size); // The file can be transmitted if(nb_file_processes >= MAX_FILE_TRANSFER) { printf("\rToo many ongoing file transfers !\n"); senderror(p->fd, CMD_FILE, ERR_TOO_MANY_FILE_TRANSFERS); return; } // create a pipe to communicate between the two processes pipe(in); pipe(out); // fork if((childpid = fork()) == -1) { printf("\rServer failed to fork !\n"); senderror(p->fd, CMD_FILE, ERR_INTERNAL); return; } // for the child if(childpid == 0) { // close the input part of one pipe and the output part of the other one close(out[0]); close(in[1]); // create the listening socket int filelistener = socket(AF_INET, SOCK_STREAM, 0); if(filelistener == -1) { senderror(out[1], NULL, "Could not open socket"); exit(EXIT_FAILURE); } // enable to reuse addr right after we stopped the server int optval = 1; setsockopt(filelistener, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); struct sockaddr_in servaddr; // socket address struct memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(0); // bind socket if(bind(filelistener, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { senderror(out[1], NULL, "Error when trying to bind !"); exit(EXIT_FAILURE); } // get port socklen_t length = sizeof(servaddr); getsockname(filelistener, (struct sockaddr *)&servaddr, &length); int port = ntohs(servaddr.sin_port); // Listen on the port if(listen(filelistener, MAX_PLAYER_GAME+2) == -1) { senderror(out[1], NULL, "Error when trying to listen !"); exit(EXIT_FAILURE); } // send port to parent char * msg = malloc(sizeof(char)*(12+strlen(filepath))); sprintf(msg, "%s#%05d#%s\n", CMD_PORT, port, filepath); sendline(out[1], msg); free(msg); // wait for the connection of the sender fd_set rfds; FD_ZERO(&rfds); FD_SET(filelistener, &rfds); int fd_max; fd_max = filelistener; struct timeval to = {TIMEOUT_FILE, 0}; if(select(fd_max+1, &rfds, NULL, NULL, &to) < 0) { senderror(out[1], NULL, "Error when trying to select !"); exit(EXIT_FAILURE); } int sender_socket; if(FD_ISSET(filelistener, &rfds)) { struct sockaddr_in csin; socklen_t recsize = sizeof(csin); sender_socket = accept(filelistener, (struct sockaddr *) &csin, &recsize); } else { senderror(out[1], NULL, "Timeout before sender tries to connect !"); exit(EXIT_FAILURE); } // get the file from the sender char filename[12+MAX_NAME_SIZE]; sprintf(filename, "/tmp/%05d_%s", p->game->id, p->name); int serverfile = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); int sent = 0; while(sent < size) { // prepare the set fd_set rfds; FD_ZERO(&rfds); FD_SET(sender_socket, &rfds); fd_max = sender_socket; to.tv_sec = TIMEOUT_FILE; to.tv_usec = 0; if(select(fd_max+1, &rfds, NULL, NULL, &to) < 0) { senderror(out[1], NULL, "Error when trying to select !"); close(serverfile); unlink(filename); exit(EXIT_FAILURE); } if(FD_ISSET(sender_socket, &rfds)) { int rc = read(sender_socket, buffer, MAXBUF); if(write(serverfile, buffer, rc) < 0) { senderror(out[1], NULL, "Error when writing to tmp file !"); close(serverfile); unlink(filename); exit(EXIT_FAILURE); } sent += rc; } else { senderror(out[1], NULL, "Timeout when sender was sending data"); close(serverfile); unlink(filename); exit(EXIT_FAILURE); } } close(serverfile); close(sender_socket); // send notification to the parent that we are ready to broadcast msg = malloc(sizeof(char)*(19+strlen(filepath))); sprintf(msg, "%s#%05d#%06d#%s\n", CMD_READY, port, size, filepath); sendline(out[1], msg); readline(in[0], buffer, MAXBUF); if(buffer[3] != '#') { senderror(out[1], NULL, "Who are you ?"); unlink(filename); exit(EXIT_FAILURE); } buffer[3] = 0; if(strcmp(buffer, CMD_ACK) != 0) { senderror(out[1], NULL, "Who are you ?"); unlink(filename); exit(EXIT_FAILURE); } int nb_players = atoi(buffer+4); // send the file to the other players int connected_clients = 0, served_clients = 0; int * sock_client = malloc(sizeof(int)*nb_players); int * fd_client = malloc(sizeof(int)*nb_players); int * byte_written = malloc(sizeof(int)*nb_players); while(served_clients < nb_players-1) { fd_set rfds; fd_set rfds_write; FD_ZERO(&rfds); FD_ZERO(&rfds_write); FD_SET(filelistener, &rfds); fd_max = filelistener; int j; for(j=0; j<connected_clients; j++) { FD_SET(sock_client[j], &rfds_write); if(sock_client[j] > fd_max) fd_max = sock_client[j]; } to.tv_sec = TIMEOUT_FILE; to.tv_usec = 0; int return_value; if((return_value = select(fd_max+1, &rfds, &rfds_write, NULL, &to)) < 0) { senderror(out[1], NULL, "Error when trying to select !"); unlink(filename); exit(EXIT_FAILURE); } if(return_value == 0) { senderror(out[1], NULL, "Timeout clients"); unlink(filename); exit(EXIT_FAILURE); } if(FD_ISSET(filelistener, &rfds)) { struct sockaddr_in csin; socklen_t recsize = sizeof(csin); int s = accept(filelistener, (struct sockaddr *) &csin, &recsize); if(connected_clients < nb_players) { sock_client[connected_clients] = s; fd_client[connected_clients] = open(filename, O_RDONLY); byte_written[connected_clients] = 0; connected_clients ++; } else close(s); } for(j=0; j<connected_clients; j++) if(FD_ISSET(sock_client[j], &rfds_write)) { int b_read = read(fd_client[j], buffer, size-byte_written[j] < MAXBUF ? size-byte_written[j] : MAXBUF); int b_written = write(sock_client[j], buffer, b_read); if(b_written == 0) { close(sock_client[j]); close(fd_client[j]); int k; for(k=j; k<connected_clients-1; k++) { fd_client[k] = fd_client[k+1]; sock_client[k] = sock_client[k+1]; byte_written[k] = byte_written[k+1]; } } lseek(sock_client[j], b_written-b_read, SEEK_CUR); byte_written[j] += b_written; if(byte_written[j] == size) { close(sock_client[j]); close(fd_client[j]); int k; for(k=j; k<connected_clients-1; k++) { fd_client[k] = fd_client[k+1]; sock_client[k] = sock_client[k+1]; byte_written[k] = byte_written[k+1]; } served_clients++; connected_clients--; j--; } } } sendack(out[1], NULL, filepath); unlink(filename); exit(0); } // for the parent else { // close output part of the pipe and input part of the other close(out[1]); close(in[0]); // create a new entry in the child processes table fileprocesses[nb_file_processes] = malloc(sizeof(struct _fproc)); fileprocesses[nb_file_processes]->in = out[0]; fileprocesses[nb_file_processes]->out = in[1]; fileprocesses[nb_file_processes]->sender = p; fileprocesses[nb_file_processes]->pid = childpid; nb_file_processes++; free(filepath); return; } }