Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_common_newsocket_c = 00002 "$Id: newsocket.c 9428 2008-07-08 06:31:53Z mwedel $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire-devel@real-time.com 00023 */ 00024 00025 /* Made this either client or server specific for 0.95.2 release - getting 00026 * too complicated to keep them the same, and the common code is pretty much 00027 * frozen now. 00028 */ 00029 00030 00031 #include <stdio.h> 00032 #include <stdarg.h> 00033 #include <errno.h> 00034 00035 #include <client.h> 00036 #include <newclient.h> 00037 #include <script.h> 00038 00039 /* The LOG function is normally part of the libcross. If client compile, 00040 * we need to supply something since some of the common code calls this. 00041 */ 00042 /*void LOG (int logLevel, char *format, ...) 00043 { 00044 #ifdef DEBUG 00045 va_list ap; 00046 va_start(ap, format); 00047 vfprintf(stderr, format, ap); 00048 va_end(ap); 00049 #endif 00050 }*/ 00051 00052 00053 #define llevDebug LOG_DEBUG 00054 #define llevError LOG_ERROR 00055 00056 00057 /* 00058 * This writes data to the socket. 00059 */ 00060 static int write_socket(int fd, const unsigned char *buf, int len) 00061 { 00062 int amt=0; 00063 const unsigned char *pos=buf; 00064 00065 /* If we manage to write more than we wanted, take it as a bonus */ 00066 while (len>0) { 00067 do { 00068 #ifndef WIN32 00069 amt=write(fd, pos, len); 00070 } while ((amt<0) && ((errno==EINTR) || (errno=EAGAIN))); 00071 #else 00072 amt=send(fd, pos, len, 0); 00073 } while ((amt<0) && (WSAGetLastError()==EINTR)); 00074 #endif 00075 00076 if (amt < 0) { /* We got an error */ 00077 LOG(llevError,"write_socket","New socket (fd=%d) write failed: %s.\n", fd, strerror(errno)); 00078 return -1; 00079 } 00080 if (amt==0) { 00081 LOG(llevError,"write_socket","Write_To_Socket: No data written out.\n"); 00082 } 00083 len -= amt; 00084 pos += amt; 00085 } 00086 return 0; 00087 } 00088 00089 00090 00091 void SockList_Init(SockList *sl, uint8 *buf) 00092 { 00093 sl->len=0; 00094 sl->buf=buf + 2; /* reserve two bytes for total length */ 00095 } 00096 00097 void SockList_AddChar(SockList *sl, char c) 00098 { 00099 sl->buf[sl->len++]=c; 00100 } 00101 00102 void SockList_AddShort(SockList *sl, uint16 data) 00103 { 00104 sl->buf[sl->len++] = (data>>8)&0xff; 00105 sl->buf[sl->len++] = data & 0xff; 00106 } 00107 00108 00109 void SockList_AddInt(SockList *sl, uint32 data) 00110 { 00111 sl->buf[sl->len++] = (data>>24)&0xff; 00112 sl->buf[sl->len++] = (data>>16)&0xff; 00113 sl->buf[sl->len++] = (data>>8)&0xff; 00114 sl->buf[sl->len++] = data & 0xff; 00115 } 00116 00117 void SockList_AddString(SockList *sl, const char *str) 00118 { 00119 int len = strlen(str); 00120 00121 if (sl->len + len > MAX_BUF-2) 00122 len = MAX_BUF-2 - sl->len; 00123 memcpy(sl->buf + sl->len, str, len); 00124 sl->len += len; 00125 } 00126 00127 int SockList_Send(SockList *sl, int fd) 00128 { 00129 sl->buf[-2] = sl->len / 256; 00130 sl->buf[-1] = sl->len % 256; 00131 00132 return write_socket(fd, sl->buf-2, sl->len+2); 00133 } 00134 00135 00136 char GetChar_String(const unsigned char *data) 00137 { 00138 return (data[0]); 00139 } 00140 /* Basically does the reverse of SockList_AddInt, but on 00141 * strings instead. Same for the GetShort, but for 16 bits. 00142 */ 00143 int GetInt_String(const unsigned char *data) 00144 { 00145 return ((data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]); 00146 } 00147 00148 /* 64 bit version of the above */ 00149 sint64 GetInt64_String(const unsigned char *data) 00150 { 00151 #ifdef WIN32 00152 return (((sint64)data[0]<<56) + ((sint64)data[1]<<48) + 00153 ((sint64)data[2]<<40) + ((sint64)data[3]<<32) + 00154 ((sint64)data[4]<<24) + ((sint64)data[5]<<16) + ((sint64)data[6]<<8) + (sint64)data[7]); 00155 #else 00156 return (((uint64)data[0]<<56) + ((uint64)data[1]<<48) + 00157 ((uint64)data[2]<<40) + ((uint64)data[3]<<32) + 00158 ((uint64)data[4]<<24) + (data[5]<<16) + (data[6]<<8) + data[7]); 00159 #endif 00160 } 00161 00162 short GetShort_String(const unsigned char *data) { 00163 return ((data[0]<<8)+data[1]); 00164 } 00165 00166 /* This reads from fd and puts the data in sl. We return true if we think we 00167 * have a full packet, 0 if we have a partial packet, or -1 if an error 00168 * occurred. The only processing we do is remove the initial size value. len 00169 * (As passed) is the size of the buffer allocated in the socklist. We make 00170 * the assumption the buffer is at least 2 bytes long. 00171 */ 00172 00173 int SockList_ReadPacket(int fd, SockList *sl, int len) 00174 { 00175 int stat,toread,readsome=0; 00176 00177 /* We already have a partial packet */ 00178 if (sl->len<2) { 00179 do { 00180 #ifndef WIN32 00181 stat=read(fd, sl->buf + sl->len, 2-sl->len); 00182 } while ((stat==-1) && (errno==EINTR)); 00183 #else 00184 stat=recv(fd, sl->buf + sl->len, 2-sl->len, 0); 00185 } while ((stat==-1) && (WSAGetLastError()==EINTR)); 00186 #endif 00187 if (stat<0) { 00188 /* In non blocking mode, EAGAIN is set when there is no 00189 * data available. 00190 */ 00191 #ifndef WIN32 00192 if (errno!=EAGAIN && errno!=EWOULDBLOCK) { 00193 #else 00194 if (WSAGetLastError()!=EAGAIN && WSAGetLastError()!=WSAEWOULDBLOCK) { 00195 #endif 00196 perror("ReadPacket got an error."); 00197 LOG(llevDebug,"SockList_ReadPacket","ReadPacket got error %d, returning -1",errno); 00198 return -1; 00199 } 00200 return 0; /*Error */ 00201 } 00202 if (stat==0) return -1; 00203 sl->len += stat; 00204 #ifdef CS_LOGSTATS 00205 cst_tot.ibytes += stat; 00206 cst_lst.ibytes += stat; 00207 #endif 00208 if (stat<2) return 0; /* Still don't have a full packet */ 00209 readsome=1; 00210 } 00211 /* Figure out how much more data we need to read. Add 2 from the 00212 * end of this - size header information is not included. 00213 */ 00214 toread = 2+(sl->buf[0] << 8) + sl->buf[1] - sl->len; 00215 if ((toread + sl->len) > len) { 00216 LOG(llevError,"SockList_ReadPacket","Want to read more bytes than will fit in buffer.\n"); 00217 /* return error so the socket is closed */ 00218 return -1; 00219 } 00220 do { 00221 do { 00222 #ifndef WIN32 00223 stat = read(fd, sl->buf+ sl->len, toread); 00224 } while ((stat<0) && (errno==EINTR)); 00225 #else 00226 stat = recv(fd, sl->buf+ sl->len, toread, 0); 00227 } while ((stat<0) && (WSAGetLastError()==EINTR)); 00228 #endif 00229 if (stat<0) { 00230 #ifndef WIN32 00231 if (errno!=EAGAIN && errno!=EWOULDBLOCK) { 00232 #else 00233 if (WSAGetLastError()!=EAGAIN && WSAGetLastError()!=WSAEWOULDBLOCK) { 00234 #endif 00235 perror("ReadPacket got an error."); 00236 LOG(llevDebug,"SockList_ReadPacket","ReadPacket got error %d, returning 0",errno); 00237 } 00238 return 0; /*Error */ 00239 } 00240 if (stat==0) return -1; 00241 sl->len += stat; 00242 #ifdef CS_LOGSTATS 00243 cst_tot.ibytes += stat; 00244 cst_lst.ibytes += stat; 00245 #endif 00246 toread -= stat; 00247 if (toread==0) return 1; 00248 if (toread < 0) { 00249 LOG(llevError,"SockList_ReadPacket","SockList_ReadPacket: Read more bytes than desired."); 00250 return 1; 00251 } 00252 } while (toread>0); 00253 return 0; 00254 } 00255 00256 /* 00257 * Send a printf-formatted packet to the socket. 00258 */ 00259 int cs_print_string(int fd, const char *str, ...) 00260 { 00261 va_list args; 00262 SockList sl; 00263 uint8 buf[MAX_BUF]; 00264 00265 SockList_Init(&sl, buf); 00266 va_start(args, str); 00267 sl.len += vsprintf((char*)sl.buf + sl.len, str, args); 00268 va_end(args); 00269 00270 script_monitor_str((char*)sl.buf); 00271 00272 return SockList_Send(&sl, fd); 00273 }