/********************************************************************* Callback from client listening to server in its own thread Only used for data transfers *********************************************************************/ static int async_data_recv(void * p_pData) { context_t * l_pContext = (context_t *) p_pData; while (true) { uint32_t l_FrameSize = 0U; if (network_read_bytes(l_pContext->socket_data, (char *) &l_FrameSize, sizeof(uint32_t)) == RET_NOK) { break; } { l_FrameSize = ntohl(l_FrameSize); wlog(LOGDEVELOPER, "received on data %u bytes long frame on socket %u", l_FrameSize, l_pContext->socket_data); NetworkFrame l_Frame(l_FrameSize); if (network_read_bytes(l_pContext->socket_data, (char *) l_Frame.getFrame(), l_FrameSize) == RET_NOK) { break; } if (parse_incoming_data(l_pContext, l_Frame) == RET_NOK) { break; } } } werr(LOGUSER, "Socket closed on server side."); context_set_connected(l_pContext, false); SDLNet_TCP_Close(l_pContext->socket); SDLNet_TCP_Close(l_pContext->socket_data); context_set_socket(l_pContext, 0); context_set_socket_data(l_pContext, 0); screen_quit(); return 0; }
/***************************** Disconnect a character. This kill a NPC AI thread return -1 if fails *****************************/ int character_disconnect( const char * id) { context_t * ctx; werr(LOGDEBUG,"Disconnecting %s",id); ctx = context_find(id); context_set_in_game(ctx,false); context_set_connected(ctx,false); context_spread(ctx); if( context_is_npc(ctx) == true ) { /* Wake up NPC */ if( SDL_TryLockMutex (ctx->cond_mutex) == 0 ) { SDL_CondSignal (ctx->cond); SDL_UnlockMutex (ctx->cond_mutex); } } return 0; }
/************************************** Return RET_NOK on error **************************************/ ret_code_t parse_incoming_data(context_t * context, Uint32 command, Uint32 command_size, char * data) { char * value = NULL; char * fullname; char * elements[512]; char * cksum; int i; char * user_name; char * password; if( !context_get_connected(context) && ( command != CMD_REQ_LOGIN && command != CMD_REQ_FILE) ) { werr(LOGUSER,"Request from not authenticated client, close connection"); return RET_NOK; } switch(command) { case CMD_REQ_LOGIN: wlog(LOGDEBUG,"Received CMD_REQ_LOGIN"); user_name = _strsep(&data,NETWORK_DELIMITER); password = _strsep(&data,NETWORK_DELIMITER); if(entry_read_string(PASSWD_TABLE, user_name, &value, PASSWD_KEY_PASSWORD,NULL) == RET_NOK) { return RET_NOK; } if( strcmp(value, password) != 0) { free(value); werr(LOGUSER,"Wrong login for %s",user_name); // send answer network_send_command(context, CMD_SEND_LOGIN_NOK, 0, NULL, false); // force client disconnection return RET_NOK; } else { free(value); if( context_set_username(context, user_name) == RET_NOK ) { return RET_NOK; } context_set_connected(context, true); // send answer network_send_command(context, CMD_SEND_LOGIN_OK, 0, NULL, false); wlog(LOGUSER,"Login successful for user %s",context->user_name); } break; case CMD_REQ_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_CHARACTER_LIST"); character_send_list(context); wlog(LOGDEBUG,"character list sent"); break; case CMD_REQ_FILE : i = 0; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } if(elements[0]==NULL || elements[1]==NULL) { werr(LOGDEV,"Received erroneous CMD_REQ_FILE"); break; } wlog(LOGDEBUG,"Received CMD_REQ_FILE for %s",elements[0]); /* compare checksum */ fullname = strconcat(base_directory,"/",elements[0],NULL); cksum = checksum_file(fullname); free(fullname); if( cksum == NULL) { werr(LOGUSER,"Required file %s doesn't exists",elements[0]); break; } if( strcmp(elements[1],cksum) == 0 ) { wlog(LOGDEBUG,"Client has already newest %s file",elements[0]); free(cksum); break; } free(cksum); network_send_file(context,elements[0]); wlog(LOGDEBUG,"File %s sent",elements[0]); break; case CMD_REQ_USER_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_USER_CHARACTER_LIST"); character_user_send_list(context); wlog(LOGDEBUG,"user %s's character list sent",context->user_name); break; case CMD_REQ_START : if( context->in_game == false ) { context->id = strdup(data); context->in_game = true; context_update_from_file(context); context_spread(context); context_request_other_context(context); } wlog(LOGDEBUG,"Received CMD_REQ_START for %s /%s",context->user_name,context->id); break; case CMD_REQ_STOP : wlog(LOGDEBUG,"Received CMD_REQ_STOP for %s /%s",context->user_name,context->id); if( context->in_game == true ) { context->in_game = false; if( context->map ) { free(context->map); } context->map = NULL; if( context->prev_map ) { free(context->prev_map); } context->prev_map = NULL; if( context->id ) { free(context->id); } context->id = NULL; context_spread(context); } break; case CMD_REQ_ACTION : i = 0; elements[i] = NULL; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } elements[i+1] = NULL; wlog(LOGDEBUG,"Received CMD_REQ_ACTION %s from %s /%s",elements[0],context->user_name,context->character_name); action_execute(context,elements[0],&elements[1]); break; default: werr(LOGDEV,"Unknown request %d from client",command); return RET_NOK; } return RET_OK; }
/************************************** Called from client **************************************/ void context_add_or_update_from_network_frame(context_t * context,char * data) { context_t * ctx = NULL; char * user_name = NULL; char * name = NULL; char * map = NULL; int in_game; bool connected; int pos_tx; int pos_ty; char * type = NULL; char * id = NULL; char * selected_character = NULL; char * selected_map = NULL; int selected_map_x = 0; int selected_map_y = 0; char * selected_equipment = NULL; char * selected_item = NULL; /* First decode the data */ user_name = strdup(data); data += (strlen(data)+1); name = strdup(data); data += (strlen(data)+1); map = strdup(data); data += (strlen(data)+1); in_game = atoi(data); data += (strlen(data)+1); connected = atoi(data); data += (strlen(data)+1); pos_tx = atoi(data); data += (strlen(data)+1); pos_ty = atoi(data); data += (strlen(data)+1); type = strdup(data); data += (strlen(data)+1); id = strdup(data); data += (strlen(data)+1); selected_character = strdup(data); data += (strlen(data)+1); selected_map = strdup(data); data += (strlen(data)+1); selected_map_x = atoi(data); data += (strlen(data)+1); selected_map_y = atoi(data); data += (strlen(data)+1); selected_equipment = strdup(data); data += (strlen(data)+1); selected_item = strdup(data); data += (strlen(data)+1); /* search for this context */ context_lock_list(); ctx = context_list_start; while( ctx != NULL ) { if( strcmp( id, ctx->id) == 0 ) { ctx->in_game = in_game; ctx->connected = connected; if( in_game == true ) { wlog(LOGDEBUG,"Updating context %s / %s",user_name,name); /* do not call context_set_* function since we already have the lock */ _context_set_map(ctx,map); _context_set_pos_tx(ctx,pos_tx); _context_set_pos_ty(ctx,pos_ty); free(ctx->type); ctx->type = strdup(type); if( ctx->selection.map ) { free(ctx->selection.map ); } ctx->selection.map = strdup(selected_map); ctx->selection.map_coord[0] = selected_map_x; ctx->selection.map_coord[1] = selected_map_y; if( ctx->selection.id ) { free(ctx->selection.id ); } ctx->selection.id = strdup(selected_character); if( ctx->selection.equipment ) { free(ctx->selection.equipment ); } ctx->selection.equipment = strdup(selected_equipment); if( ctx->selection.inventory ) { free(ctx->selection.inventory ); } ctx->selection.inventory = strdup(selected_item); } if( connected == false ) { wlog(LOGDEBUG,"Deleting context %s / %s",user_name,name); context_free(ctx); } context_unlock_list(); goto context_add_or_update_from_network_frame_free; } ctx = ctx->next; } context_unlock_list(); wlog(LOGDEBUG,"Creating context %s / %s",user_name,name); ctx = context_new(); context_set_username(ctx,user_name); context_set_character_name(ctx,name); context_set_map(ctx,map); context_set_type(ctx,type); context_set_pos_tx(ctx,pos_tx); context_set_pos_ty(ctx,pos_ty); context_set_id(ctx,id); context_set_connected(ctx,connected); context_set_in_game(ctx,in_game); context_set_selected_character(ctx,selected_character); context_set_selected_tile(ctx,selected_map,selected_map_x,selected_map_y); context_set_selected_equipment(ctx,selected_equipment); context_set_selected_item(ctx,selected_item); context_add_or_update_from_network_frame_free: free(user_name); free(name); free(map); free(type); free(id); free(selected_character); free(selected_map); free(selected_equipment); free(selected_item); }