$ git clone https://ion.nu/git/webchat
commit 2eb39c0f8d5d4d116fee2e873c91739dfdcbcb9c
Author: Alicia <...>
Date: Wed Jan 6 20:49:27 2016 +0100
Don't try to read whole packets at a time (especially for big packets like video data)
diff --git a/libwebsocket/websock.c b/libwebsocket/websock.c
index 28055f1..4222756 100644
--- a/libwebsocket/websock.c
+++ b/libwebsocket/websock.c
@@ -187,6 +187,7 @@ void websock_write(void* fd, void* buf, unsigned int len, unsigned char opcode,
char websock_readhead(void* fd, struct websock_head* head_info, char tls)
{
+ head_info->received=0;
unsigned char head[2];
if(aread(fd, head, sizeof(unsigned char)*2)!=sizeof(unsigned char)*2){return 0;}
if(!(head[0]&0x80))
@@ -221,14 +222,17 @@ printf("Non-FIN length: %llu\n", head_info->length);
return 1;
}
-void websock_readcontent(void* fd, void* buf_, struct websock_head* head, char tls)
+char websock_readcontent(void* fd, void* buf_, struct websock_head* head, char tls)
{
+ if(head->length==0){return 1;} // Nothing to read, success by default
unsigned char* buf=buf_;
- unsigned int pos=0;
- int r;
- while(pos<head->length && (r=aread(fd, buf+pos, head->length-pos))>0)
+ int r=aread(fd, buf+head->received, head->length-head->received);
+ if(r>0)
{
- pos+=r;
+ head->received+=r;
+ if(head->received<head->length){return 0;} // Not done yet
+ }else{
+ return 0;
}
if(head->masked)
{
@@ -238,4 +242,5 @@ void websock_readcontent(void* fd, void* buf_, struct websock_head* head, char t
buf[i]^=head->mask[i%4];
}
}
+ return 1; // Got whole packet
}
diff --git a/libwebsocket/websock.h b/libwebsocket/websock.h
index eac98e0..37f0749 100644
--- a/libwebsocket/websock.h
+++ b/libwebsocket/websock.h
@@ -14,6 +14,8 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef WEBSOCK_H
+#define WEBSOCK_H
#define WEBSOCK_CONT 0x0
#define WEBSOCK_TEXT 0x1
#define WEBSOCK_BINARY 0x2
@@ -27,6 +29,7 @@ struct websock_head
char masked;
unsigned char mask[4];
unsigned long long int length;
+ unsigned long long int received;
};
// NOTE: The callback decides whether or not to accept the request, and if so with which protocol, return 0/NULL to reject, nonsockcb is an option to not treat the session as a websocket session
@@ -34,4 +37,5 @@ extern char websock_handshake_server(void* fd, const char*(*cb)(const char* path
// TODO: implement websock_handshake_client()
extern void websock_write(void* fd, void* buf, unsigned int len, unsigned char opcode, char tls);
extern char websock_readhead(void* fd, struct websock_head* head_info, char tls);
-extern void websock_readcontent(void* fd, void* buf_, struct websock_head* head, char tls);
+extern char websock_readcontent(void* fd, void* buf_, struct websock_head* head, char tls);
+#endif
diff --git a/src/chat.c b/src/chat.c
index 8a0ee39..667621b 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -105,7 +105,7 @@ int main()
fds[0].revents=0;
unsigned int i;
unsigned int j;
- struct websock_head head;
+ unsigned char* data=0;
while(1)
{
poll(fds, usercount+1, -1);
@@ -221,25 +221,33 @@ printf("New connection\n");
}
continue;
}
- char status;
- if(!(status=websock_readhead(users[i]->socket, &head, use_tls)) || head.opcode==WEBSOCK_CLOSE) // Disconnect
+ if(!users[i]->packet.data)
{
- if(status){websock_write(users[i]->socket, 0, 0, WEBSOCK_CLOSE, use_tls);}
-printf("User %u disconnected\n", i);
- if(users[i]->channel)
+ char status;
+ if(!(status=websock_readhead(users[i]->socket, &users[i]->packet.head, use_tls)) || users[i]->packet.head.opcode==WEBSOCK_CLOSE) // Disconnect
{
- char quitmsg[strlen("quit:0")+strlen(users[i]->nickname)];
- sprintf(quitmsg, "quit:%s", users[i]->nickname);
- channel_write(users[i]->channel, quitmsg, strlen(quitmsg), WEBSOCK_TEXT, users[i]);
+ if(status){websock_write(users[i]->socket, 0, 0, WEBSOCK_CLOSE, use_tls);}
+printf("User %u disconnected\n", i);
+ if(users[i]->channel)
+ {
+ char quitmsg[strlen("quit:0")+strlen(users[i]->nickname)];
+ sprintf(quitmsg, "quit:%s", users[i]->nickname);
+ channel_write(users[i]->channel, quitmsg, strlen(quitmsg), WEBSOCK_TEXT, users[i]);
+ }
+ freeuser(users[i]); // also takes care of removing user from channel
+ --usercount;
+ memmove(&users[i], &users[i+1], sizeof(struct user*)*(usercount-i));
+ memmove(&fds[i+1], &fds[i+2], sizeof(struct pollfd)*(usercount-i));
+ break;
}
- freeuser(users[i]); // also takes care of removing user from channel
- --usercount;
- memmove(&users[i], &users[i+1], sizeof(struct user*)*(usercount-i));
- memmove(&fds[i+1], &fds[i+2], sizeof(struct pollfd)*(usercount-i));
- break;
+ users[i]->packet.data=malloc(users[i]->packet.head.length+1);
+ continue;
}
- unsigned char data[head.length+1];
- websock_readcontent(users[i]->socket, data, &head, use_tls);
+ if(!websock_readcontent(users[i]->socket, users[i]->packet.data, &users[i]->packet.head, use_tls)){continue;} // Handle other sessions while waiting for the rest of the packet
+ #define head users[i]->packet.head
+ free(data);
+ data=users[i]->packet.data;
+ users[i]->packet.data=0;
data[head.length]=0;
// Handle commands
if(head.opcode==WEBSOCK_TEXT)
@@ -659,6 +667,7 @@ printf("Got video packet\n");
{
websock_write(users[i]->socket, data, head.length, WEBSOCK_PONG, use_tls);
}
+ else{printf("Got unknown data from user %u (length: %llu, opcode %u)\n", i, head.length, head.opcode);}
}
}
return 0;
diff --git a/src/users.c b/src/users.c
index 499a935..c730321 100644
--- a/src/users.c
+++ b/src/users.c
@@ -71,6 +71,7 @@ struct user* adduser(int socket, struct sockaddr* addr, socklen_t addrlen)
users[usercount-1]->httpcam=0;
users[usercount-1]->account=0;
users[usercount-1]->modprivileges=0;
+ users[usercount-1]->packet.data=0;
unsigned int i=0;
unsigned int j=0;
while(j<usercount-1) // Find unique startnick
@@ -124,6 +125,7 @@ void freeuser(struct user* user)
#endif
close(user->rawsocket);
free(user->account);
+ free(user->packet.data);
free(user);
}
diff --git a/src/users.h b/src/users.h
index d6f8446..17b6a0c 100644
--- a/src/users.h
+++ b/src/users.h
@@ -16,6 +16,7 @@
*/
#include <sys/socket.h>
#include <gnutls/gnutls.h>
+#include "../libwebsocket/websock.h"
#define use_tls 1
struct channel;
enum bincmd_type
@@ -55,6 +56,11 @@ struct user
char* account;
int modprivileges;
struct sockaddr sockaddr;
+ struct
+ {
+ struct websock_head head;
+ char* data;
+ } packet;
};
extern unsigned int usercount;
extern struct user** users;