project_files/frontlib/net/netconn_send.c
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7580 c92596feac0d
child 10017 de822cd3df3a
equal deleted inserted replaced
7855:ddcdedd3330b 7857:2bc61f8841a1
       
     1 /*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU General Public License
       
     7  * as published by the Free Software Foundation; either version 2
       
     8  * of the License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13  * GNU General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License
       
    16  * along with this program; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    18  */
       
    19 
       
    20 #include "netconn_internal.h"
       
    21 
       
    22 #include "../util/logging.h"
       
    23 #include "../util/util.h"
       
    24 #include "../util/buffer.h"
       
    25 #include "../md5/md5.h"
       
    26 #include "../base64/base64.h"
       
    27 
       
    28 #include <zlib.h>
       
    29 
       
    30 #include <stdlib.h>
       
    31 #include <string.h>
       
    32 #include <limits.h>
       
    33 
       
    34 // cmdname is always given as literal from functions in this file, so it is never null.
       
    35 static int sendVoid(flib_netconn *conn, const char *cmdname) {
       
    36 	if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) {
       
    37 		return -1;
       
    38 	}
       
    39 	return flib_netbase_sendf(conn->netBase, "%s\n\n", cmdname);
       
    40 }
       
    41 
       
    42 // Testing for !*str prevents sending 0-length parameters (they trip up the protocol)
       
    43 static int sendStr(flib_netconn *conn, const char *cmdname, const char *str) {
       
    44 	if(log_e_if(!conn || flib_strempty(str), "Invalid parameter sending %s command", cmdname)) {
       
    45 		return -1;
       
    46 	}
       
    47 	return flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", cmdname, str);
       
    48 }
       
    49 
       
    50 static int sendInt(flib_netconn *conn, const char *cmdname, int param) {
       
    51 	if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) {
       
    52 		return -1;
       
    53 	}
       
    54 	return flib_netbase_sendf(conn->netBase, "%s\n%i\n\n", cmdname, param);
       
    55 }
       
    56 
       
    57 int flib_netconn_send_nick(flib_netconn *conn, const char *nick) {
       
    58 	int result = -1;
       
    59 	if(!log_badargs_if2(conn==NULL, flib_strempty(nick))) {
       
    60 		char *tmpName = flib_strdupnull(nick);
       
    61 		if(tmpName) {
       
    62 			if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) {
       
    63 				free(conn->playerName);
       
    64 				conn->playerName = tmpName;
       
    65 				tmpName = NULL;
       
    66 				result = 0;
       
    67 			}
       
    68 		}
       
    69 		free(tmpName);
       
    70 	}
       
    71 	return result;
       
    72 }
       
    73 
       
    74 int flib_netconn_send_password(flib_netconn *conn, const char *passwd) {
       
    75 	int result = -1;
       
    76 	if(!log_badargs_if2(conn==NULL, passwd==NULL)) {
       
    77 		md5_state_t md5state;
       
    78 		uint8_t md5bytes[16];
       
    79 		char md5hex[33];
       
    80 		md5_init(&md5state);
       
    81 		md5_append(&md5state, (unsigned char*)passwd, strlen(passwd));
       
    82 		md5_finish(&md5state, md5bytes);
       
    83 		for(int i=0;i<sizeof(md5bytes); i++) {
       
    84 			// Needs to be lowercase - server checks case sensitive
       
    85 			snprintf(md5hex+i*2, 3, "%02x", (unsigned)md5bytes[i]);
       
    86 		}
       
    87 		result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "PASSWORD", md5hex);
       
    88 	}
       
    89 	return result;
       
    90 }
       
    91 
       
    92 int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) {
       
    93 	return sendStr(conn, "QUIT", (quitmsg && *quitmsg) ? quitmsg : "User quit");
       
    94 }
       
    95 
       
    96 int flib_netconn_send_chat(flib_netconn *conn, const char *chat) {
       
    97 	if(!flib_strempty(chat)) {
       
    98 		return sendStr(conn, "CHAT", chat);
       
    99 	}
       
   100 	return 0;
       
   101 }
       
   102 
       
   103 int flib_netconn_send_kick(flib_netconn *conn, const char *playerName) {
       
   104 	return sendStr(conn, "KICK", playerName);
       
   105 }
       
   106 
       
   107 int flib_netconn_send_playerInfo(flib_netconn *conn, const char *playerName) {
       
   108 	return sendStr(conn, "INFO", playerName);
       
   109 }
       
   110 
       
   111 int flib_netconn_send_request_roomlist(flib_netconn *conn) {
       
   112 	return sendVoid(conn, "LIST");
       
   113 }
       
   114 
       
   115 int flib_netconn_send_joinRoom(flib_netconn *conn, const char *room) {
       
   116 	if(!sendStr(conn, "JOIN_ROOM", room)) {
       
   117 		conn->isChief = false;
       
   118 		return 0;
       
   119 	}
       
   120 	return -1;
       
   121 }
       
   122 
       
   123 int flib_netconn_send_playerFollow(flib_netconn *conn, const char *playerName) {
       
   124 	return sendStr(conn, "FOLLOW", playerName);
       
   125 }
       
   126 
       
   127 int flib_netconn_send_createRoom(flib_netconn *conn, const char *room) {
       
   128 	if(!sendStr(conn, "CREATE_ROOM", room)) {
       
   129 		conn->isChief = true;
       
   130 		return 0;
       
   131 	}
       
   132 	return -1;
       
   133 }
       
   134 
       
   135 int flib_netconn_send_ban(flib_netconn *conn, const char *playerName) {
       
   136 	return sendStr(conn, "BAN", playerName);
       
   137 }
       
   138 
       
   139 int flib_netconn_send_clearAccountsCache(flib_netconn *conn) {
       
   140 	return sendVoid(conn, "CLEAR_ACCOUNTS_CACHE");
       
   141 }
       
   142 
       
   143 int flib_netconn_send_setServerVar(flib_netconn *conn, const char *name, const char *value) {
       
   144 	if(log_badargs_if3(conn==NULL, flib_strempty(name), flib_strempty(value))) {
       
   145 		return -1;
       
   146 	}
       
   147 	return flib_netbase_sendf(conn->netBase, "%s\n%s\n%s\n\n", "SET_SERVER_VAR", name, value);
       
   148 }
       
   149 
       
   150 int flib_netconn_send_getServerVars(flib_netconn *conn) {
       
   151 	return sendVoid(conn, "GET_SERVER_VAR");
       
   152 }
       
   153 int flib_netconn_send_leaveRoom(flib_netconn *conn, const char *str) {
       
   154 	int result = -1;
       
   155 	if(conn->netconnState==NETCONN_STATE_ROOM) {
       
   156 		result = (str && *str) ? sendStr(conn, "PART", str) : sendVoid(conn, "PART");
       
   157 		if(!result) {
       
   158 			netconn_leaveRoom(conn);
       
   159 		}
       
   160 	}
       
   161 	return result;
       
   162 }
       
   163 
       
   164 int flib_netconn_send_toggleReady(flib_netconn *conn) {
       
   165 	return sendVoid(conn, "TOGGLE_READY");
       
   166 }
       
   167 
       
   168 static void addTeamToPendingList(flib_netconn *conn, const flib_team *team) {
       
   169 	flib_team *teamcopy = flib_team_copy(team);
       
   170 	if(teamcopy) {
       
   171 		teamcopy->remoteDriven = false;
       
   172 		free(teamcopy->ownerName);
       
   173 		teamcopy->ownerName = flib_strdupnull(conn->playerName);
       
   174 		if(teamcopy->ownerName) {
       
   175 			flib_teamlist_delete(&conn->pendingTeamlist, team->name);
       
   176 			if(!flib_teamlist_insert(&conn->pendingTeamlist, teamcopy, 0)) {
       
   177 				teamcopy = NULL;
       
   178 			}
       
   179 		}
       
   180 	}
       
   181 	flib_team_destroy(teamcopy);
       
   182 }
       
   183 
       
   184 int flib_netconn_send_addTeam(flib_netconn *conn, const flib_team *team) {
       
   185 	int result = -1;
       
   186 	if(!log_badargs_if2(conn==NULL, team==NULL)) {
       
   187 		bool missingInfo = flib_strempty(team->name) || flib_strempty(team->grave) || flib_strempty(team->fort) || flib_strempty(team->voicepack) || flib_strempty(team->flag);
       
   188 		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
       
   189 			missingInfo |= flib_strempty(team->hogs[i].name) || flib_strempty(team->hogs[i].hat);
       
   190 		}
       
   191 		if(!log_e_if(missingInfo, "Incomplete team definition")) {
       
   192 			flib_vector *vec = flib_vector_create();
       
   193 			if(vec) {
       
   194 				bool error = false;
       
   195 				error |= flib_vector_appendf(vec, "ADD_TEAM\n%s\n%i\n%s\n%s\n%s\n%s\n%i\n", team->name, team->colorIndex, team->grave, team->fort, team->voicepack, team->flag, team->hogs[0].difficulty);
       
   196 				for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
       
   197 					error |= flib_vector_appendf(vec, "%s\n%s\n", team->hogs[i].name, team->hogs[i].hat);
       
   198 				}
       
   199 				error |= flib_vector_appendf(vec, "\n");
       
   200 				if(!error && !flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec))) {
       
   201 					addTeamToPendingList(conn, team);
       
   202 					result = 0;
       
   203 				}
       
   204 			}
       
   205 			flib_vector_destroy(vec);
       
   206 		}
       
   207 	}
       
   208 	return result;
       
   209 }
       
   210 
       
   211 int flib_netconn_send_removeTeam(flib_netconn *conn, const char *teamname) {
       
   212 	flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
       
   213 	if(team && !team->remoteDriven && !sendStr(conn, "REMOVE_TEAM", teamname)) {
       
   214 		flib_teamlist_delete(&conn->teamlist, teamname);
       
   215 		return 0;
       
   216 	}
       
   217 	return -1;
       
   218 }
       
   219 
       
   220 int flib_netconn_send_renameRoom(flib_netconn *conn, const char *roomName) {
       
   221 	return sendStr(conn, "ROOM_NAME", roomName);
       
   222 }
       
   223 
       
   224 int flib_netconn_send_teamHogCount(flib_netconn *conn, const char *teamname, int hogcount) {
       
   225 	if(!log_badargs_if5(conn==NULL, flib_strempty(teamname), hogcount<1, hogcount>HEDGEHOGS_PER_TEAM, !conn->isChief)
       
   226 			&& !flib_netbase_sendf(conn->netBase, "HH_NUM\n%s\n%i\n\n", teamname, hogcount)) {
       
   227 		flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
       
   228 		if(team) {
       
   229 			team->hogsInGame = hogcount;
       
   230 		}
       
   231 		return 0;
       
   232 	}
       
   233 	return -1;
       
   234 }
       
   235 
       
   236 int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, int colorIndex) {
       
   237 	if(!log_badargs_if3(conn==NULL, flib_strempty(teamname), !conn->isChief)
       
   238 			&& !flib_netbase_sendf(conn->netBase, "TEAM_COLOR\n%s\n%i\n\n", teamname, colorIndex)) {
       
   239 		flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
       
   240 		if(team) {
       
   241 			team->colorIndex = colorIndex;
       
   242 		}
       
   243 		return 0;
       
   244 	}
       
   245 	return -1;
       
   246 }
       
   247 
       
   248 int flib_netconn_send_weaponset(flib_netconn *conn, const flib_weaponset *weaponset) {
       
   249 	if(!log_badargs_if3(conn==NULL, weaponset==NULL, flib_strempty(weaponset->name))) {
       
   250 		char ammostring[WEAPONS_COUNT*4+1];
       
   251 		strcpy(ammostring, weaponset->loadout);
       
   252 		strcat(ammostring, weaponset->crateprob);
       
   253 		strcat(ammostring, weaponset->delay);
       
   254 		strcat(ammostring, weaponset->crateammo);
       
   255 		if(conn->isChief) {
       
   256 			if(!flib_netbase_sendf(conn->netBase, "CFG\nAMMO\n%s\n%s\n\n", weaponset->name, ammostring)) {
       
   257 				netconn_setWeaponset(conn, weaponset);
       
   258 				return 0;
       
   259 			}
       
   260 		}
       
   261 	}
       
   262 	return -1;
       
   263 }
       
   264 
       
   265 int flib_netconn_send_map(flib_netconn *conn, const flib_map *map) {
       
   266 	if(log_badargs_if2(conn==NULL, map==NULL)) {
       
   267 		return -1;
       
   268 	}
       
   269 	bool error = false;
       
   270 
       
   271 	if(map->seed) {
       
   272 		error |= flib_netconn_send_mapSeed(conn, map->seed);
       
   273 	}
       
   274 	error |= flib_netconn_send_mapTemplate(conn, map->templateFilter);
       
   275 	if(map->theme) {
       
   276 		error |= flib_netconn_send_mapTheme(conn, map->theme);
       
   277 	}
       
   278 	error |= flib_netconn_send_mapGen(conn, map->mapgen);
       
   279 	error |= flib_netconn_send_mapMazeSize(conn, map->mazeSize);
       
   280 	if(map->drawData && map->drawDataSize>0) {
       
   281 		error |= flib_netconn_send_mapDrawdata(conn, map->drawData, map->drawDataSize);
       
   282 	}
       
   283 	// Name is sent last, because the QtFrontend uses this to update its preview, and to show/hide
       
   284 	// certain fields
       
   285 	if(map->name) {
       
   286 		error |= flib_netconn_send_mapName(conn, map->name);
       
   287 	}
       
   288 	return error;
       
   289 }
       
   290 
       
   291 int flib_netconn_send_mapName(flib_netconn *conn, const char *mapName) {
       
   292 	if(log_badargs_if2(conn==NULL, mapName==NULL)) {
       
   293 		return -1;
       
   294 	}
       
   295 	if(conn->isChief) {
       
   296 		if(!sendStr(conn, "CFG\nMAP", mapName)) {
       
   297 			char *copy = flib_strdupnull(mapName);
       
   298 			if(copy) {
       
   299 				free(conn->map->name);
       
   300 				conn->map->name = copy;
       
   301 				return 0;
       
   302 			}
       
   303 		}
       
   304 	}
       
   305 	return -1;
       
   306 }
       
   307 
       
   308 int flib_netconn_send_mapGen(flib_netconn *conn, int mapGen) {
       
   309 	if(log_badargs_if(conn==NULL)) {
       
   310 		return -1;
       
   311 	}
       
   312 	if(conn->isChief) {
       
   313 		if(!sendInt(conn, "CFG\nMAPGEN", mapGen)) {
       
   314 			conn->map->mapgen = mapGen;
       
   315 			return 0;
       
   316 		}
       
   317 	}
       
   318 	return -1;
       
   319 }
       
   320 
       
   321 int flib_netconn_send_mapTemplate(flib_netconn *conn, int templateFilter) {
       
   322 	if(log_badargs_if(conn==NULL)) {
       
   323 		return -1;
       
   324 	}
       
   325 	if(conn->isChief) {
       
   326 		if(!sendInt(conn, "CFG\nTEMPLATE", templateFilter)) {
       
   327 			conn->map->templateFilter = templateFilter;
       
   328 			return 0;
       
   329 		}
       
   330 	}
       
   331 	return -1;
       
   332 }
       
   333 
       
   334 int flib_netconn_send_mapMazeSize(flib_netconn *conn, int mazeSize) {
       
   335 	if(log_badargs_if(conn==NULL)) {
       
   336 		return -1;
       
   337 	}
       
   338 	if(conn->isChief) {
       
   339 		if(!sendInt(conn, "CFG\nMAZE_SIZE", mazeSize)) {
       
   340 			conn->map->mazeSize = mazeSize;
       
   341 			return 0;
       
   342 		}
       
   343 	}
       
   344 	return -1;
       
   345 }
       
   346 
       
   347 int flib_netconn_send_mapSeed(flib_netconn *conn, const char *seed) {
       
   348 	if(log_badargs_if2(conn==NULL, seed==NULL)) {
       
   349 		return -1;
       
   350 	}
       
   351 	if(conn->isChief) {
       
   352 		if(!sendStr(conn, "CFG\nSEED", seed)) {
       
   353 			char *copy = flib_strdupnull(seed);
       
   354 			if(copy) {
       
   355 				free(conn->map->seed);
       
   356 				conn->map->seed = copy;
       
   357 				return 0;
       
   358 			}
       
   359 		}
       
   360 	}
       
   361 	return -1;
       
   362 }
       
   363 
       
   364 int flib_netconn_send_mapTheme(flib_netconn *conn, const char *theme) {
       
   365 	if(log_badargs_if2(conn==NULL, theme==NULL)) {
       
   366 		return -1;
       
   367 	}
       
   368 	if(conn->isChief) {
       
   369 		if(!sendStr(conn, "CFG\nTHEME", theme)) {
       
   370 			char *copy = flib_strdupnull(theme);
       
   371 			if(copy) {
       
   372 				free(conn->map->theme);
       
   373 				conn->map->theme = copy;
       
   374 				return 0;
       
   375 			}
       
   376 		}
       
   377 	}
       
   378 	return -1;
       
   379 }
       
   380 
       
   381 int flib_netconn_send_mapDrawdata(flib_netconn *conn, const uint8_t *drawData, size_t size) {
       
   382 	int result = -1;
       
   383 	if(!log_badargs_if3(conn==NULL, drawData==NULL && size>0, size>SIZE_MAX/2) && conn->isChief) {
       
   384 		uLongf zippedSize = compressBound(size);
       
   385 		uint8_t *zipped = flib_malloc(zippedSize+4); // 4 extra bytes for header
       
   386 		if(zipped) {
       
   387 			// Create the QCompress size header (uint32 big endian)
       
   388 			zipped[0] = (size>>24) & 0xff;
       
   389 			zipped[1] = (size>>16) & 0xff;
       
   390 			zipped[2] = (size>>8) & 0xff;
       
   391 			zipped[3] = (size) & 0xff;
       
   392 
       
   393 			if(compress(zipped+4, &zippedSize, drawData, size) != Z_OK) {
       
   394 				flib_log_e("Error compressing drawn map data.");
       
   395 			} else {
       
   396 				char *base64encout = NULL;
       
   397 				base64_encode_alloc((const char*)zipped, zippedSize+4, &base64encout);
       
   398 				if(!base64encout) {
       
   399 					flib_log_e("Error base64-encoding drawn map data.");
       
   400 				} else {
       
   401 					result = flib_netbase_sendf(conn->netBase, "CFG\nDRAWNMAP\n%s\n\n", base64encout);
       
   402 				}
       
   403 				free(base64encout);
       
   404 			}
       
   405 		}
       
   406 		free(zipped);
       
   407 	}
       
   408 
       
   409 	if(!result) {
       
   410 		uint8_t *copy = flib_bufdupnull(drawData, size);
       
   411 		if(copy) {
       
   412 			free(conn->map->drawData);
       
   413 			conn->map->drawData = copy;
       
   414 			conn->map->drawDataSize = size;
       
   415 		}
       
   416 	}
       
   417 	return result;
       
   418 }
       
   419 
       
   420 int flib_netconn_send_script(flib_netconn *conn, const char *scriptName) {
       
   421 	if(log_badargs_if2(conn==NULL, scriptName==NULL)) {
       
   422 		return -1;
       
   423 	}
       
   424 	if(conn->isChief) {
       
   425 		if(!sendStr(conn, "CFG\nSCRIPT", scriptName)) {
       
   426 			netconn_setScript(conn, scriptName);
       
   427 			return 0;
       
   428 		}
       
   429 	}
       
   430 	return -1;
       
   431 }
       
   432 
       
   433 int flib_netconn_send_scheme(flib_netconn *conn, const flib_scheme *scheme) {
       
   434 	int result = -1;
       
   435 	if(!log_badargs_if3(conn==NULL, scheme==NULL, flib_strempty(scheme->name)) && conn->isChief) {
       
   436 		flib_vector *vec = flib_vector_create();
       
   437 		if(vec) {
       
   438 			bool error = false;
       
   439 			error |= flib_vector_appendf(vec, "CFG\nSCHEME\n%s\n", scheme->name);
       
   440 			for(int i=0; i<flib_meta.modCount; i++) {
       
   441 				error |= flib_vector_appendf(vec, "%s\n", scheme->mods[i] ? "true" : "false");
       
   442 			}
       
   443 			for(int i=0; i<flib_meta.settingCount; i++) {
       
   444 				error |= flib_vector_appendf(vec, "%i\n", scheme->settings[i]);
       
   445 			}
       
   446 			error |= flib_vector_appendf(vec, "\n");
       
   447 			if(!error) {
       
   448 				result = flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec));
       
   449 			}
       
   450 		}
       
   451 		flib_vector_destroy(vec);
       
   452 	}
       
   453 
       
   454 	if(!result) {
       
   455 		netconn_setScheme(conn, scheme);
       
   456 	}
       
   457 	return result;
       
   458 }
       
   459 
       
   460 int flib_netconn_send_startGame(flib_netconn *conn) {
       
   461 	return sendVoid(conn, "START_GAME");
       
   462 }
       
   463 
       
   464 int flib_netconn_send_toggleRestrictJoins(flib_netconn *conn) {
       
   465 	return sendVoid(conn, "TOGGLE_RESTRICT_JOINS");
       
   466 }
       
   467 
       
   468 int flib_netconn_send_toggleRestrictTeams(flib_netconn *conn) {
       
   469 	return sendVoid(conn, "TOGGLE_RESTRICT_TEAMS");
       
   470 }
       
   471 
       
   472 int flib_netconn_send_teamchat(flib_netconn *conn, const char *chat) {
       
   473 	if(!flib_strempty(chat)) {
       
   474 		return sendStr(conn, "TEAMCHAT", chat);
       
   475 	}
       
   476 	return 0;
       
   477 }
       
   478 
       
   479 int flib_netconn_send_engineMessage(flib_netconn *conn, const uint8_t *message, size_t size) {
       
   480 	int result = -1;
       
   481 	if(!log_badargs_if2(conn==NULL, message==NULL && size>0)) {
       
   482 		char *base64encout = NULL;
       
   483 		base64_encode_alloc((const char*)message, size, &base64encout);
       
   484 		if(base64encout) {
       
   485 			result = flib_netbase_sendf(conn->netBase, "EM\n%s\n\n", base64encout);
       
   486 		}
       
   487 		free(base64encout);
       
   488 	}
       
   489 	return result;
       
   490 }
       
   491 
       
   492 int flib_netconn_send_roundfinished(flib_netconn *conn, bool withoutError) {
       
   493 	return sendInt(conn, "ROUNDFINISHED", withoutError ? 1 : 0);
       
   494 }
       
   495