project_files/frontlib/net/netbase.c
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7497 7e1d72fc03c7
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 "netbase.h"
       
    21 #include "../util/buffer.h"
       
    22 #include "../util/logging.h"
       
    23 #include "../util/util.h"
       
    24 #include "../socket.h"
       
    25 
       
    26 #include <string.h>
       
    27 #include <stdbool.h>
       
    28 #include <stdlib.h>
       
    29 #include <stdio.h>
       
    30 
       
    31 #define NET_READBUFFER_LIMIT (1024*1024)
       
    32 
       
    33 struct _flib_netbase {
       
    34 	flib_vector *readBuffer;
       
    35 	flib_tcpsocket *sock;
       
    36 };
       
    37 
       
    38 flib_netbase *flib_netbase_create(const char *server, uint16_t port) {
       
    39 	if(log_badargs_if2(server==NULL, port==0)) {
       
    40 		return NULL;
       
    41 	}
       
    42 
       
    43 	flib_netbase *result = NULL;
       
    44 	flib_netbase *newNet =  flib_calloc(1, sizeof(flib_netbase));
       
    45 
       
    46 	if(newNet) {
       
    47 		newNet->readBuffer = flib_vector_create();
       
    48 		newNet->sock = flib_socket_connect(server, port);
       
    49 		if(newNet->readBuffer && newNet->sock) {
       
    50 			flib_log_i("Connected to server %s:%u", server, (unsigned)port);
       
    51 			result = newNet;
       
    52 			newNet = NULL;
       
    53 		}
       
    54 	}
       
    55 	flib_netbase_destroy(newNet);
       
    56 
       
    57 	return result;
       
    58 }
       
    59 
       
    60 void flib_netbase_destroy(flib_netbase *net) {
       
    61 	if(net) {
       
    62 		flib_socket_close(net->sock);
       
    63 		flib_vector_destroy(net->readBuffer);
       
    64 		free(net);
       
    65 	}
       
    66 }
       
    67 
       
    68 bool flib_netbase_connected(flib_netbase *net) {
       
    69 	if(!log_badargs_if(net==NULL) && net->sock) {
       
    70 		return true;
       
    71 	}
       
    72 	return false;
       
    73 }
       
    74 
       
    75 /**
       
    76  * Parses and returns a message, and removes it from the vector.
       
    77  */
       
    78 static flib_netmsg *parseMessage(flib_vector *vec) {
       
    79 	const uint8_t *partStart = flib_vector_data(vec);
       
    80 	const uint8_t *end = partStart+flib_vector_size(vec);
       
    81 	flib_netmsg *result = flib_netmsg_create();
       
    82 	if(!result) {
       
    83 		return NULL;
       
    84 	}
       
    85 
       
    86 	while(1) {
       
    87 		const uint8_t *partEnd = memchr(partStart, '\n', end-partStart);
       
    88 		if(!partEnd) {
       
    89 			// message incomplete
       
    90 			flib_netmsg_destroy(result);
       
    91 			return NULL;
       
    92 		} else if(partEnd-partStart == 0) {
       
    93 			// Zero-length part, message end marker. Remove the message from the vector.
       
    94 			uint8_t *vectorStart = flib_vector_data(vec);
       
    95 			size_t msgLen = partEnd+1-vectorStart;
       
    96 			memmove(vectorStart, partEnd+1, flib_vector_size(vec)-msgLen);
       
    97 			flib_vector_resize(vec, flib_vector_size(vec)-msgLen);
       
    98 			return result;
       
    99 		} else {
       
   100 			if(flib_netmsg_append_part(result, partStart, partEnd-partStart)) {
       
   101 				flib_netmsg_destroy(result);
       
   102 				return NULL;
       
   103 			}
       
   104 			partStart = partEnd+1; // Skip the '\n'
       
   105 		}
       
   106 	}
       
   107 	return NULL; // Never reached
       
   108 }
       
   109 
       
   110 /**
       
   111  * Receive some bytes and add them to the buffer.
       
   112  * Returns the number of bytes received.
       
   113  * Automatically closes the socket if an error occurs
       
   114  * and sets sock=NULL.
       
   115  */
       
   116 static int receiveToBuffer(flib_netbase *net) {
       
   117 	uint8_t buffer[256];
       
   118 	if(!net->sock) {
       
   119 		return 0;
       
   120 	} else if(flib_vector_size(net->readBuffer) > NET_READBUFFER_LIMIT) {
       
   121 		flib_log_e("Net connection closed: Net message too big");
       
   122 		flib_socket_close(net->sock);
       
   123 		net->sock = NULL;
       
   124 		return 0;
       
   125 	} else {
       
   126 		int size = flib_socket_nbrecv(net->sock, buffer, sizeof(buffer));
       
   127 		if(size>=0 && !flib_vector_append(net->readBuffer, buffer, size)) {
       
   128 			return size;
       
   129 		} else {
       
   130 			flib_socket_close(net->sock);
       
   131 			net->sock = NULL;
       
   132 			return 0;
       
   133 		}
       
   134 	}
       
   135 }
       
   136 
       
   137 flib_netmsg *flib_netbase_recv_message(flib_netbase *net) {
       
   138 	if(log_badargs_if(net==NULL)) {
       
   139 		return NULL;
       
   140 	}
       
   141 
       
   142 	flib_netmsg *msg;
       
   143 	while(!(msg=parseMessage(net->readBuffer))
       
   144 			&& receiveToBuffer(net)) {}
       
   145 
       
   146 	if(msg) {
       
   147 		return msg;
       
   148 	} else if(!net->sock && flib_vector_size(net->readBuffer)>0) {
       
   149 		// Connection is down and we didn't get a complete message, just flush the rest.
       
   150 		flib_vector_resize(net->readBuffer, 0);
       
   151 	}
       
   152 	return NULL;
       
   153 }
       
   154 
       
   155 static void logSentMsg(const uint8_t *data, size_t len) {
       
   156 	if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
       
   157 		flib_log_d("[NET OUT][%03u]%*.*s",(unsigned)len, (unsigned)len, (unsigned)len, data);
       
   158 	}
       
   159 }
       
   160 
       
   161 int flib_netbase_send_raw(flib_netbase *net, const void *data, size_t len) {
       
   162 	if(log_badargs_if2(net==NULL, data==NULL && len>0)) {
       
   163 		return -1;
       
   164 	}
       
   165 	if(!net->sock) {
       
   166 		flib_log_w("flib_netbase_send_raw: Not connected.");
       
   167 		return -1;
       
   168 	}
       
   169 
       
   170 	if(flib_socket_send(net->sock, data, len) == len) {
       
   171 		logSentMsg(data, len);
       
   172 		return 0;
       
   173 	} else {
       
   174 		flib_log_w("Failed or incomplete write: net connection lost.");
       
   175 		flib_socket_close(net->sock);
       
   176 		net->sock = NULL;
       
   177 		return -1;
       
   178 	}
       
   179 }
       
   180 
       
   181 int flib_netbase_send_message(flib_netbase *net, const flib_netmsg *msg) {
       
   182 	if(log_badargs_if2(net==NULL, msg==NULL)) {
       
   183 		return -1;
       
   184 	}
       
   185 
       
   186 	size_t totalSize = 0;
       
   187 	for(int i=0; i<msg->partCount; i++) {
       
   188 		totalSize += strlen(msg->parts[i]) + 1;
       
   189 	}
       
   190 	totalSize++; // Last part ends in two '\n' instead of one
       
   191 
       
   192 	uint8_t *buffer = flib_malloc(totalSize);
       
   193 	if(!buffer) {
       
   194 		return -1;
       
   195 	}
       
   196 	size_t pos = 0;
       
   197 	for(int i=0; i<msg->partCount; i++) {
       
   198 		size_t partsize = strlen(msg->parts[i]);
       
   199 		memcpy(buffer+pos, msg->parts[i], partsize);
       
   200 		pos += partsize;
       
   201 		buffer[pos++] = '\n';
       
   202 	}
       
   203 	buffer[pos++] = '\n';
       
   204 	return flib_netbase_send_raw(net, buffer, pos);
       
   205 }
       
   206 
       
   207 int flib_netbase_sendf(flib_netbase *net, const char *format, ...) {
       
   208 	int result = -1;
       
   209 	if(!log_badargs_if2(net==NULL, format==NULL)) {
       
   210 		va_list argp;
       
   211 		va_start(argp, format);
       
   212 		char *buffer = flib_vasprintf(format, argp);
       
   213 		if(buffer) {
       
   214 			result = flib_netbase_send_raw(net, buffer, strlen(buffer));
       
   215 		}
       
   216 		free(buffer);
       
   217 		va_end(argp);
       
   218 	}
       
   219 	return result;
       
   220 }
       
   221 
       
   222 flib_netmsg *flib_netmsg_create() {
       
   223 	flib_netmsg *result = flib_calloc(1, sizeof(flib_netmsg));
       
   224 	if(result) {
       
   225 		result->partCount = 0;
       
   226 		result->parts = NULL;
       
   227 		return result;
       
   228 	} else {
       
   229 		return NULL;
       
   230 	}
       
   231 }
       
   232 
       
   233 void flib_netmsg_destroy(flib_netmsg *msg) {
       
   234 	if(msg) {
       
   235 		for(int i=0; i<msg->partCount; i++) {
       
   236 			free(msg->parts[i]);
       
   237 		}
       
   238 		free(msg->parts);
       
   239 		free(msg);
       
   240 	}
       
   241 }
       
   242 
       
   243 int flib_netmsg_append_part(flib_netmsg *msg, const void *part, size_t partlen) {
       
   244 	int result = -1;
       
   245 	if(!log_badargs_if2(msg==NULL, part==NULL && partlen>0)) {
       
   246 		char **newParts = realloc(msg->parts, (msg->partCount+1)*sizeof(*msg->parts));
       
   247 		if(newParts) {
       
   248 			msg->parts = newParts;
       
   249 			msg->parts[msg->partCount] = flib_malloc(partlen+1);
       
   250 			if(msg->parts[msg->partCount]) {
       
   251 				memcpy(msg->parts[msg->partCount], part, partlen);
       
   252 				msg->parts[msg->partCount][partlen] = 0;
       
   253 				msg->partCount++;
       
   254 				result = 0;
       
   255 			}
       
   256 		}
       
   257 	}
       
   258 	return result;
       
   259 }