int Drawboard::sendDrawdata(Client *client,std::vector<uint8_t> data, uint8_t chan) { uint8_t tempdata[4]; std::vector<uint8_t> drawdata; //ToDo: add compression //Type byte drawdata.push_back(ACTION_DRAW_DATA); //Msg len, allocate the space drawdata.insert(drawdata.end(),&tempdata[0],&tempdata[0]+2); //UID putUint16(&tempdata[0],client->UID); drawdata.insert(drawdata.end(),&tempdata[0],&tempdata[0]+2); //the data drawdata.insert(drawdata.end(),&data[0],&data[0]+data.size()); //Fill in the length information putUint16(&drawdata[1], drawdata.size()-3); sendAll((uint8_t *)&drawdata[0],drawdata.size()); return 1; }
bool Drawboard::sendUserlist(Client* client) { uint8_t tempdata[2]; std::vector<uint8_t> data; uint8_t users = 0; data.push_back(ACTION_USER_ADD); data.push_back(0); data.push_back(0); //Datalen data.push_back(0); //Add data.push_back(0); //Client number (fill at the end) for (std::vector<Client*>::iterator it = m_clients.begin(); it!=m_clients.end(); ++it) { if((*it)->UID > 0) { putUint16(&tempdata[0],(*it)->UID); data.insert(data.end(),&tempdata[0],&tempdata[0]+2); data.push_back((uint8_t)((*it)->nick).size()); data.insert(data.end(),((*it)->nick).data(),((*it)->nick).data()+((*it)->nick).size()); users++; } } data[4] = users; //Fill in the length information putUint16(&data[1], data.size()-3); send(client->getFd(), (uint8_t *)&data[0],data.size()); return true; }
//Search for the cliend and remove bool Drawboard::remClient(int m_fd) { uint32_t UID = -1; std::string nick; for (std::vector<Client*>::iterator it = m_clients.begin(); it!=m_clients.end(); ++it) { if((*it)->getFd() == m_fd) { if((*it)->UID > 0) { UID = (*it)->UID; nick = (*it)->nick; } //Close client socket #ifdef WIN32 closesocket(m_fd); #else close(m_fd); #endif delete *it; m_clients.erase(it); break; } } //ToDo: send info of removed client if(UID != -1) { uint8_t tempdata[2]; std::vector<uint8_t> remdata; //Type byte remdata.push_back(ACTION_USER_REM); //Datalen putUint16(&tempdata[0],4); remdata.insert(remdata.end(),&tempdata[0],&tempdata[0]+2); remdata.push_back(1); //Rem remdata.push_back(1); //Number of users //UID putUint16(&tempdata[0],UID); remdata.insert(remdata.end(),&tempdata[0],&tempdata[0]+2); sendAll((uint8_t *)&remdata[0],remdata.size()); } std::cout << "Client removed" << std::endl; return true; }
int Drawboard::sendChat(Client *client,std::string data, uint8_t chan) { uint8_t tempdata[4]; std::vector<uint8_t> chatdata; //Type byte chatdata.push_back(ACTION_CHAT_DATA); //Msg len, allocate the space chatdata.insert(chatdata.end(),&tempdata[0],&tempdata[0]+2); //UID putUint16(&tempdata[0],client->UID); chatdata.insert(chatdata.end(),&tempdata[0],&tempdata[0]+2); //Nick size chatdata.push_back(client->nick.size()); //Nick chatdata.insert(chatdata.end(),client->nick.data(),client->nick.data()+client->nick.size()); //Channel ID chatdata.push_back(0); //Msg size chatdata.push_back(data.size()); //Nick chatdata.insert(chatdata.end(),data.data(), data.data()+data.size()); //Fill in the length information putUint16(&chatdata[1], chatdata.size()-3); sendAll((uint8_t *)&chatdata[0],chatdata.size()); return 1; }
extern "C" void client_callback(int fd, short ev, void* arg) { Client* client = reinterpret_cast<Client*>(arg); std::vector<uint8_t> outBuf; if (ev & EV_READ) { int read = 1; read = recv(fd, clientBuf, BUFSIZE, 0); #ifdef DEBUG std::cout << "Read from socket " << read << std::endl; #endif if (read == 0) { #ifdef DEBUG std::cout << "Socket closed properly" << std::endl; #endif Drawboard::get()->remClient(fd); return; } if (read == SOCKET_ERROR) { #ifdef DEBUG std::cout << "Socket had no data to read" << std::endl; #endif Drawboard::get()->remClient(fd); return; } //Store the time //client->lastData = time(NULL); client->buffer.insert(client->buffer.end(), clientBuf,clientBuf+read); //Handle the data while (client->buffer.size()>2) { //If user has not authenticated and tries to send other data if(client->buffer[0] != 0x05 && client->UID == -1) { #ifdef DEBUG std::cout << "First data was not auth, closing" << std::endl; #endif Drawboard::get()->remClient(fd); return; } int curpos = 1; switch(client->buffer[0]) { //uncompressed draw data case ACTION_DRAW_DATA: case ACTION_COMPRESSED_DRAW_DATA: { //Datalen uint32_t len=getUint16((uint8_t *)(&client->buffer[0]+curpos)); curpos += 2; #ifdef DEBUG std::cout << " Draw data " << len << std::endl; #endif //Wait for more data if( (client->buffer.size() - curpos) < len) { event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); return; } std::vector<uint8_t> drawdata; drawdata.insert(drawdata.begin(),&client->buffer[0]+curpos, &client->buffer[0]+curpos+len); //If compressed, uncompress if(client->buffer[0] == ACTION_COMPRESSED_DRAW_DATA) { uint32_t read=2000; uint8_t *out=(uint8_t *)malloc(2000); //Uncompress the data, kick client if invalid if(uncompress((Bytef *)out, (uLongf *)&read, (Bytef *)&drawdata[0], drawdata.size())!=0) { free(out); Drawboard::get()->remClient(fd); return; } drawdata.clear(); drawdata.insert(drawdata.begin(),out, out+read); } //Echo to others if(drawdata.size()) { Drawboard::get()->sendDrawdata(client,drawdata,0); } client->eraseFromBuffer(curpos+len); } break; //compressed draw data case ACTION_PNG_REQUEST: { //Datalen uint32_t len=getUint16((uint8_t *)(&client->buffer[0]+curpos)); curpos += 2; #ifdef DEBUG std::cout << " PNG request " << len << std::endl; #endif //Wait for more data if( (client->buffer.size() - curpos) < len) { event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); return; } //Clear the data from buffer client->eraseFromBuffer(curpos+len); } break; //Chat data case ACTION_CHAT_DATA: { //Datalen uint32_t len=getUint16((uint8_t *)(&client->buffer[0]+curpos)); curpos += 2; #ifdef DEBUG std::cout << " Got chat data with length " << len << std::endl; #endif //Wait for more data if( (client->buffer.size() - curpos) < len) { event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); return; } //ToDo: maybe check the data, now we just echo everything uint8_t chan = client->buffer[curpos]; curpos++; uint8_t datalen=client->buffer[curpos]; curpos++; if(datalen) { std::string chatdata(&client->buffer[curpos], &client->buffer[curpos]+datalen); #ifdef DEBUG std::cout << " Repeating chat data" << std::endl; #endif Drawboard::get()->sendChat(client, chatdata, chan); } //Clear the data from the buffer client->eraseFromBuffer(curpos+datalen); } break; //Authentication case ACTION_AUTH: { #ifdef DEBUG std::cout << " Got auth " << std::endl; #endif int response = Drawboard::get()->authenticate(client); if(response == NEED_MORE_DATA) { #ifdef DEBUG std::cout << " NEED_MORE_DATA" << std::endl; #endif event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); return; } else if(response == DATA_ERROR) { Drawboard::get()->remClient(fd); return; } //Send userlist to the new client //Generate uid for the user client->UID = Drawboard::get()->generateUID(); { //Send others info about this client uint8_t tempdata[2]; std::vector<uint8_t> data; //Type byte data.push_back(ACTION_USER_REM); //Datalen putUint16(&tempdata[0],5+client->nick.size()); data.insert(data.end(),&tempdata[0],&tempdata[0]+2); data.push_back(0); //Add data.push_back(1); //Number of users //UID putUint16(&tempdata[0],client->UID); data.insert(data.end(),&tempdata[0],&tempdata[0]+2); data.push_back((uint8_t)client->nick.size()); data.insert(data.end(),(client->nick).data(),(client->nick).data()+(client->nick).size()); Drawboard::get()->sendAll((uint8_t *)&data[0],data.size(), client->getFd()); } //Send userlist to the new client Drawboard::get()->sendUserlist(client); } break; //If something else, remove the client default: Drawboard::get()->remClient(fd); return; break; } /* event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); return; */ } // while(user->buffer) if(outBuf.size()) { if(Drawboard::get()->send(fd,(uint8_t *)outBuf.data(), outBuf.size()) == -1) { return; } } } event_set(&client->m_event, fd, EV_READ, client_callback, client); event_add(&client->m_event, NULL); }