|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 #include <zlib.h> 00032 00037 void SockList_AddString(SockList *sl, const char *data) 00038 { 00039 char c; 00040 00041 while ((c = *data++)) 00042 { 00043 sl->buf[sl->len] = c; 00044 sl->len++; 00045 } 00046 00047 sl->buf[sl->len] = c; 00048 sl->len++; 00049 } 00050 00059 char *GetString_String(uint8 *data, int len, int *pos, char *dest, size_t dest_size) 00060 { 00061 size_t i = 0; 00062 char c; 00063 00064 while (*pos < len && (c = (char) (data[(*pos)++]))) 00065 { 00066 if (i < dest_size - 1) 00067 { 00068 dest[i++] = c; 00069 } 00070 } 00071 00072 dest[i] = '\0'; 00073 return dest; 00074 } 00075 00081 int SockList_ReadPacket(socket_struct *ns, int len) 00082 { 00083 SockList *sl = &ns->readbuf; 00084 int stat_ret; 00085 00086 #ifdef WIN32 00087 stat_ret = recv(ns->fd, sl->buf + sl->len, len - sl->len, 0); 00088 #else 00089 do 00090 { 00091 stat_ret = read(ns->fd, sl->buf + sl->len, len - sl->len); 00092 } 00093 while (stat_ret == -1 && errno == EINTR); 00094 #endif 00095 00096 if (stat_ret == 0) 00097 { 00098 return -1; 00099 } 00100 00101 if (stat_ret > 0) 00102 { 00103 sl->len += stat_ret; 00104 #if CS_LOGSTATS 00105 cst_tot.ibytes += stat_ret; 00106 cst_lst.ibytes += stat_ret; 00107 #endif 00108 } 00109 else if (stat_ret < 0) 00110 { 00111 #ifdef WIN32 00112 if (WSAGetLastError() != WSAEWOULDBLOCK) 00113 { 00114 if (WSAGetLastError() == WSAECONNRESET) 00115 { 00116 LOG(llevDebug, "Connection closed by client.\n"); 00117 } 00118 else 00119 { 00120 LOG(llevDebug, "SockList_ReadPacket() got error %d, returning %d.\n", WSAGetLastError(), stat_ret); 00121 } 00122 00123 return stat_ret; 00124 } 00125 #else 00126 if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) 00127 { 00128 LOG(llevDebug, "SockList_ReadPacket() got error %d: %s, returning %d.\n", errno, strerror_local(errno), stat_ret); 00129 return stat_ret; 00130 } 00131 #endif 00132 } 00133 00134 return 1; 00135 } 00136 00142 int SockList_ReadCommand(SockList *sl, SockList *sl2) 00143 { 00144 int toread, ret = 0; 00145 00146 sl2->buf[0] = '\0'; 00147 sl2->len = 0; 00148 00149 /* Is there anything in our buffer that was read 00150 * before? */ 00151 if (sl->len >= 2) 00152 { 00153 /* Length of the command. */ 00154 toread = 2 + (sl->buf[0] << 8) + sl->buf[1]; 00155 00156 /* If we have a command, copy it over. */ 00157 if (toread <= sl->len) 00158 { 00159 memcpy(sl2->buf, sl->buf, toread); 00160 sl2->len = toread; 00161 00162 if (sl->len - toread) 00163 { 00164 memmove(sl->buf, sl->buf + toread, sl->len - toread); 00165 } 00166 00167 sl->len -= toread; 00168 ret = toread; 00169 } 00170 } 00171 00172 return ret; 00173 } 00174 00178 void socket_enable_no_delay(int fd) 00179 { 00180 int tmp = 1; 00181 00182 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, sizeof(tmp))) 00183 { 00184 LOG(llevDebug, "socket_enable_no_delay(): Cannot enable TCP_NODELAY: %s\n", strerror_local(errno)); 00185 } 00186 } 00187 00191 void socket_disable_no_delay(int fd) 00192 { 00193 int tmp = 0; 00194 00195 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, sizeof(tmp))) 00196 { 00197 LOG(llevDebug, "socket_disable_no_delay(): Cannot disable TCP_NODELAY: %s\n", strerror_local(errno)); 00198 } 00199 } 00200 00207 static void socket_buffer_enqueue(socket_struct *ns, unsigned char *buf, size_t len, uint8 ndelay) 00208 { 00209 socket_buffer *buffer = (socket_buffer *) malloc(sizeof(socket_buffer)); 00210 00211 buffer->buf = (char *) malloc(len + 1); 00212 memcpy(buffer->buf, buf, len); 00213 buffer->len = len; 00214 buffer->next = NULL; 00215 buffer->pos = 0; 00216 buffer->ndelay = ndelay; 00217 00218 if (ns->buffer_front) 00219 { 00220 ns->buffer_front->last = buffer; 00221 buffer->next = ns->buffer_front; 00222 buffer->last = NULL; 00223 ns->buffer_front = buffer; 00224 } 00225 else 00226 { 00227 ns->buffer_back = ns->buffer_front = buffer; 00228 buffer->next = buffer->last = NULL; 00229 } 00230 } 00231 00235 static void socket_buffer_dequeue(socket_struct *ns) 00236 { 00237 socket_buffer *tmp = ns->buffer_back; 00238 00239 ns->buffer_back = ns->buffer_back->last; 00240 00241 if (ns->buffer_back) 00242 { 00243 ns->buffer_back->next = NULL; 00244 } 00245 else 00246 { 00247 ns->buffer_front = NULL; 00248 } 00249 00250 free(tmp->buf); 00251 free(tmp); 00252 } 00253 00257 void socket_buffer_clear(socket_struct *ns) 00258 { 00259 while (ns->buffer_back) 00260 { 00261 socket_buffer_dequeue(ns); 00262 } 00263 } 00264 00268 void socket_buffer_write(socket_struct *ns) 00269 { 00270 int amt, max; 00271 00272 /* Nothing to send? */ 00273 if (!ns->buffer_back) 00274 { 00275 return; 00276 } 00277 00278 while (ns->buffer_back) 00279 { 00280 if (ns->buffer_back->ndelay) 00281 { 00282 socket_enable_no_delay(ns->fd); 00283 } 00284 00285 max = ns->buffer_back->len - ns->buffer_back->pos; 00286 amt = send(ns->fd, ns->buffer_back->buf + ns->buffer_back->pos, max, MSG_DONTWAIT); 00287 00288 if (ns->buffer_back->ndelay) 00289 { 00290 socket_disable_no_delay(ns->fd); 00291 } 00292 00293 #ifndef WIN32 00294 if (!amt) 00295 { 00296 amt = max; 00297 } 00298 else 00299 #endif 00300 if (amt < 0) 00301 { 00302 #ifdef WIN32 00303 if (WSAGetLastError() != WSAEWOULDBLOCK) 00304 { 00305 LOG(llevDebug, "socket_buffer_write(): New socket write failed (%d).\n", WSAGetLastError()); 00306 #else 00307 if (errno != EWOULDBLOCK) 00308 { 00309 LOG(llevDebug, "socket_buffer_write(): New socket write failed (%d: %s).\n", errno, strerror_local(errno)); 00310 #endif 00311 ns->status = Ns_Dead; 00312 return; 00313 } 00314 /* EWOULDBLOCK: We can't write because socket is busy. */ 00315 else 00316 { 00317 return; 00318 } 00319 } 00320 00321 ns->buffer_back->pos += amt; 00322 #if CS_LOGSTATS 00323 cst_tot.obytes += amt; 00324 cst_lst.obytes += amt; 00325 #endif 00326 00327 if (ns->buffer_back->len - ns->buffer_back->pos == 0) 00328 { 00329 socket_buffer_dequeue(ns); 00330 } 00331 } 00332 } 00333 00341 void Send_With_Handling(socket_struct *ns, SockList *msg) 00342 { 00343 unsigned char sbuf[4]; 00344 uint8 *buf; 00345 size_t len; 00346 #if COMPRESS_DATA_PACKETS 00347 uint8 *dest = NULL; 00348 #endif 00349 00350 if (ns->status == Ns_Dead || !msg) 00351 { 00352 return; 00353 } 00354 00355 buf = msg->buf; 00356 len = msg->len; 00357 00358 #if COMPRESS_DATA_PACKETS 00359 if (len > COMPRESS_DATA_PACKETS_SIZE && buf[0] != BINARY_CMD_DATA) 00360 { 00361 size_t new_size = compressBound(len); 00362 00363 dest = malloc(new_size + 5); 00364 /* Marker for the reserved #0 binary command. */ 00365 dest[0] = 0; 00366 /* Add original length of the packet. */ 00367 dest[1] = (len >> 24) & 0xff; 00368 dest[2] = (len >> 16) & 0xff; 00369 dest[3] = (len >> 8) & 0xff; 00370 dest[4] = (len) & 0xff; 00371 /* Compress it. */ 00372 compress2((Bytef *) dest + 5, (uLong *) &new_size, (const unsigned char FAR *) buf, len, Z_BEST_COMPRESSION); 00373 buf = dest; 00374 len = new_size + 5; 00375 } 00376 #endif 00377 00378 /* If more than 32kb use 3 bytes header and set the high bit to show 00379 * it to the client. */ 00380 if (len > 32 * 1024 - 1) 00381 { 00382 sbuf[0] = ((uint32) (len) >> 16) & 0xFF; 00383 /* High bit marker for the client */ 00384 sbuf[0] |= 0x80; 00385 sbuf[1] = ((uint32) (len) >> 8) & 0xFF; 00386 sbuf[2] = ((uint32) (len)) & 0xFF; 00387 00388 socket_buffer_enqueue(ns, sbuf, 3, 0); 00389 } 00390 else 00391 { 00392 sbuf[0] = ((uint32) (len) >> 8) & 0xFF; 00393 sbuf[1] = ((uint32) (len)) & 0xFF; 00394 00395 socket_buffer_enqueue(ns, sbuf, 2, 0); 00396 } 00397 00398 socket_buffer_enqueue(ns, buf, len, msg->buf[0] == BINARY_CMD_MAP2 || msg->buf[0] == BINARY_CMD_ITEMY); 00399 00400 #if COMPRESS_DATA_PACKETS 00401 /* Free the buffer that was used for compression, if it was allocated. */ 00402 if (dest) 00403 { 00404 free(dest); 00405 } 00406 #endif 00407 } 00408 00412 void Write_String_To_Socket(socket_struct *ns, char cmd, const char *buf, int len) 00413 { 00414 SockList sl; 00415 00416 sl.len = len; 00417 sl.buf = (uint8 *) buf; 00418 *((char *) buf) = cmd; 00419 00420 Send_With_Handling(ns, &sl); 00421 } 00422 00423 #if CS_LOGSTATS 00424 00426 CS_Stats cst_tot; 00427 00429 CS_Stats cst_lst; 00430 00435 void write_cs_stats() 00436 { 00437 time_t now = time(NULL); 00438 00439 /* If no connections recently, don't bother to log anything */ 00440 if (cst_lst.ibytes == 0 && cst_lst.obytes == 0) 00441 { 00442 return; 00443 } 00444 00445 /* CSSTAT is put in so scripts can easily find the line */ 00446 LOG(llevInfo, "CSSTAT: %.16s tot in:%d out:%d maxc:%d time:%lu last block-> in:%d out:%d maxc:%d time:%lu\n", ctime(&now), cst_tot.ibytes, cst_tot.obytes, cst_tot.max_conn, now - cst_tot.time_start, cst_lst.ibytes, cst_lst.obytes, cst_lst.max_conn, now - cst_lst.time_start); 00447 00448 cst_lst.ibytes = 0; 00449 cst_lst.obytes = 0; 00450 cst_lst.max_conn = socket_info.nconns; 00451 cst_lst.time_start = now; 00452 } 00453 #endif
1.7.4