static int csend(int nr,unsigned char *buf,int len) { int size; if (!player[nr]) return -1; while (len) { if (player[nr]->iptr>=player[nr]->optr) { size=OBUFSIZE-player[nr]->iptr; } else { size=player[nr]->optr-player[nr]->iptr; } size=min(size,len); memcpy(player[nr]->obuf+player[nr]->iptr,buf,size); player[nr]->iptr+=size; if (player[nr]->iptr==OBUFSIZE) player[nr]->iptr=0; buf+=size; len-=size; if (player[nr]->iptr==player[nr]->optr) { //xlog("send buffer overflow, kicking player %d",nr); kick_player(nr,NULL); return -1; } //xlog("add: iptr=%d, optr=%d, len=%d, size=%d",player[nr]->iptr,player[nr]->optr,len,size); } return 0; }
static void send_player(int nr) { int ret,len; unsigned long long prof; if (player[nr]->iptr<player[nr]->optr) { len=OBUFSIZE-player[nr]->optr; } else { len=player[nr]->iptr-player[nr]->optr; } //xlog("rem: iptr=%d, optr=%d, len=%d",player[nr]->iptr,player[nr]->optr,len); prof=prof_start(11); ret=send(player[nr]->sock,player[nr]->obuf+player[nr]->optr,len,0); prof_stop(11,prof); if (ret==-1) { // send failure //xlog("send failure, kicking player %d",nr); kick_player(nr,NULL); return; } player[nr]->optr+=ret; if (player[nr]->optr==OBUFSIZE) player[nr]->optr=0; sent_bytes_raw+=ret+60; sent_bytes+=ret; }
// careful here, any csend might clear player[n]! void pflush(void) { int n,ilen,olen,csize,ret,olow,ohigh; unsigned char obuf[OBUFSIZE]; unsigned long long prof; for (n=1; n<MAXPLAYER; n++) { if (!player[n]) continue; ilen=player[n]->tptr; if (ilen>16) { player[n]->zs.next_in=player[n]->tbuf; player[n]->zs.avail_in=ilen; player[n]->zs.next_out=obuf; player[n]->zs.avail_out=OBUFSIZE; prof=prof_start(12); ret=deflate(&player[n]->zs,Z_SYNC_FLUSH); prof_stop(12,prof); if (ret!=Z_OK) { elog("compression failure #1, kicking player %d",n); kick_player(n,NULL); continue; } if (player[n]->zs.avail_in) { elog("compression failure #2, kicking player %d",n); kick_player(n,NULL); continue; } csize=OBUFSIZE-player[n]->zs.avail_out; olen=(csize); if (olen>63) { ohigh=(olen>>8)|0x80; olow=olen&255; csend(n,(void*)(&ohigh),1); csend(n,(void*)(&olow),1); } else {
void psend(int nr,char *buf,int len) { if (!player[nr]) return; if (player[nr]->tptr+len>=OBUFSIZE) { xlog("tptr overflow!"); kick_player(nr,NULL); return; } memcpy(player[nr]->tbuf+player[nr]->tptr,buf,len); player[nr]->tptr+=len; }
static void rec_player(int nr) { int len; len=recv(player[nr]->sock,(char*)player[nr]->inbuf+player[nr]->in_len,256-player[nr]->in_len,0); if (len<1) { // receive failure if (errno!=EWOULDBLOCK) { //xlog("receive failure, kicking player %d",nr); kick_player(nr,NULL); } return; } player[nr]->in_len+=len; rec_bytes_raw+=len+60; rec_bytes+=len; }
/* true return value indicates that connection must be closed */ int process_msg(int fd, char* msg) { int client_proto_major; int client_proto_minor; char * args; char * ptr, * ptr2; char * msg_orig; /* check for leading protocol tag */ if (!str_begins_static_str(msg, "FB/") || strlen(msg) < 8) { // 8 stands for "FB/M.m f"(oo) send_line_log(fd, fl_line_unrecognized, msg); return 1; } /* check if client protocol is compatible; for simplicity, we don't support client protocol more recent * than server protocol, we suppose that our servers are upgraded when a new release appears (but of * course client protocol older is supported within the major protocol) */ client_proto_major = charstar_to_int(msg + 3); client_proto_minor = charstar_to_int(msg + 5); if (client_proto_major != proto_major || client_proto_minor > proto_minor) { send_line_log(fd, fl_proto_mismatch, msg); return 1; } if (remote_proto_minor[fd] == -1) remote_proto_minor[fd] = client_proto_minor; msg_orig = strdup(msg); /* after protocol, first word is command, then possible args */ current_command = msg + 7; // 7 stands for "FB/M.m " if ((ptr = strchr(current_command, ' '))) { *ptr = '\0'; args = current_command + strlen(current_command) + 1; } else args = NULL; if (streq(current_command, "PING")) { send_line_log(fd, ok_pong, msg_orig); } else if (streq(current_command, "NICK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!is_nick_ok(args)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else { if (nick[fd] != NULL) { free(nick[fd]); } nick[fd] = strdup(args); calculate_list_games(); send_ok(fd, msg_orig); } } } else if (streq(current_command, "GEOLOC")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 13) // sign, 4 digits, dot, colon, sign, 4 digits, dot args[13] = '\0'; if (geoloc[fd] != NULL) { free(geoloc[fd]); } geoloc[fd] = strdup(args); calculate_list_games(); send_ok(fd, msg_orig); } } else if (streq(current_command, "CREATE")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!is_nick_ok(args)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else if (!nick_available(args)) { send_line_log(fd, wn_nick_in_use, msg_orig); } else if (already_in_game(fd)) { send_line_log(fd, wn_already_in_game, msg_orig); } else if (games_open == 16) { // FB client can display 16 max send_line_log(fd, wn_max_open_games, msg_orig); } else { create_game(fd, strdup(args)); send_ok(fd, msg_orig); } } } else if (streq(current_command, "JOIN")) { if (!args || !(ptr = strchr(args, ' '))) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { struct game * g; char* nick = ptr + 1; *ptr = '\0'; if ((ptr2 = strchr(ptr, ' '))) *ptr2 = '\0'; if (strlen(nick) > 10) nick[10] = '\0'; if (!is_nick_ok(nick)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else if (!nick_available(nick)) { send_line_log(fd, wn_nick_in_use, msg_orig); } else if (already_in_game(fd)) { send_line_log(fd, wn_already_in_game, msg_orig); } else if (!(g = find_game_by_nick(args))) { send_line_log(fd, wn_no_such_game, msg_orig); } else { if (add_player(g, fd, strdup(nick))) send_ok(fd, msg_orig); else send_line_log(fd, wn_game_full, msg_orig); } } } else if (streq(current_command, "KICK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { struct game * g = find_game_by_fd(fd); if (g->players_conn[0] != fd) { send_line_log(fd, wn_not_creator, msg_orig); } else { kick_player(fd, g, args); } } } } else if (streq(current_command, "PART")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { player_part_game(fd); send_ok(fd, msg_orig); } } else if (streq(current_command, "LIST")) { send_line_log(fd, list_games_str, msg_orig); } else if (streq(current_command, "STATUS")) { // 1.0 command if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { status(fd, msg_orig); } } else if (streq(current_command, "STATUSGEO")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { status_geo(fd, msg_orig); } } else if (streq(current_command, "PROTOCOL_LEVEL")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { protocol_level(fd, msg_orig); } } else if (streq(current_command, "TALK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { talk(fd, args); } } else if (streq(current_command, "START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { start_game(fd); } } else if (streq(current_command, "CLOSE")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { close_game(fd); } } else if (streq(current_command, "SETOPTIONS")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { setoptions(fd, args); } } else if (streq(current_command, "LEADER_CHECK_GAME_START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { leader_check_game_start(fd); } } else if (streq(current_command, "OK_GAME_START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { ok_start_game(fd); } } else if (streq(current_command, "ADMIN_REREAD")) { if (!admin_authorized[fd]) { send_line_log(fd, wn_denied, msg_orig); } else { reread(); send_ok(fd, "ADMIN_REREAD"); } } else { send_line_log(fd, wn_unknown_command, msg); } free(msg_orig); current_command = NULL; return 0; }