diff options
Diffstat (limited to 'src/examples/websocket_chatserver_example.c')
-rw-r--r-- | src/examples/websocket_chatserver_example.c | 1051 |
1 files changed, 510 insertions, 541 deletions
diff --git a/src/examples/websocket_chatserver_example.c b/src/examples/websocket_chatserver_example.c index 701684cc..0893279b 100644 --- a/src/examples/websocket_chatserver_example.c +++ b/src/examples/websocket_chatserver_example.c | |||
@@ -43,6 +43,12 @@ | |||
43 | See: https://github.com/coapp-packages/pthreads/issues/2 | 43 | See: https://github.com/coapp-packages/pthreads/issues/2 |
44 | */ | 44 | */ |
45 | #include "pthread_windows.h" | 45 | #include "pthread_windows.h" |
46 | |||
47 | /* | ||
48 | On Windows we will use stricmp instead of strcasecmp (strcasecmp is undefined there). | ||
49 | */ | ||
50 | #define strcasecmp stricmp | ||
51 | |||
46 | #else | 52 | #else |
47 | /* | 53 | /* |
48 | On Unix systems we can use pthread. | 54 | On Unix systems we can use pthread. |
@@ -180,429 +186,429 @@ | |||
180 | " function window_onload(event)\n" \ | 186 | " function window_onload(event)\n" \ |
181 | " {\n" \ | 187 | " {\n" \ |
182 | " // Determine the base url (for http:// this is ws:// for https:// this must be wss://)\n" \ | 188 | " // Determine the base url (for http:// this is ws:// for https:// this must be wss://)\n" \ |
183 | // " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ | 189 | " baseUrl = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/ChatServerWebSocket';\n" \ |
184 | // " chat_generate();\n" \ | 190 | " chat_generate();\n" \ |
185 | // " chat_connect();\n" \ | 191 | " chat_connect();\n" \ |
186 | // " }\n" \ | 192 | " }\n" \ |
187 | // "\n" \ | 193 | "\n" \ |
188 | // " /**\n" \ | 194 | " /**\n" \ |
189 | // " This function generates the chat using DOM\n" \ | 195 | " This function generates the chat using DOM\n" \ |
190 | // " */\n" \ | 196 | " */\n" \ |
191 | // " function chat_generate()\n" \ | 197 | " function chat_generate()\n" \ |
192 | // " {\n" \ | 198 | " {\n" \ |
193 | // " document.body.innerHTML = '';\n" \ | 199 | " document.body.innerHTML = '';\n" \ |
194 | // " let chat = document.createElement('div');\n" \ | 200 | " let chat = document.createElement('div');\n" \ |
195 | // " document.body.appendChild(chat);\n" \ | 201 | " document.body.appendChild(chat);\n" \ |
196 | // " chat.id = 'Chat';\n" \ | 202 | " chat.id = 'Chat';\n" \ |
197 | // " let messagesAndInput = document.createElement('div');\n" \ | 203 | " let messagesAndInput = document.createElement('div');\n" \ |
198 | // " chat.appendChild(messagesAndInput);\n" \ | 204 | " chat.appendChild(messagesAndInput);\n" \ |
199 | // " messagesAndInput.classList.add('MessagesAndInput');\n" \ | 205 | " messagesAndInput.classList.add('MessagesAndInput');\n" \ |
200 | // " let messages = document.createElement('div');\n" \ | 206 | " let messages = document.createElement('div');\n" \ |
201 | // " messagesAndInput.appendChild(messages);\n" \ | 207 | " messagesAndInput.appendChild(messages);\n" \ |
202 | // " messages.id = 'Messages';\n" \ | 208 | " messages.id = 'Messages';\n" \ |
203 | // " let input = document.createElement('div');\n" \ | 209 | " let input = document.createElement('div');\n" \ |
204 | // " messagesAndInput.appendChild(input);\n" \ | 210 | " messagesAndInput.appendChild(input);\n" \ |
205 | // " input.classList.add('Input');\n" \ | 211 | " input.classList.add('Input');\n" \ |
206 | // " let inputMessage = document.createElement('input');\n" \ | 212 | " let inputMessage = document.createElement('input');\n" \ |
207 | // " input.appendChild(inputMessage);\n" \ | 213 | " input.appendChild(inputMessage);\n" \ |
208 | // " inputMessage.type = 'text';\n" \ | 214 | " inputMessage.type = 'text';\n" \ |
209 | // " inputMessage.id = 'InputMessage';\n" \ | 215 | " inputMessage.id = 'InputMessage';\n" \ |
210 | // " inputMessage.disabled = true;\n" \ | 216 | " inputMessage.disabled = true;\n" \ |
211 | // " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ | 217 | " inputMessage.addEventListener('keydown', chat_onKeyDown);\n" \ |
212 | // " let inputMessageSend = document.createElement('button');\n" \ | 218 | " let inputMessageSend = document.createElement('button');\n" \ |
213 | // " input.appendChild(inputMessageSend);\n" \ | 219 | " input.appendChild(inputMessageSend);\n" \ |
214 | // " inputMessageSend.id = 'InputMessageButton';\n" \ | 220 | " inputMessageSend.id = 'InputMessageButton';\n" \ |
215 | // " inputMessageSend.disabled = true;\n" \ | 221 | " inputMessageSend.disabled = true;\n" \ |
216 | // " inputMessageSend.innerText = 'send';\n" \ | 222 | " inputMessageSend.innerText = 'send';\n" \ |
217 | // " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ | 223 | " inputMessageSend.addEventListener('click', chat_onSendClicked);\n" \ |
218 | // " let inputImage = document.createElement('input');\n" \ | 224 | " let inputImage = document.createElement('input');\n" \ |
219 | // " input.appendChild(inputImage);\n" \ | 225 | " input.appendChild(inputImage);\n" \ |
220 | // " inputImage.id = 'InputImage';\n" \ | 226 | " inputImage.id = 'InputImage';\n" \ |
221 | // " inputImage.type = 'file';\n" \ | 227 | " inputImage.type = 'file';\n" \ |
222 | // " inputImage.accept = 'image/*';\n" \ | 228 | " inputImage.accept = 'image/*';\n" \ |
223 | // " inputImage.style.display = 'none';\n" \ | 229 | " inputImage.style.display = 'none';\n" \ |
224 | // " inputImage.addEventListener('change', chat_onImageSelected);\n" \ | 230 | " inputImage.addEventListener('change', chat_onImageSelected);\n" \ |
225 | // " let inputImageButton = document.createElement('button');\n" \ | 231 | " let inputImageButton = document.createElement('button');\n" \ |
226 | // " input.appendChild(inputImageButton);\n" \ | 232 | " input.appendChild(inputImageButton);\n" \ |
227 | // " inputImageButton.id = 'InputImageButton';\n" \ | 233 | " inputImageButton.id = 'InputImageButton';\n" \ |
228 | // " inputImageButton.disabled = true;\n" \ | 234 | " inputImageButton.disabled = true;\n" \ |
229 | // " inputImageButton.innerText = 'image';\n" \ | 235 | " inputImageButton.innerText = 'image';\n" \ |
230 | // " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ | 236 | " inputImageButton.addEventListener('click', chat_onImageClicked);\n" \ |
231 | // " let users = document.createElement('div');\n" \ | 237 | " let users = document.createElement('div');\n" \ |
232 | // " chat.appendChild(users);\n" \ | 238 | " chat.appendChild(users);\n" \ |
233 | // " users.id = 'Users';\n" \ | 239 | " users.id = 'Users';\n" \ |
234 | // " users.addEventListener('click', chat_onUserClicked);\n" \ | 240 | " users.addEventListener('click', chat_onUserClicked);\n" \ |
235 | // " let allUsers = document.createElement('div');\n" \ | 241 | " let allUsers = document.createElement('div');\n" \ |
236 | // " users.appendChild(allUsers);\n" \ | 242 | " users.appendChild(allUsers);\n" \ |
237 | // " allUsers.classList.add('selected');\n" \ | 243 | " allUsers.classList.add('selected');\n" \ |
238 | // " allUsers.innerText = '<everyone>';\n" \ | 244 | " allUsers.innerText = '<everyone>';\n" \ |
239 | // " allUsers.setAttribute('data-user', '0');\n" \ | 245 | " allUsers.setAttribute('data-user', '0');\n" \ |
240 | // " }\n" \ | 246 | " }\n" \ |
241 | // "\n" \ | 247 | "\n" \ |
242 | // " /**\n" \ | 248 | " /**\n" \ |
243 | // " This function creates and connects a WebSocket\n" \ | 249 | " This function creates and connects a WebSocket\n" \ |
244 | // " */\n" \ | 250 | " */\n" \ |
245 | // " function chat_connect()\n" \ | 251 | " function chat_connect()\n" \ |
246 | // " {\n" \ | 252 | " {\n" \ |
247 | // " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ | 253 | " chat_addMessage(`Connecting to libmicrohttpd chat server demo (${baseUrl})...`, { type: 'system' });\n" \ |
248 | // " socket = new WebSocket(baseUrl);\n" \ | 254 | " socket = new WebSocket(baseUrl);\n" \ |
249 | // " socket.binaryType = 'arraybuffer';\n" \ | 255 | " socket.binaryType = 'arraybuffer';\n" \ |
250 | // " socket.onopen = socket_onopen;\n" \ | 256 | " socket.onopen = socket_onopen;\n" \ |
251 | // " socket.onclose = socket_onclose;\n" \ | 257 | " socket.onclose = socket_onclose;\n" \ |
252 | // " socket.onerror = socket_onerror;\n" \ | 258 | " socket.onerror = socket_onerror;\n" \ |
253 | // " socket.onmessage = socket_onmessage;\n" \ | 259 | " socket.onmessage = socket_onmessage;\n" \ |
254 | // " }\n" \ | 260 | " }\n" \ |
255 | // "\n" \ | 261 | "\n" \ |
256 | // " /**\n" \ | 262 | " /**\n" \ |
257 | // " This function adds new text to the chat list\n" \ | 263 | " This function adds new text to the chat list\n" \ |
258 | // " */\n" \ | 264 | " */\n" \ |
259 | // " function chat_addMessage(text, options)\n" \ | 265 | " function chat_addMessage(text, options)\n" \ |
260 | // " {\n" \ | 266 | " {\n" \ |
261 | // " let type = options && options.type || 'regular';\n" \ | 267 | " let type = options && options.type || 'regular';\n" \ |
262 | // " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ | 268 | " if(!/^(?:regular|system|error|private|moderator)$/.test(type))\n" \ |
263 | // " type = 'regular';\n" \ | 269 | " type = 'regular';\n" \ |
264 | // " let message = document.createElement('div');\n" \ | 270 | " let message = document.createElement('div');\n" \ |
265 | // " message.classList.add('Message');\n" \ | 271 | " message.classList.add('Message');\n" \ |
266 | // " message.classList.add(type);\n" \ | 272 | " message.classList.add(type);\n" \ |
267 | // " if(typeof(text) === 'string')\n" \ | 273 | " if(typeof(text) === 'string')\n" \ |
268 | // " {\n" \ | 274 | " {\n" \ |
269 | // " let content = document.createElement('span');\n" \ | 275 | " let content = document.createElement('span');\n" \ |
270 | // " message.appendChild(content);\n" \ | 276 | " message.appendChild(content);\n" \ |
271 | // " if(options && options.from)\n" \ | 277 | " if(options && options.from)\n" \ |
272 | // " content.innerText = `${options.from}: ${text}`;\n" \ | 278 | " content.innerText = `${options.from}: ${text}`;\n" \ |
273 | // " else\n" \ | 279 | " else\n" \ |
274 | // " content.innerText = text;\n" \ | 280 | " content.innerText = text;\n" \ |
275 | // " if(options && options.reconnect)\n" \ | 281 | " if(options && options.reconnect)\n" \ |
276 | // " {\n" \ | 282 | " {\n" \ |
277 | // " let span = document.createElement('span');\n" \ | 283 | " let span = document.createElement('span');\n" \ |
278 | // " span.appendChild(document.createTextNode(' ('));\n" \ | 284 | " span.appendChild(document.createTextNode(' ('));\n" \ |
279 | // " let reconnect = document.createElement('a');\n" \ | 285 | " let reconnect = document.createElement('a');\n" \ |
280 | // " reconnect.href = 'javascript:chat_connect()';\n" \ | 286 | " reconnect.href = 'javascript:chat_connect()';\n" \ |
281 | // " reconnect.innerText = 'reconnect';\n" \ | 287 | " reconnect.innerText = 'reconnect';\n" \ |
282 | // " span.appendChild(reconnect);\n" \ | 288 | " span.appendChild(reconnect);\n" \ |
283 | // " span.appendChild(document.createTextNode(')'));\n" \ | 289 | " span.appendChild(document.createTextNode(')'));\n" \ |
284 | // " message.appendChild(span);\n" \ | 290 | " message.appendChild(span);\n" \ |
285 | // " }\n" \ | 291 | " }\n" \ |
286 | // " }\n" \ | 292 | " }\n" \ |
287 | // " else\n" \ | 293 | " else\n" \ |
288 | // " {\n" \ | 294 | " {\n" \ |
289 | // " let content = document.createElement('span');\n" \ | 295 | " let content = document.createElement('span');\n" \ |
290 | // " message.appendChild(content);\n" \ | 296 | " message.appendChild(content);\n" \ |
291 | // " if(options && options.from)\n" \ | 297 | " if(options && options.from)\n" \ |
292 | // " {\n" \ | 298 | " {\n" \ |
293 | // " content.innerText = `${options.from}:\\n`;\n" \ | 299 | " content.innerText = `${options.from}:\\n`;\n" \ |
294 | // " }\n" \ | 300 | " }\n" \ |
295 | // " if(options && options.pictureType && text instanceof Uint8Array)\n" \ | 301 | " if(options && options.pictureType && text instanceof Uint8Array)\n" \ |
296 | // " {\n" \ | 302 | " {\n" \ |
297 | // " let img = document.createElement('img');\n" \ | 303 | " let img = document.createElement('img');\n" \ |
298 | // " content.appendChild(img);\n" \ | 304 | " content.appendChild(img);\n" \ |
299 | // " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ | 305 | " img.src = URL.createObjectURL(new Blob([ text.buffer ], { type: options.pictureType }));\n" \ |
300 | // " }\n" \ | 306 | " }\n" \ |
301 | // " }\n" \ | 307 | " }\n" \ |
302 | // " document.getElementById('Messages').appendChild(message);\n" \ | 308 | " document.getElementById('Messages').appendChild(message);\n" \ |
303 | // " message.scrollIntoView();\n" \ | 309 | " message.scrollIntoView();\n" \ |
304 | // " }\n" \ | 310 | " }\n" \ |
305 | // "\n" \ | 311 | "\n" \ |
306 | // " /**\n" \ | 312 | " /**\n" \ |
307 | // " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ | 313 | " This is a keydown event handler, which allows that you can just press enter instead of clicking the 'send' button\n" \ |
308 | // " */\n" \ | 314 | " */\n" \ |
309 | // " function chat_onKeyDown(event)\n" \ | 315 | " function chat_onKeyDown(event)\n" \ |
310 | // " {\n" \ | 316 | " {\n" \ |
311 | // " if(event.key == 'Enter')\n" \ | 317 | " if(event.key == 'Enter')\n" \ |
312 | // " chat_onSendClicked();\n" \ | 318 | " chat_onSendClicked();\n" \ |
313 | // " }\n" \ | 319 | " }\n" \ |
314 | // "\n" \ | 320 | "\n" \ |
315 | // " /**\n" \ | 321 | " /**\n" \ |
316 | // " This is the code to send a message or command, when clicking the 'send' button\n" \ | 322 | " This is the code to send a message or command, when clicking the 'send' button\n" \ |
317 | // " */\n" \ | 323 | " */\n" \ |
318 | // " function chat_onSendClicked(event)\n" \ | 324 | " function chat_onSendClicked(event)\n" \ |
319 | // " {\n" \ | 325 | " {\n" \ |
320 | // " let message = document.getElementById('InputMessage').value;\n" \ | 326 | " let message = document.getElementById('InputMessage').value;\n" \ |
321 | // " if(message.length == 0)\n" \ | 327 | " if(message.length == 0)\n" \ |
322 | // " return;\n" \ | 328 | " return;\n" \ |
323 | // " if(message.substr(0, 1) == '/')\n" \ | 329 | " if(message.substr(0, 1) == '/')\n" \ |
324 | // " {\n" \ | 330 | " {\n" \ |
325 | // " // command\n" \ | 331 | " // command\n" \ |
326 | // " let match;\n" \ | 332 | " let match;\n" \ |
327 | // " if(/^\\/disconnect\\s*$/.test(message))\n" \ | 333 | " if(/^\\/disconnect\\s*$/.test(message))\n" \ |
328 | // " {\n" \ | 334 | " {\n" \ |
329 | // " socket.close(1000);\n" \ | 335 | " socket.close(1000);\n" \ |
330 | // " }\n" \ | 336 | " }\n" \ |
331 | // " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ | 337 | " else if((match = /^\\/m\\s+(\\S+)\\s+/.exec(message)))\n" \ |
332 | // " {\n" \ | 338 | " {\n" \ |
333 | // " message = message.substr(match[0].length);\n" \ | 339 | " message = message.substr(match[0].length);\n" \ |
334 | // " let userId = chat_getUserIdByName(match[1]);\n" \ | 340 | " let userId = chat_getUserIdByName(match[1]);\n" \ |
335 | // " if(userId !== null)\n" \ | 341 | " if(userId !== null)\n" \ |
336 | // " {\n" \ | 342 | " {\n" \ |
337 | // " socket.send(`private|${userId}|${message}`);\n" \ | 343 | " socket.send(`private|${userId}|${message}`);\n" \ |
338 | // " }\n" \ | 344 | " }\n" \ |
339 | // " else\n" \ | 345 | " else\n" \ |
340 | // " {\n" \ | 346 | " {\n" \ |
341 | // " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ | 347 | " chat_addMessage(`Unknown user \"${match[1]}\" for private message: ${message}`, { type: 'error' });\n" \ |
342 | // " }\n" \ | 348 | " }\n" \ |
343 | // " }\n" \ | 349 | " }\n" \ |
344 | // " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ | 350 | " else if((match = /^\\/ping\\s+(\\S+)\\s*$/.exec(message)))\n" \ |
345 | // " {\n" \ | 351 | " {\n" \ |
346 | // " let userId = chat_getUserIdByName(match[1]);\n" \ | 352 | " let userId = chat_getUserIdByName(match[1]);\n" \ |
347 | // " if(userId !== null)\n" \ | 353 | " if(userId !== null)\n" \ |
348 | // " {\n" \ | 354 | " {\n" \ |
349 | // " socket.send(`ping|${userId}|`);\n" \ | 355 | " socket.send(`ping|${userId}|`);\n" \ |
350 | // " }\n" \ | 356 | " }\n" \ |
351 | // " else\n" \ | 357 | " else\n" \ |
352 | // " {\n" \ | 358 | " {\n" \ |
353 | // " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ | 359 | " chat_addMessage(`Unknown user \"${match[1]}\" for ping`, { type: 'error' });\n" \ |
354 | // " }\n" \ | 360 | " }\n" \ |
355 | // " }\n" \ | 361 | " }\n" \ |
356 | // " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ | 362 | " else if((match = /^\\/name\\s+(\\S+)\\s*$/.exec(message)))\n" \ |
357 | // " {\n" \ | 363 | " {\n" \ |
358 | // " socket.send(`name||${match[1]}`);\n" \ | 364 | " socket.send(`name||${match[1]}`);\n" \ |
359 | // " }\n" \ | 365 | " }\n" \ |
360 | // " else\n" \ | 366 | " else\n" \ |
361 | // " {\n" \ | 367 | " {\n" \ |
362 | // " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ | 368 | " chat_addMessage(`Unsupported command or invalid syntax: ${message}`, { type: 'error' });\n" \ |
363 | // " }\n" \ | 369 | " }\n" \ |
364 | // " }\n" \ | 370 | " }\n" \ |
365 | // " else\n" \ | 371 | " else\n" \ |
366 | // " {\n" \ | 372 | " {\n" \ |
367 | // " // regular chat message to the selected user\n" \ | 373 | " // regular chat message to the selected user\n" \ |
368 | // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ | 374 | " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ |
369 | // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ | 375 | " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ |
370 | // " if(selectedUserId == 0)\n" \ | 376 | " if(selectedUserId == 0)\n" \ |
371 | // " socket.send(`||${message}`);\n" \ | 377 | " socket.send(`||${message}`);\n" \ |
372 | // " else\n" \ | 378 | " else\n" \ |
373 | // " socket.send(`private|${selectedUserId}|${message}`);\n" \ | 379 | " socket.send(`private|${selectedUserId}|${message}`);\n" \ |
374 | // " }\n" \ | 380 | " }\n" \ |
375 | // " document.getElementById('InputMessage').value = '';\n" \ | 381 | " document.getElementById('InputMessage').value = '';\n" \ |
376 | // " }\n" \ | 382 | " }\n" \ |
377 | // "\n" \ | 383 | "\n" \ |
378 | // " /**\n" \ | 384 | " /**\n" \ |
379 | // " This is the event when the user hits the 'image' button\n" \ | 385 | " This is the event when the user hits the 'image' button\n" \ |
380 | // " */\n" \ | 386 | " */\n" \ |
381 | // " function chat_onImageClicked(event)\n" \ | 387 | " function chat_onImageClicked(event)\n" \ |
382 | // " {\n" \ | 388 | " {\n" \ |
383 | // " document.getElementById('InputImage').click();\n" \ | 389 | " document.getElementById('InputImage').click();\n" \ |
384 | // " }\n" \ | 390 | " }\n" \ |
385 | // "\n" \ | 391 | "\n" \ |
386 | // " /**\n" \ | 392 | " /**\n" \ |
387 | // " This is the event when the user selected an image.\n" \ | 393 | " This is the event when the user selected an image.\n" \ |
388 | // " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ | 394 | " The image will be read with the FileReader (allowed in web, because the user selected the file).\n" \ |
389 | // " */\n" \ | 395 | " */\n" \ |
390 | // " function chat_onImageSelected(event)\n" \ | 396 | " function chat_onImageSelected(event)\n" \ |
391 | // " {\n" \ | 397 | " {\n" \ |
392 | // " let file = event.target.files[0];\n" \ | 398 | " let file = event.target.files[0];\n" \ |
393 | // " if(!file || !/^image\\//.test(file.type))\n" \ | 399 | " if(!file || !/^image\\//.test(file.type))\n" \ |
394 | // " return;\n" \ | 400 | " return;\n" \ |
395 | // " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ | 401 | " let selectedUser = document.querySelector('div#Users > div.selected');\n" \ |
396 | // " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ | 402 | " let selectedUserId = parseInt(selectedUser.getAttribute('data-user') || '0', 10);\n" \ |
397 | // " let reader = new FileReader();\n" \ | 403 | " let reader = new FileReader();\n" \ |
398 | // " reader.onload = function(event) {\n" \ | 404 | " reader.onload = function(event) {\n" \ |
399 | // " chat_onImageRead(event, file.type, selectedUserId);\n" \ | 405 | " chat_onImageRead(event, file.type, selectedUserId);\n" \ |
400 | // " };\n" \ | 406 | " };\n" \ |
401 | // " reader.readAsArrayBuffer(file);\n" \ | 407 | " reader.readAsArrayBuffer(file);\n" \ |
402 | // " }\n" \ | 408 | " }\n" \ |
403 | // "\n" \ | 409 | "\n" \ |
404 | // " /**\n" \ | 410 | " /**\n" \ |
405 | // " This is the event when the user selected image has been read.\n" \ | 411 | " This is the event when the user selected image has been read.\n" \ |
406 | // " This will add our chat protocol prefix and send it via the websocket.\n" \ | 412 | " This will add our chat protocol prefix and send it via the websocket.\n" \ |
407 | // " */\n" \ | 413 | " */\n" \ |
408 | // " function chat_onImageRead(event, fileType, selectedUserId)\n" \ | 414 | " function chat_onImageRead(event, fileType, selectedUserId)\n" \ |
409 | // " {\n" \ | 415 | " {\n" \ |
410 | // " let encoder = new TextEncoder();\n" \ | 416 | " let encoder = new TextEncoder();\n" \ |
411 | // " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ | 417 | " let prefix = ((selectedUserId == 0 ? '||' : `private|${selectedUserId}|`) + fileType + '|');\n" \ |
412 | // " prefix = encoder.encode(prefix);\n" \ | 418 | " prefix = encoder.encode(prefix);\n" \ |
413 | // " let byteData = new Uint8Array(event.target.result);\n" \ | 419 | " let byteData = new Uint8Array(event.target.result);\n" \ |
414 | // " let totalLength = prefix.length + byteData.length;\n" \ | 420 | " let totalLength = prefix.length + byteData.length;\n" \ |
415 | // " let resultByteData = new Uint8Array(totalLength);\n" \ | 421 | " let resultByteData = new Uint8Array(totalLength);\n" \ |
416 | // " resultByteData.set(prefix, 0);\n" \ | 422 | " resultByteData.set(prefix, 0);\n" \ |
417 | // " resultByteData.set(byteData, prefix.length);\n" \ | 423 | " resultByteData.set(byteData, prefix.length);\n" \ |
418 | // " socket.send(resultByteData);\n" \ | 424 | " socket.send(resultByteData);\n" \ |
419 | // " }\n" \ | 425 | " }\n" \ |
420 | // "\n" \ | 426 | "\n" \ |
421 | // " /**\n" \ | 427 | " /**\n" \ |
422 | // " This is the event when the user clicked a name in the user list.\n" \ | 428 | " This is the event when the user clicked a name in the user list.\n" \ |
423 | // " This is useful to send private messages or images without needing to add the /m prefix.\n" \ | 429 | " This is useful to send private messages or images without needing to add the /m prefix.\n" \ |
424 | // " */\n" \ | 430 | " */\n" \ |
425 | // " function chat_onUserClicked(event, selectedUserId)\n" \ | 431 | " function chat_onUserClicked(event, selectedUserId)\n" \ |
426 | // " {\n" \ | 432 | " {\n" \ |
427 | // " let newSelected = event.target.closest('div#Users > div');\n" \ | 433 | " let newSelected = event.target.closest('div#Users > div');\n" \ |
428 | // " if(newSelected === null)\n" \ | 434 | " if(newSelected === null)\n" \ |
429 | // " return;\n" \ | 435 | " return;\n" \ |
430 | // " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ | 436 | " for(let div of this.querySelectorAll(':scope > div.selected'))\n" \ |
431 | // " div.classList.remove('selected');\n" \ | 437 | " div.classList.remove('selected');\n" \ |
432 | // " newSelected.classList.add('selected');\n" \ | 438 | " newSelected.classList.add('selected');\n" \ |
433 | // " }\n" \ | 439 | " }\n" \ |
434 | // "\n" \ | 440 | "\n" \ |
435 | // " /**\n" \ | 441 | " /**\n" \ |
436 | // " This functions returns the current id of a user identified by its name.\n" \ | 442 | " This functions returns the current id of a user identified by its name.\n" \ |
437 | // " */\n" \ | 443 | " */\n" \ |
438 | // " function chat_getUserIdByName(name)\n" \ | 444 | " function chat_getUserIdByName(name)\n" \ |
439 | // " {\n" \ | 445 | " {\n" \ |
440 | // " let nameUpper = name.toUpperCase();\n" \ | 446 | " let nameUpper = name.toUpperCase();\n" \ |
441 | // " for(let pair of connectedUsers)\n" \ | 447 | " for(let pair of connectedUsers)\n" \ |
442 | // " {\n" \ | 448 | " {\n" \ |
443 | // " if(pair[1].toUpperCase() == nameUpper)\n" \ | 449 | " if(pair[1].toUpperCase() == nameUpper)\n" \ |
444 | // " return pair[0];\n" \ | 450 | " return pair[0];\n" \ |
445 | // " }\n" \ | 451 | " }\n" \ |
446 | // " return null;\n" \ | 452 | " return null;\n" \ |
447 | // " }\n" \ | 453 | " }\n" \ |
448 | // "\n" \ | 454 | "\n" \ |
449 | // " /**\n" \ | 455 | " /**\n" \ |
450 | // " This functions clears the entire user list (needed for reconnecting).\n" \ | 456 | " This functions clears the entire user list (needed for reconnecting).\n" \ |
451 | // " */\n" \ | 457 | " */\n" \ |
452 | // " function chat_clearUserList()\n" \ | 458 | " function chat_clearUserList()\n" \ |
453 | // " {\n" \ | 459 | " {\n" \ |
454 | // " let users = document.getElementById('Users');\n" \ | 460 | " let users = document.getElementById('Users');\n" \ |
455 | // " for(let div of users.querySelectorAll(':scope > div'))\n" \ | 461 | " for(let div of users.querySelectorAll(':scope > div'))\n" \ |
456 | // " {\n" \ | 462 | " {\n" \ |
457 | // " if(div.getAttribute('data-user') === '0')\n" \ | 463 | " if(div.getAttribute('data-user') === '0')\n" \ |
458 | // " {\n" \ | 464 | " {\n" \ |
459 | // " div.classList.add('selected');\n" \ | 465 | " div.classList.add('selected');\n" \ |
460 | // " }\n" \ | 466 | " }\n" \ |
461 | // " else\n" \ | 467 | " else\n" \ |
462 | // " {\n" \ | 468 | " {\n" \ |
463 | // " div.parentNode.removeChild(div);\n" \ | 469 | " div.parentNode.removeChild(div);\n" \ |
464 | // " }\n" \ | 470 | " }\n" \ |
465 | // " }\n" \ | 471 | " }\n" \ |
466 | // " return null;\n" \ | 472 | " return null;\n" \ |
467 | // " }\n" \ | 473 | " }\n" \ |
468 | // "\n" \ | 474 | "\n" \ |
469 | // " /**\n" \ | 475 | " /**\n" \ |
470 | // " This is the event when the socket has established a connection.\n" \ | 476 | " This is the event when the socket has established a connection.\n" \ |
471 | // " This will initialize an empty chat and enable the controls.\n" \ | 477 | " This will initialize an empty chat and enable the controls.\n" \ |
472 | // " */\n" \ | 478 | " */\n" \ |
473 | // " function socket_onopen(event)\n" \ | 479 | " function socket_onopen(event)\n" \ |
474 | // " {\n" \ | 480 | " {\n" \ |
475 | // " connectedUsers.clear();\n" \ | 481 | " connectedUsers.clear();\n" \ |
476 | // " chat_clearUserList();\n" \ | 482 | " chat_clearUserList();\n" \ |
477 | // " chat_addMessage('Connected!', { type: 'system' });\n" \ | 483 | " chat_addMessage('Connected!', { type: 'system' });\n" \ |
478 | // " document.getElementById('InputMessage').disabled = false;\n" \ | 484 | " document.getElementById('InputMessage').disabled = false;\n" \ |
479 | // " document.getElementById('InputMessageButton').disabled = false;\n" \ | 485 | " document.getElementById('InputMessageButton').disabled = false;\n" \ |
480 | // " document.getElementById('InputImageButton').disabled = false;\n" \ | 486 | " document.getElementById('InputImageButton').disabled = false;\n" \ |
481 | // " }\n" \ | 487 | " }\n" \ |
482 | // "\n" \ | 488 | "\n" \ |
483 | // " /**\n" \ | 489 | " /**\n" \ |
484 | // " This is the event when the socket has been closed.\n" \ | 490 | " This is the event when the socket has been closed.\n" \ |
485 | // " This will lock the controls.\n" \ | 491 | " This will lock the controls.\n" \ |
486 | // " */\n" \ | 492 | " */\n" \ |
487 | // " function socket_onclose(event)\n" \ | 493 | " function socket_onclose(event)\n" \ |
488 | // " {\n" \ | 494 | " {\n" \ |
489 | // " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ | 495 | " chat_addMessage('Connection closed!', { type: 'system', reconnect: true });\n" \ |
490 | // " document.getElementById('InputMessage').disabled = true;\n" \ | 496 | " document.getElementById('InputMessage').disabled = true;\n" \ |
491 | // " document.getElementById('InputMessageButton').disabled = true;\n" \ | 497 | " document.getElementById('InputMessageButton').disabled = true;\n" \ |
492 | // " document.getElementById('InputImageButton').disabled = true;\n" \ | 498 | " document.getElementById('InputImageButton').disabled = true;\n" \ |
493 | // " }\n" \ | 499 | " }\n" \ |
494 | // "\n" \ | 500 | "\n" \ |
495 | // " /**\n" \ | 501 | " /**\n" \ |
496 | // " This is the event when the socket reported an error.\n" \ | 502 | " This is the event when the socket reported an error.\n" \ |
497 | // " This will just make an output.\n" \ | 503 | " This will just make an output.\n" \ |
498 | // " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ | 504 | " In the web browser console (F12 on many browsers) will show you more detailed error information.\n" \ |
499 | // " */\n" \ | 505 | " */\n" \ |
500 | // " function socket_onerror(event)\n" \ | 506 | " function socket_onerror(event)\n" \ |
501 | // " {\n" \ | 507 | " {\n" \ |
502 | // " console.error('WebSocket error reported: ', event);\n" \ | 508 | " console.error('WebSocket error reported: ', event);\n" \ |
503 | // " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ | 509 | " chat_addMessage('The socket reported an error!', { type: 'error' });\n" \ |
504 | // " }\n" \ | 510 | " }\n" \ |
505 | // "\n" \ | 511 | "\n" \ |
506 | // " /**\n" \ | 512 | " /**\n" \ |
507 | // " This is the event when the socket has received a message.\n" \ | 513 | " This is the event when the socket has received a message.\n" \ |
508 | // " This will parse the message and execute the corresponding command (or add the message).\n" \ | 514 | " This will parse the message and execute the corresponding command (or add the message).\n" \ |
509 | // " */\n" \ | 515 | " */\n" \ |
510 | // " function socket_onmessage(event)\n" \ | 516 | " function socket_onmessage(event)\n" \ |
511 | // " {\n" \ | 517 | " {\n" \ |
512 | // " if(typeof(event.data) === 'string')\n" \ | 518 | " if(typeof(event.data) === 'string')\n" \ |
513 | // " {\n" \ | 519 | " {\n" \ |
514 | // " // text message or command\n" \ | 520 | " // text message or command\n" \ |
515 | // " let message = event.data.split('|', 3);\n" \ | 521 | " let message = event.data.split('|', 3);\n" \ |
516 | // " switch(message[0])\n" \ | 522 | " switch(message[0])\n" \ |
517 | // " {\n" \ | 523 | " {\n" \ |
518 | // " case 'userinit':\n" \ | 524 | " case 'userinit':\n" \ |
519 | // " connectedUsers.set(message[1], message[2]);\n" \ | 525 | " connectedUsers.set(message[1], message[2]);\n" \ |
520 | // " {\n" \ | 526 | " {\n" \ |
521 | // " let users = document.getElementById('Users');\n" \ | 527 | " let users = document.getElementById('Users');\n" \ |
522 | // " let div = document.createElement('div');\n" \ | 528 | " let div = document.createElement('div');\n" \ |
523 | // " users.appendChild(div);\n" \ | 529 | " users.appendChild(div);\n" \ |
524 | // " div.innerText = message[2];\n" \ | 530 | " div.innerText = message[2];\n" \ |
525 | // " div.setAttribute('data-user', message[1]);\n" \ | 531 | " div.setAttribute('data-user', message[1]);\n" \ |
526 | // " }\n" \ | 532 | " }\n" \ |
527 | // " break;\n" \ | 533 | " break;\n" \ |
528 | // " case 'useradd':\n" \ | 534 | " case 'useradd':\n" \ |
529 | // " connectedUsers.set(message[1], message[2]);\n" \ | 535 | " connectedUsers.set(message[1], message[2]);\n" \ |
530 | // " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ | 536 | " chat_addMessage(`The user '${message[2]}' has joined our lovely chatroom.`, { type: 'moderator' });\n" \ |
531 | // " {\n" \ | 537 | " {\n" \ |
532 | // " let users = document.getElementById('Users');\n" \ | 538 | " let users = document.getElementById('Users');\n" \ |
533 | // " let div = document.createElement('div');\n" \ | 539 | " let div = document.createElement('div');\n" \ |
534 | // " users.appendChild(div);\n" \ | 540 | " users.appendChild(div);\n" \ |
535 | // " div.innerText = message[2];\n" \ | 541 | " div.innerText = message[2];\n" \ |
536 | // " div.setAttribute('data-user', message[1]);\n" \ | 542 | " div.setAttribute('data-user', message[1]);\n" \ |
537 | // " }\n" \ | 543 | " }\n" \ |
538 | // " break;\n" \ | 544 | " break;\n" \ |
539 | // " case 'userdel':\n" \ | 545 | " case 'userdel':\n" \ |
540 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ | 546 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has left our chatroom. We will miss you.`, { type: 'moderator' });\n" \ |
541 | // " connectedUsers.delete(message[1]);\n" \ | 547 | " connectedUsers.delete(message[1]);\n" \ |
542 | // " {\n" \ | 548 | " {\n" \ |
543 | // " let users = document.getElementById('Users');\n" \ | 549 | " let users = document.getElementById('Users');\n" \ |
544 | // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ | 550 | " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ |
545 | // " if(div !== null)\n" \ | 551 | " if(div !== null)\n" \ |
546 | // " {\n" \ | 552 | " {\n" \ |
547 | // " users.removeChild(div);\n" \ | 553 | " users.removeChild(div);\n" \ |
548 | // " if(div.classList.contains('selected'))\n" \ | 554 | " if(div.classList.contains('selected'))\n" \ |
549 | // " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ | 555 | " users.querySelector('div[data-user=\\'0\\']').classList.add('selected');\n" \ |
550 | // " }\n" \ | 556 | " }\n" \ |
551 | // " }\n" \ | 557 | " }\n" \ |
552 | // " break;\n" \ | 558 | " break;\n" \ |
553 | // " case 'username':\n" \ | 559 | " case 'username':\n" \ |
554 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ | 560 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has changed his name to '${message[2]}'.`, { type: 'moderator' });\n" \ |
555 | // " connectedUsers.set(message[1], message[2]);\n" \ | 561 | " connectedUsers.set(message[1], message[2]);\n" \ |
556 | // " {\n" \ | 562 | " {\n" \ |
557 | // " let users = document.getElementById('Users');\n" \ | 563 | " let users = document.getElementById('Users');\n" \ |
558 | // " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ | 564 | " let div = users.querySelector(`div[data-user='${message[1]}']`);\n" \ |
559 | // " if(div !== null)\n" \ | 565 | " if(div !== null)\n" \ |
560 | // " {\n" \ | 566 | " {\n" \ |
561 | // " div.innerText = message[2];\n" \ | 567 | " div.innerText = message[2];\n" \ |
562 | // " }\n" \ | 568 | " }\n" \ |
563 | // " }\n" \ | 569 | " }\n" \ |
564 | // " break;\n" \ | 570 | " break;\n" \ |
565 | // " case 'ping':\n" \ | 571 | " case 'ping':\n" \ |
566 | // " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ | 572 | " chat_addMessage(`The user '${connectedUsers.get(message[1])}' has a ping of ${message[2]} ms.`, { type: 'moderator' });\n" \ |
567 | // " break;\n" \ | 573 | " break;\n" \ |
568 | // " default:\n" \ | 574 | " default:\n" \ |
569 | // " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ | 575 | " chat_addMessage(message[2], { type: message[0], from: connectedUsers.get(message[1]) });\n" \ |
570 | // " break;\n" \ | 576 | " break;\n" \ |
571 | // " }\n" \ | 577 | " }\n" \ |
572 | // " }\n" \ | 578 | " }\n" \ |
573 | // " else\n" \ | 579 | " else\n" \ |
574 | // " {\n" \ | 580 | " {\n" \ |
575 | // " // We received a binary frame, which means a picture here\n" \ | 581 | " // We received a binary frame, which means a picture here\n" \ |
576 | // " let byteData = new Uint8Array(event.data);\n" \ | 582 | " let byteData = new Uint8Array(event.data);\n" \ |
577 | // " let decoder = new TextDecoder();\n" \ | 583 | " let decoder = new TextDecoder();\n" \ |
578 | // " let message = [ ];\n" \ | 584 | " let message = [ ];\n" \ |
579 | // " // message type\n" \ | 585 | " // message type\n" \ |
580 | // " let j = 0;\n" \ | 586 | " let j = 0;\n" \ |
581 | // " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ | 587 | " let i = byteData.indexOf(0x7C, j); // | = 0x7C;\n" \ |
582 | // " if(i < 0)\n" \ | 588 | " if(i < 0)\n" \ |
583 | // " return;\n" \ | 589 | " return;\n" \ |
584 | // " message.push(decoder.decode(byteData.slice(0, i)));\n" \ | 590 | " message.push(decoder.decode(byteData.slice(0, i)));\n" \ |
585 | // " // picture from\n" \ | 591 | " // picture from\n" \ |
586 | // " j = i + 1;\n" \ | 592 | " j = i + 1;\n" \ |
587 | // " i = byteData.indexOf(0x7C, j);\n" \ | 593 | " i = byteData.indexOf(0x7C, j);\n" \ |
588 | // " if(i < 0)\n" \ | 594 | " if(i < 0)\n" \ |
589 | // " return;\n" \ | 595 | " return;\n" \ |
590 | // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ | 596 | " message.push(decoder.decode(byteData.slice(j, i)));\n" \ |
591 | // " // picture encoding\n" \ | 597 | " // picture encoding\n" \ |
592 | // " j = i + 1;\n" \ | 598 | " j = i + 1;\n" \ |
593 | // " i = byteData.indexOf(0x7C, j);\n" \ | 599 | " i = byteData.indexOf(0x7C, j);\n" \ |
594 | // " if(i < 0)\n" \ | 600 | " if(i < 0)\n" \ |
595 | // " return;\n" \ | 601 | " return;\n" \ |
596 | // " message.push(decoder.decode(byteData.slice(j, i)));\n" \ | 602 | " message.push(decoder.decode(byteData.slice(j, i)));\n" \ |
597 | // " // picture\n" \ | 603 | " // picture\n" \ |
598 | // " byteData = byteData.slice(i + 1);\n" \ | 604 | " byteData = byteData.slice(i + 1);\n" \ |
599 | // " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ | 605 | " chat_addMessage(byteData, { type: message[0], from: connectedUsers.get(message[1]), pictureType: message[2] });\n" \ |
600 | // " }\n" \ | 606 | " }\n" \ |
601 | // " }\n" \ | 607 | " }\n" \ |
602 | // "</script>" \ | 608 | "</script>" \ |
603 | // "</head>" \ | 609 | "</head>" \ |
604 | // "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ | 610 | "<body><noscript>Please enable JavaScript to test the libmicrohttpd Websocket chatserver demo!</noscript></body>" \ |
605 | // "</html>" | 611 | "</html>" |
606 | 612 | ||
607 | #define PAGE_NOT_FOUND \ | 613 | #define PAGE_NOT_FOUND \ |
608 | "404 Not Found" | 614 | "404 Not Found" |
@@ -708,7 +714,7 @@ make_blocking (MHD_socket fd) | |||
708 | #elif defined(MHD_WINSOCK_SOCKETS) | 714 | #elif defined(MHD_WINSOCK_SOCKETS) |
709 | unsigned long flags = 0; | 715 | unsigned long flags = 0; |
710 | 716 | ||
711 | ioctlsocket (fd, (int) FIONBIO, &flags); | 717 | ioctlsocket (fd, FIONBIO, &flags); |
712 | #endif /* MHD_WINSOCK_SOCKETS */ | 718 | #endif /* MHD_WINSOCK_SOCKETS */ |
713 | 719 | ||
714 | } | 720 | } |
@@ -739,7 +745,6 @@ send_all (struct ConnectedUser*cu, | |||
739 | 0); | 745 | 0); |
740 | if (0 > ret) | 746 | if (0 > ret) |
741 | { | 747 | { |
742 | int err = errno; | ||
743 | if (EAGAIN == errno) | 748 | if (EAGAIN == errno) |
744 | { | 749 | { |
745 | ret = 0; | 750 | ret = 0; |
@@ -927,7 +932,7 @@ chat_adduser (struct ConnectedUser*cu) | |||
927 | { | 932 | { |
928 | /* initialize the notification message of the new user */ | 933 | /* initialize the notification message of the new user */ |
929 | char user_index[32]; | 934 | char user_index[32]; |
930 | itoa ((int) cu->user_id, user_index, 10); | 935 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
931 | size_t user_index_len = strlen (user_index); | 936 | size_t user_index_len = strlen (user_index); |
932 | size_t data_len = user_index_len + cu->user_name_len + 9; | 937 | size_t data_len = user_index_len + cu->user_name_len + 9; |
933 | char*data = (char*) malloc (data_len + 1); | 938 | char*data = (char*) malloc (data_len + 1); |
@@ -998,7 +1003,7 @@ chat_removeuser (struct ConnectedUser*cu) | |||
998 | char user_index[32]; | 1003 | char user_index[32]; |
999 | 1004 | ||
1000 | /* initialize the chat message for the removed user */ | 1005 | /* initialize the chat message for the removed user */ |
1001 | itoa ((int) cu->user_id, user_index, 10); | 1006 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1002 | size_t user_index_len = strlen (user_index); | 1007 | size_t user_index_len = strlen (user_index); |
1003 | size_t data_len = user_index_len + 9; | 1008 | size_t data_len = user_index_len + 9; |
1004 | char*data = (char*) malloc (data_len + 1); | 1009 | char*data = (char*) malloc (data_len + 1); |
@@ -1071,9 +1076,8 @@ chat_renameuser (struct ConnectedUser*cu, | |||
1071 | { | 1076 | { |
1072 | if (cu != users[i]) | 1077 | if (cu != users[i]) |
1073 | { | 1078 | { |
1074 | if ((users[i]->user_name_len == new_name_len) && (0 == stricmp ( | 1079 | if ((users[i]->user_name_len == new_name_len) && |
1075 | users[i]->user_name, | 1080 | (0 == strcasecmp (users[i]->user_name, new_name))) |
1076 | new_name))) | ||
1077 | { | 1081 | { |
1078 | pthread_mutex_unlock (&chat_mutex); | 1082 | pthread_mutex_unlock (&chat_mutex); |
1079 | return 2; | 1083 | return 2; |
@@ -1083,7 +1087,7 @@ chat_renameuser (struct ConnectedUser*cu, | |||
1083 | 1087 | ||
1084 | /* generate the notification message */ | 1088 | /* generate the notification message */ |
1085 | char user_index[32]; | 1089 | char user_index[32]; |
1086 | itoa ((int) cu->user_id, user_index, 10); | 1090 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1087 | size_t user_index_len = strlen (user_index); | 1091 | size_t user_index_len = strlen (user_index); |
1088 | size_t data_len = user_index_len + new_name_len + 10; | 1092 | size_t data_len = user_index_len + new_name_len + 10; |
1089 | char*data = (char*) malloc (data_len + 1); | 1093 | char*data = (char*) malloc (data_len + 1); |
@@ -1202,17 +1206,17 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1202 | /* no command means regular message */ | 1206 | /* no command means regular message */ |
1203 | command = 0; | 1207 | command = 0; |
1204 | } | 1208 | } |
1205 | else if (0 == stricmp (frame_data, "private")) | 1209 | else if (0 == strcasecmp (frame_data, "private")) |
1206 | { | 1210 | { |
1207 | /* private means private message */ | 1211 | /* private means private message */ |
1208 | command = 1; | 1212 | command = 1; |
1209 | } | 1213 | } |
1210 | else if (0 == stricmp (frame_data, "name")) | 1214 | else if (0 == strcasecmp (frame_data, "name")) |
1211 | { | 1215 | { |
1212 | /* name means chat user rename */ | 1216 | /* name means chat user rename */ |
1213 | command = 2; | 1217 | command = 2; |
1214 | } | 1218 | } |
1215 | else if (0 == stricmp (frame_data, "ping")) | 1219 | else if (0 == strcasecmp (frame_data, "ping")) |
1216 | { | 1220 | { |
1217 | /* ping means a ping request */ | 1221 | /* ping means a ping request */ |
1218 | command = 3; | 1222 | command = 3; |
@@ -1263,7 +1267,7 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1263 | * This is useful for debugging with an IDE. | 1267 | * This is useful for debugging with an IDE. |
1264 | */ | 1268 | */ |
1265 | char user_index[32]; | 1269 | char user_index[32]; |
1266 | itoa ((int) from_user_id, user_index, 10); | 1270 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1267 | size_t user_index_len = strlen (user_index); | 1271 | size_t user_index_len = strlen (user_index); |
1268 | size_t data_len = user_index_len + frame_len - j + 9; | 1272 | size_t data_len = user_index_len + frame_len - j + 9; |
1269 | char*data = (char*) malloc (data_len + 1); | 1273 | char*data = (char*) malloc (data_len + 1); |
@@ -1300,7 +1304,7 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1300 | * The difference is the prefix "private" | 1304 | * The difference is the prefix "private" |
1301 | */ | 1305 | */ |
1302 | char user_index[32]; | 1306 | char user_index[32]; |
1303 | itoa ((int) from_user_id, user_index, 10); | 1307 | snprintf (user_index, 32, "%d", (int) cu->user_id); |
1304 | size_t user_index_len = strlen (user_index); | 1308 | size_t user_index_len = strlen (user_index); |
1305 | size_t data_len = user_index_len + frame_len - j + 9; | 1309 | size_t data_len = user_index_len + frame_len - j + 9; |
1306 | char*data = (char*) malloc (data_len + 1); | 1310 | char*data = (char*) malloc (data_len + 1); |
@@ -1538,14 +1542,10 @@ connecteduser_parse_received_websocket_stream (struct ConnectedUser*cu, | |||
1538 | char result_text[240]; | 1542 | char result_text[240]; |
1539 | strcpy (result_text, | 1543 | strcpy (result_text, |
1540 | "ping|"); | 1544 | "ping|"); |
1541 | itoa ((int) cu->user_id, | 1545 | snprintf (result_text + 5, 235, "%d", (int) cu->user_id); |
1542 | result_text + 5, | ||
1543 | 10); | ||
1544 | strcat (result_text, | 1546 | strcat (result_text, |
1545 | "|"); | 1547 | "|"); |
1546 | itoa (ping, | 1548 | snprintf (result_text + strlen (result_text), 240 - strlen (result_text), "%d", (int) ping); |
1547 | result_text + strlen (result_text), | ||
1548 | 10); | ||
1549 | chat_addmessage (0, | 1549 | chat_addmessage (0, |
1550 | 0, | 1550 | 0, |
1551 | result_text, | 1551 | result_text, |
@@ -1627,9 +1627,7 @@ connecteduser_send_messages (void*cls) | |||
1627 | ++cu->ping_counter; | 1627 | ++cu->ping_counter; |
1628 | strcpy (cu->ping_message, | 1628 | strcpy (cu->ping_message, |
1629 | "libmicrohttpdchatserverpingdata"); | 1629 | "libmicrohttpdchatserverpingdata"); |
1630 | itoa (cu->ping_counter, | 1630 | snprintf (cu->ping_message + 31, 97, "%d", (int) cu->ping_counter); |
1631 | cu->ping_message + 31, | ||
1632 | 10); | ||
1633 | cu->ping_message_len = strlen (cu->ping_message); | 1631 | cu->ping_message_len = strlen (cu->ping_message); |
1634 | char*frame_data = NULL; | 1632 | char*frame_data = NULL; |
1635 | size_t frame_len = 0; | 1633 | size_t frame_len = 0; |
@@ -1750,7 +1748,7 @@ connecteduser_receive_messages (void *cls) | |||
1750 | { | 1748 | { |
1751 | char user_name[32]; | 1749 | char user_name[32]; |
1752 | strcpy (user_name, "User"); | 1750 | strcpy (user_name, "User"); |
1753 | itoa ((int) cu->user_id, user_name + 4, 10); | 1751 | snprintf (user_name + 4, 28, "%d", (int) cu->user_id); |
1754 | cu->user_name_len = strlen (user_name); | 1752 | cu->user_name_len = strlen (user_name); |
1755 | cu->user_name = malloc (cu->user_name_len + 1); | 1753 | cu->user_name = malloc (cu->user_name_len + 1); |
1756 | if (NULL == cu->user_name) | 1754 | if (NULL == cu->user_name) |
@@ -1831,7 +1829,7 @@ connecteduser_receive_messages (void *cls) | |||
1831 | for (size_t i = 0; i < user_count; ++i) | 1829 | for (size_t i = 0; i < user_count; ++i) |
1832 | { | 1830 | { |
1833 | char user_index[32]; | 1831 | char user_index[32]; |
1834 | itoa ((int) users[i]->user_id, user_index, 10); | 1832 | snprintf (user_index, 32, "%d", (int) users[i]->user_id); |
1835 | size_t user_index_len = strlen (user_index); | 1833 | size_t user_index_len = strlen (user_index); |
1836 | struct UserInit iu; | 1834 | struct UserInit iu; |
1837 | iu.user_init_len = user_index_len + users[i]->user_name_len + 10; | 1835 | iu.user_init_len = user_index_len + users[i]->user_name_len + 10; |
@@ -1891,15 +1889,16 @@ connecteduser_receive_messages (void *cls) | |||
1891 | " /ping <user> - sends a ping to the specified user\n" \ | 1889 | " /ping <user> - sends a ping to the specified user\n" \ |
1892 | " /name <name> - changes your name to the specified name\n" \ | 1890 | " /name <name> - changes your name to the specified name\n" \ |
1893 | " /disconnect - disconnects your websocket\n\n" \ | 1891 | " /disconnect - disconnects your websocket\n\n" \ |
1894 | "All messages, which does not start a slash, are regular messages, which will be sent to selected user.\n\n" \ | 1892 | "All messages, which does not start with a slash, " \ |
1893 | "are regular messages and will be sent to the selected user.\n\n" \ | ||
1895 | "Have fun!"; | 1894 | "Have fun!"; |
1896 | int r = MHD_websocket_encode_text (cu->ws, | 1895 | MHD_websocket_encode_text (cu->ws, |
1897 | welcome_msg, | 1896 | welcome_msg, |
1898 | strlen (welcome_msg), | 1897 | strlen (welcome_msg), |
1899 | MHD_WEBSOCKET_FRAGMENTATION_NONE, | 1898 | MHD_WEBSOCKET_FRAGMENTATION_NONE, |
1900 | &frame_data, | 1899 | &frame_data, |
1901 | &frame_len, | 1900 | &frame_len, |
1902 | NULL); | 1901 | NULL); |
1903 | send_all (cu, | 1902 | send_all (cu, |
1904 | frame_data, | 1903 | frame_data, |
1905 | frame_len); | 1904 | frame_len); |
@@ -2132,7 +2131,7 @@ upgrade_handler (void *cls, | |||
2132 | * @param ptr A pointer for request specific data | 2131 | * @param ptr A pointer for request specific data |
2133 | * @return MHD_YES on success or MHD_NO on error. | 2132 | * @return MHD_YES on success or MHD_NO on error. |
2134 | */ | 2133 | */ |
2135 | static int | 2134 | static enum MHD_Result |
2136 | access_handler (void *cls, | 2135 | access_handler (void *cls, |
2137 | struct MHD_Connection *connection, | 2136 | struct MHD_Connection *connection, |
2138 | const char *url, | 2137 | const char *url, |
@@ -2185,118 +2184,88 @@ access_handler (void *cls, | |||
2185 | * Furthermore it must be a HTTP/1.1 or higher GET request. | 2184 | * Furthermore it must be a HTTP/1.1 or higher GET request. |
2186 | * See: https://tools.ietf.org/html/rfc6455#section-4.2.1 | 2185 | * See: https://tools.ietf.org/html/rfc6455#section-4.2.1 |
2187 | * | 2186 | * |
2188 | * To ease this example we skip the following checks: | 2187 | * To make this example portable we skip the Host check |
2189 | * - Whether the HTTP version is 1.1 or newer | ||
2190 | * - Whether Connection is Upgrade, because this header may | ||
2191 | * contain multiple values. | ||
2192 | * - The requested Host (because we don't know) | ||
2193 | */ | 2188 | */ |
2194 | 2189 | ||
2190 | char is_valid = 1; | ||
2191 | const char* value = NULL; | ||
2192 | char sec_websocket_accept[29]; | ||
2193 | |||
2195 | /* check whether an websocket upgrade is requested */ | 2194 | /* check whether an websocket upgrade is requested */ |
2196 | const char*value = MHD_lookup_connection_value (connection, | 2195 | if (0 != MHD_websocket_check_http_version (version)) |
2197 | MHD_HEADER_KIND, | ||
2198 | MHD_HTTP_HEADER_UPGRADE); | ||
2199 | if ((0 == value) || (0 != stricmp (value, "websocket"))) | ||
2200 | { | 2196 | { |
2201 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2197 | is_valid = 0; |
2202 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2198 | } |
2203 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2199 | value = MHD_lookup_connection_value (connection, |
2204 | MHD_RESPMEM_PERSISTENT); | 2200 | MHD_HEADER_KIND, |
2205 | ret = MHD_queue_response (connection, | 2201 | MHD_HTTP_HEADER_CONNECTION); |
2206 | MHD_HTTP_BAD_REQUEST, | 2202 | if (0 != MHD_websocket_check_connection_header (value)) |
2207 | response); | 2203 | { |
2208 | MHD_destroy_response (response); | 2204 | is_valid = 0; |
2209 | return ret; | 2205 | } |
2206 | value = MHD_lookup_connection_value (connection, | ||
2207 | MHD_HEADER_KIND, | ||
2208 | MHD_HTTP_HEADER_UPGRADE); | ||
2209 | if (0 != MHD_websocket_check_upgrade_header (value)) | ||
2210 | { | ||
2211 | is_valid = 0; | ||
2210 | } | 2212 | } |
2211 | |||
2212 | /* check the protocol version */ | ||
2213 | value = MHD_lookup_connection_value (connection, | 2213 | value = MHD_lookup_connection_value (connection, |
2214 | MHD_HEADER_KIND, | 2214 | MHD_HEADER_KIND, |
2215 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); | 2215 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); |
2216 | if ((0 == value) || (0 != stricmp (value, "13"))) | 2216 | if (0 != MHD_websocket_check_version_header (value)) |
2217 | { | 2217 | { |
2218 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2218 | is_valid = 0; |
2219 | PAGE_INVALID_WEBSOCKET_REQUEST), | ||
2220 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
2221 | MHD_RESPMEM_PERSISTENT); | ||
2222 | ret = MHD_queue_response (connection, | ||
2223 | MHD_HTTP_BAD_REQUEST, | ||
2224 | response); | ||
2225 | MHD_destroy_response (response); | ||
2226 | return ret; | ||
2227 | } | 2219 | } |
2228 | 2220 | value = MHD_lookup_connection_value (connection, | |
2229 | /* read the websocket key (required for the response) */ | 2221 | MHD_HEADER_KIND, |
2230 | value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | ||
2231 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); | 2222 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); |
2232 | if (0 == value) | 2223 | if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept)) |
2233 | { | 2224 | { |
2234 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2225 | is_valid = 0; |
2235 | PAGE_INVALID_WEBSOCKET_REQUEST), | ||
2236 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
2237 | MHD_RESPMEM_PERSISTENT); | ||
2238 | ret = MHD_queue_response (connection, | ||
2239 | MHD_HTTP_BAD_REQUEST, | ||
2240 | response); | ||
2241 | MHD_destroy_response (response); | ||
2242 | return ret; | ||
2243 | } | 2226 | } |
2244 | 2227 | ||
2245 | /* generate the response accept header */ | 2228 | if (1 == is_valid) |
2246 | char sec_websocket_accept[29]; | ||
2247 | if (0 != MHD_websocket_create_accept (value, sec_websocket_accept)) | ||
2248 | { | 2229 | { |
2249 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2230 | /* create the response for upgrade */ |
2250 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2231 | response = MHD_create_response_for_upgrade (&upgrade_handler, |
2251 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2232 | NULL); |
2252 | MHD_RESPMEM_PERSISTENT); | 2233 | |
2234 | /** | ||
2235 | * For the response we need at least the following headers: | ||
2236 | * 1. "Connection: Upgrade" | ||
2237 | * 2. "Upgrade: websocket" | ||
2238 | * 3. "Sec-WebSocket-Accept: <base64value>" | ||
2239 | * The value for Sec-WebSocket-Accept can be generated with MHD_websocket_create_accept_header. | ||
2240 | * It requires the value of the Sec-WebSocket-Key header of the request. | ||
2241 | * See also: https://tools.ietf.org/html/rfc6455#section-4.2.2 | ||
2242 | */ | ||
2243 | MHD_add_response_header (response, | ||
2244 | MHD_HTTP_HEADER_CONNECTION, | ||
2245 | "Upgrade"); | ||
2246 | MHD_add_response_header (response, | ||
2247 | MHD_HTTP_HEADER_UPGRADE, | ||
2248 | "websocket"); | ||
2249 | MHD_add_response_header (response, | ||
2250 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
2251 | sec_websocket_accept); | ||
2253 | ret = MHD_queue_response (connection, | 2252 | ret = MHD_queue_response (connection, |
2254 | MHD_HTTP_BAD_REQUEST, | 2253 | MHD_HTTP_SWITCHING_PROTOCOLS, |
2255 | response); | 2254 | response); |
2256 | MHD_destroy_response (response); | 2255 | MHD_destroy_response (response); |
2257 | return ret; | ||
2258 | } | 2256 | } |
2259 | 2257 | else | |
2260 | /* only for this example: don't accept incoming connection when we are already shutting down */ | ||
2261 | if (0 != disconnect_all) | ||
2262 | { | 2258 | { |
2259 | /* return error page */ | ||
2263 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( | 2260 | struct MHD_Response*response = MHD_create_response_from_buffer (strlen ( |
2264 | PAGE_INVALID_WEBSOCKET_REQUEST), | 2261 | PAGE_INVALID_WEBSOCKET_REQUEST), |
2265 | PAGE_INVALID_WEBSOCKET_REQUEST, | 2262 | PAGE_INVALID_WEBSOCKET_REQUEST, |
2266 | MHD_RESPMEM_PERSISTENT); | 2263 | MHD_RESPMEM_PERSISTENT); |
2267 | ret = MHD_queue_response (connection, | 2264 | ret = MHD_queue_response (connection, |
2268 | MHD_HTTP_SERVICE_UNAVAILABLE, | 2265 | MHD_HTTP_BAD_REQUEST, |
2269 | response); | 2266 | response); |
2270 | MHD_destroy_response (response); | 2267 | MHD_destroy_response (response); |
2271 | return ret; | ||
2272 | } | 2268 | } |
2273 | |||
2274 | /* create the response for upgrade */ | ||
2275 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
2276 | NULL); | ||
2277 | |||
2278 | /** | ||
2279 | * For the response we need at least the following headers: | ||
2280 | * 1. "Connection: Upgrade" | ||
2281 | * 2. "Upgrade: websocket" | ||
2282 | * 3. "Sec-WebSocket-Accept: <base64value>" | ||
2283 | * The value for Sec-WebSocket-Accept can be generated with MHD_websocket_create_accept. | ||
2284 | * It requires the value of the Sec-WebSocket-Key header of the request. | ||
2285 | * See also: https://tools.ietf.org/html/rfc6455#section-4.2.2 | ||
2286 | */ | ||
2287 | MHD_add_response_header (response, | ||
2288 | MHD_HTTP_HEADER_CONNECTION, | ||
2289 | "Upgrade"); | ||
2290 | MHD_add_response_header (response, | ||
2291 | MHD_HTTP_HEADER_UPGRADE, | ||
2292 | "websocket"); | ||
2293 | MHD_add_response_header (response, | ||
2294 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
2295 | sec_websocket_accept); | ||
2296 | ret = MHD_queue_response (connection, | ||
2297 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
2298 | response); | ||
2299 | MHD_destroy_response (response); | ||
2300 | } | 2269 | } |
2301 | else | 2270 | else |
2302 | { | 2271 | { |
@@ -2353,7 +2322,7 @@ main (int argc, | |||
2353 | MHD_OPTION_END); | 2322 | MHD_OPTION_END); |
2354 | #endif | 2323 | #endif |
2355 | 2324 | ||
2356 | if (d == NULL) | 2325 | if (NULL == d) |
2357 | return 1; | 2326 | return 1; |
2358 | (void) getc (stdin); | 2327 | (void) getc (stdin); |
2359 | 2328 | ||