Crossfire Client, Branch  R11627
newsocket.c
Go to the documentation of this file.
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 }