diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-18 22:56:14 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-18 22:56:14 +0000 |
commit | c8b402e00442cd249397d4d33d2723a1f08a8108 (patch) | |
tree | d72a1ace55b42aa9d41c741fa2f757d92fad6592 | |
parent | e4e2223cff658a7016724a625ebbd3dacb92a8f9 (diff) | |
download | luasocket-c8b402e00442cd249397d4d33d2723a1f08a8108.tar.gz luasocket-c8b402e00442cd249397d4d33d2723a1f08a8108.tar.bz2 luasocket-c8b402e00442cd249397d4d33d2723a1f08a8108.zip |
Changed send function.
-rw-r--r-- | FIX | 4 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | doc/introduction.html | 2 | ||||
-rw-r--r-- | doc/tcp.html | 35 | ||||
-rw-r--r-- | src/buffer.c | 23 | ||||
-rw-r--r-- | src/wsocket.c | 2 | ||||
-rw-r--r-- | test/testclnt.lua | 86 | ||||
-rw-r--r-- | test/testsrvr.lua | 33 |
8 files changed, 118 insertions, 70 deletions
@@ -1,3 +1,7 @@ | |||
1 | UDP has a reasonable maximum datagram size | ||
2 | receive accepts the prefix optional argument | ||
3 | send doesn't support multiple arguments anymore | ||
4 | send allows the selection of the substring to be sent | ||
1 | fix bug that caused select return tables not to be associative on windows | 5 | fix bug that caused select return tables not to be associative on windows |
2 | compiles with g++ | 6 | compiles with g++ |
3 | new sample unix domain support | 7 | new sample unix domain support |
@@ -1,4 +1,7 @@ | |||
1 | 1 | ||
2 | fix manual for send and receive | ||
3 | add thanks to mike | ||
4 | |||
2 | change sock:send to use indices just like string.sub? | 5 | change sock:send to use indices just like string.sub? |
3 | use mike's "don't set to blocking before closing unless needed" patch? | 6 | use mike's "don't set to blocking before closing unless needed" patch? |
4 | take a look at DB's smtp patch | 7 | take a look at DB's smtp patch |
diff --git a/doc/introduction.html b/doc/introduction.html index 6468148..20c4d36 100644 --- a/doc/introduction.html +++ b/doc/introduction.html | |||
@@ -113,7 +113,7 @@ The core LuaSocket is almost entirely implemented in C. It is | |||
113 | usually available as a dynamic library which the interpreter can load | 113 | usually available as a dynamic library which the interpreter can load |
114 | with the help of a loader module written in Lua. | 114 | with the help of a loader module written in Lua. |
115 | Beginning with version 2.0 and following the Lua 5.0 trend, all LuaSocket | 115 | Beginning with version 2.0 and following the Lua 5.0 trend, all LuaSocket |
116 | functionality is defined inside tables (or rather a namespaces). No global | 116 | functionality is defined inside tables (or rather namespaces). No global |
117 | variables are ever created. | 117 | variables are ever created. |
118 | Namespaces are obtained with the <tt>require</tt> Lua function, which loads | 118 | Namespaces are obtained with the <tt>require</tt> Lua function, which loads |
119 | and initializes any required library and returns the namespace. | 119 | and initializes any required library and returns the namespace. |
diff --git a/doc/tcp.html b/doc/tcp.html index 5f520e9..30e06f4 100644 --- a/doc/tcp.html +++ b/doc/tcp.html | |||
@@ -260,7 +260,7 @@ method returns <b><tt>nil</tt></b> followed by an error message. | |||
260 | <!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 260 | <!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
261 | 261 | ||
262 | <p class=name id=receive> | 262 | <p class=name id=receive> |
263 | client:<b>receive(</b>[pattern]<b>)</b> | 263 | client:<b>receive(</b>[pattern [, prefix]]<b>)</b> |
264 | </p> | 264 | </p> |
265 | 265 | ||
266 | <p class=description> | 266 | <p class=description> |
@@ -283,6 +283,11 @@ the returned line. This is the default pattern; | |||
283 | of bytes from the socket. | 283 | of bytes from the socket. |
284 | </ul> | 284 | </ul> |
285 | 285 | ||
286 | <p class=parameters> | ||
287 | <tt>Prefix</tt> is an optional string to be concatenated to the beginning | ||
288 | of any received data before return. | ||
289 | </p> | ||
290 | |||
286 | <p class=return> | 291 | <p class=return> |
287 | If successful, the method returns the received pattern. In case of error, | 292 | If successful, the method returns the received pattern. In case of error, |
288 | the method returns <tt><b>nil</b></tt> followed by an error message which | 293 | the method returns <tt><b>nil</b></tt> followed by an error message which |
@@ -305,18 +310,18 @@ too. | |||
305 | <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 310 | <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
306 | 311 | ||
307 | <p class=name id=send> | 312 | <p class=name id=send> |
308 | client:<b>send(</b>string<sub>1</sub> [, | 313 | client:<b>send(</b>data [, i [, j]]<b>)</b> |
309 | string<sub>2</sub>, ... string<sub>N</sub>]<b>)</b> | ||
310 | </p> | 314 | </p> |
311 | 315 | ||
312 | <p class=description> | 316 | <p class=description> |
313 | Sends data through client object. | 317 | Sends <tt>data</tt> through client object. |
314 | </p> | 318 | </p> |
315 | 319 | ||
316 | <p class=parameters> | 320 | <p class=parameters> |
317 | All parameters should be strings. For small strings, it is always better to | 321 | <tt>Data</tt> is the string to be sent. The optional arguments |
318 | concatenate them in Lua (with the '<tt>..</tt>' operator) and pass the | 322 | <tt>i</tt> and <tt>j</tt> work exactly like the standard |
319 | result to LuaSocket instead of passing several independent strings. | 323 | <tt>string.sub</tt> Lua function to allow the selection of a |
324 | substring to be sent. | ||
320 | </p> | 325 | </p> |
321 | 326 | ||
322 | <p class=return> | 327 | <p class=return> |
@@ -341,6 +346,22 @@ Alas, it wasn't returning <tt><b>nil</b></tt> in case of | |||
341 | error. So it was changed again in beta. | 346 | error. So it was changed again in beta. |
342 | </p> | 347 | </p> |
343 | 348 | ||
349 | <p class=note> | ||
350 | <b>Also important</b>: | ||
351 | In order to better support non-blocking I/O and to discourage | ||
352 | bad practice, the <tt>send</tt> method now only sends one string | ||
353 | per call. The other optional arguments allow the user to select | ||
354 | a substring to be sent in a much more efficient way than | ||
355 | using <tt>string.sub</tt>. | ||
356 | </p> | ||
357 | |||
358 | <p class=note> | ||
359 | Note: Output is <em>not</em> buffered. For small strings, | ||
360 | it is always better to concatenate them in Lua | ||
361 | (with the '<tt>..</tt>' operator) and send the result in one call | ||
362 | instead of calling the method several times. | ||
363 | </p> | ||
364 | |||
344 | <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 365 | <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
345 | 366 | ||
346 | <p class=name id=setoption> | 367 | <p class=name id=setoption> |
diff --git a/src/buffer.c b/src/buffer.c index 33fae84..30be156 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
@@ -64,23 +64,24 @@ int buf_meth_getstats(lua_State *L, p_buf buf) { | |||
64 | \*-------------------------------------------------------------------------*/ | 64 | \*-------------------------------------------------------------------------*/ |
65 | int buf_meth_send(lua_State *L, p_buf buf) { | 65 | int buf_meth_send(lua_State *L, p_buf buf) { |
66 | int top = lua_gettop(L); | 66 | int top = lua_gettop(L); |
67 | size_t total = 0; | ||
68 | int arg, err = IO_DONE; | ||
69 | p_tm tm = tm_markstart(buf->tm); | 67 | p_tm tm = tm_markstart(buf->tm); |
70 | for (arg = 2; arg <= top; arg++) { /* first arg is socket object */ | 68 | int err = IO_DONE; |
71 | size_t sent, count; | 69 | size_t size, sent; |
72 | const char *data = luaL_optlstring(L, arg, NULL, &count); | 70 | const char *data = luaL_checklstring(L, 2, &size); |
73 | if (!data || err != IO_DONE) break; | 71 | ssize_t start = (ssize_t) luaL_optnumber(L, 3, 1); |
74 | err = sendraw(buf, data, count, &sent); | 72 | ssize_t end = (ssize_t) luaL_optnumber(L, 4, -1); |
75 | total += sent; | 73 | if (start < 0) start = size+start+1; |
76 | } | 74 | if (end < 0) end = size+end+1; |
75 | if (start < 1) start = 1; | ||
76 | if (end > size) end = size; | ||
77 | if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); | ||
77 | /* check if there was an error */ | 78 | /* check if there was an error */ |
78 | if (err != IO_DONE) { | 79 | if (err != IO_DONE) { |
79 | lua_pushnil(L); | 80 | lua_pushnil(L); |
80 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); | 81 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); |
81 | lua_pushnumber(L, total); | 82 | lua_pushnumber(L, sent); |
82 | } else { | 83 | } else { |
83 | lua_pushnumber(L, total); | 84 | lua_pushnumber(L, sent); |
84 | lua_pushnil(L); | 85 | lua_pushnil(L); |
85 | lua_pushnil(L); | 86 | lua_pushnil(L); |
86 | } | 87 | } |
diff --git a/src/wsocket.c b/src/wsocket.c index d9da6fc..511dbdc 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
@@ -373,12 +373,10 @@ static const char *wstrerror(int err) { | |||
373 | case WSANOTINITIALISED: | 373 | case WSANOTINITIALISED: |
374 | return "Successful WSAStartup not yet performed"; | 374 | return "Successful WSAStartup not yet performed"; |
375 | case WSAEDISCON: return "Graceful shutdown in progress"; | 375 | case WSAEDISCON: return "Graceful shutdown in progress"; |
376 | case WSATYPE_NOT_FOUND: return "Class type not found"; | ||
377 | case WSAHOST_NOT_FOUND: return "Host not found"; | 376 | case WSAHOST_NOT_FOUND: return "Host not found"; |
378 | case WSATRY_AGAIN: return "Nonauthoritative host not found"; | 377 | case WSATRY_AGAIN: return "Nonauthoritative host not found"; |
379 | case WSANO_RECOVERY: return "Nonrecoverable name lookup error"; | 378 | case WSANO_RECOVERY: return "Nonrecoverable name lookup error"; |
380 | case WSANO_DATA: return "Valid name, no data record of requested type"; | 379 | case WSANO_DATA: return "Valid name, no data record of requested type"; |
381 | case WSASYSCALLFAILURE: return "System call failure"; | ||
382 | default: return "Unknown error"; | 380 | default: return "Unknown error"; |
383 | } | 381 | } |
384 | } | 382 | } |
diff --git a/test/testclnt.lua b/test/testclnt.lua index f98a504..356350a 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
@@ -25,7 +25,7 @@ function remote(...) | |||
25 | s = string.gsub(s, "\n", ";") | 25 | s = string.gsub(s, "\n", ";") |
26 | s = string.gsub(s, "%s+", " ") | 26 | s = string.gsub(s, "%s+", " ") |
27 | s = string.gsub(s, "^%s*", "") | 27 | s = string.gsub(s, "^%s*", "") |
28 | control:send(s, "\n") | 28 | control:send(s .. "\n") |
29 | control:receive() | 29 | control:receive() |
30 | end | 30 | end |
31 | 31 | ||
@@ -120,7 +120,7 @@ function test_mixed(len) | |||
120 | local bp1, bp2, bp3, bp4 | 120 | local bp1, bp2, bp3, bp4 |
121 | remote (string.format("str = data:receive(%d)", | 121 | remote (string.format("str = data:receive(%d)", |
122 | string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) | 122 | string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) |
123 | sent, err = data:send(p1, p2, p3, p4) | 123 | sent, err = data:send(p1..p2..p3..p4) |
124 | if err then fail(err) end | 124 | if err then fail(err) end |
125 | remote "data:send(str); data:close()" | 125 | remote "data:send(str); data:close()" |
126 | bp1, err = data:receive() | 126 | bp1, err = data:receive() |
@@ -144,9 +144,9 @@ function test_asciiline(len) | |||
144 | str10 = string.rep("aZb.c#dAe?", math.floor(len/10)) | 144 | str10 = string.rep("aZb.c#dAe?", math.floor(len/10)) |
145 | str = str .. str10 | 145 | str = str .. str10 |
146 | remote "str = data:receive()" | 146 | remote "str = data:receive()" |
147 | sent, err = data:send(str, "\n") | 147 | sent, err = data:send(str.."\n") |
148 | if err then fail(err) end | 148 | if err then fail(err) end |
149 | remote "data:send(str, '\\n')" | 149 | remote "data:send(str ..'\\n')" |
150 | back, err = data:receive() | 150 | back, err = data:receive() |
151 | if err then fail(err) end | 151 | if err then fail(err) end |
152 | if back == str then pass("lines match") | 152 | if back == str then pass("lines match") |
@@ -162,9 +162,9 @@ function test_rawline(len) | |||
162 | math.floor(len/10)) | 162 | math.floor(len/10)) |
163 | str = str .. str10 | 163 | str = str .. str10 |
164 | remote "str = data:receive()" | 164 | remote "str = data:receive()" |
165 | sent, err = data:send(str, "\n") | 165 | sent, err = data:send(str.."\n") |
166 | if err then fail(err) end | 166 | if err then fail(err) end |
167 | remote "data:send(str, '\\n')" | 167 | remote "data:send(str..'\\n')" |
168 | back, err = data:receive() | 168 | back, err = data:receive() |
169 | if err then fail(err) end | 169 | if err then fail(err) end |
170 | if back == str then pass("lines match") | 170 | if back == str then pass("lines match") |
@@ -457,7 +457,62 @@ function getstats_test() | |||
457 | print("ok") | 457 | print("ok") |
458 | end | 458 | end |
459 | 459 | ||
460 | |||
460 | ------------------------------------------------------------------------ | 461 | ------------------------------------------------------------------------ |
462 | function test_nonblocking(size) | ||
463 | reconnect() | ||
464 | remote(string.format([[ | ||
465 | data:send(string.rep("a", %d)) | ||
466 | socket.sleep(0.5) | ||
467 | data:send(string.rep("b", %d)) | ||
468 | ]], size, size)) | ||
469 | local err = "timeout" | ||
470 | local part = "" | ||
471 | local str | ||
472 | data:settimeout(0) | ||
473 | while 1 do | ||
474 | str, err, part = data:receive(2*size - string.len(part), part) | ||
475 | if err ~= "timeout" then break end | ||
476 | end | ||
477 | assert(str == (string.rep("a", size) .. string.rep("b", size))) | ||
478 | reconnect() | ||
479 | remote(string.format([[ | ||
480 | str = data:receive(%d) | ||
481 | socket.sleep(0.5) | ||
482 | str = data:receive(%d, str) | ||
483 | str = data:receive("*l", str) | ||
484 | data:send(str) | ||
485 | data:send("\n") | ||
486 | ]], size, size)) | ||
487 | data:settimeout(0) | ||
488 | local sofar = 1 | ||
489 | while 1 do | ||
490 | _, err, part = data:send(str, sofar) | ||
491 | if err ~= "timeout" then break end | ||
492 | sofar = sofar + part | ||
493 | end | ||
494 | data:send("\n") | ||
495 | data:settimeout(-1) | ||
496 | local back = data:receive() | ||
497 | assert(back == str) | ||
498 | print("ok") | ||
499 | end | ||
500 | |||
501 | |||
502 | ------------------------------------------------------------------------ | ||
503 | test("non-blocking transfer") | ||
504 | test_nonblocking(1) | ||
505 | test_nonblocking(17) | ||
506 | test_nonblocking(200) | ||
507 | test_nonblocking(4091) | ||
508 | test_nonblocking(80199) | ||
509 | test_nonblocking(8000000) | ||
510 | test_nonblocking(80199) | ||
511 | test_nonblocking(4091) | ||
512 | test_nonblocking(200) | ||
513 | test_nonblocking(17) | ||
514 | test_nonblocking(1) | ||
515 | |||
461 | test("method registration") | 516 | test("method registration") |
462 | test_methods(socket.tcp(), { | 517 | test_methods(socket.tcp(), { |
463 | "accept", | 518 | "accept", |
@@ -548,7 +603,6 @@ test_mixed(1) | |||
548 | 603 | ||
549 | 604 | ||
550 | test("binary line") | 605 | test("binary line") |
551 | reconnect() | ||
552 | test_rawline(1) | 606 | test_rawline(1) |
553 | test_rawline(17) | 607 | test_rawline(17) |
554 | test_rawline(200) | 608 | test_rawline(200) |
@@ -562,24 +616,6 @@ test_rawline(17) | |||
562 | test_rawline(1) | 616 | test_rawline(1) |
563 | 617 | ||
564 | test("raw transfer") | 618 | test("raw transfer") |
565 | reconnect() | ||
566 | test_raw(1) | ||
567 | test_raw(17) | ||
568 | test_raw(200) | ||
569 | test_raw(4091) | ||
570 | test_raw(80199) | ||
571 | test_raw(8000000) | ||
572 | test_raw(80199) | ||
573 | test_raw(4091) | ||
574 | test_raw(200) | ||
575 | test_raw(17) | ||
576 | test_raw(1) | ||
577 | |||
578 | test("non-blocking transfer") | ||
579 | reconnect() | ||
580 | -- the value is not important, we only want | ||
581 | -- to test non-blocking I/O anyways | ||
582 | data:settimeout(200) | ||
583 | test_raw(1) | 619 | test_raw(1) |
584 | test_raw(17) | 620 | test_raw(17) |
585 | test_raw(200) | 621 | test_raw(200) |
diff --git a/test/testsrvr.lua b/test/testsrvr.lua index 969f95b..23e3850 100644 --- a/test/testsrvr.lua +++ b/test/testsrvr.lua | |||
@@ -1,29 +1,14 @@ | |||
1 | socket = require"socket" | 1 | socket = require("socket"); |
2 | 2 | host = host or "localhost"; | |
3 | host = host or "localhost" | 3 | port = port or "8080"; |
4 | port = port or "8080" | 4 | server = assert(socket.bind(host, port)); |
5 | 5 | ack = "\n"; | |
6 | server, error = socket.bind(host, port) | ||
7 | if not server then print("server: " .. tostring(error)) os.exit() end | ||
8 | ack = "\n" | ||
9 | while 1 do | 6 | while 1 do |
10 | print("server: waiting for client connection..."); | 7 | print("server: waiting for client connection..."); |
11 | control, error = server:accept() | 8 | control = assert(server:accept()); |
12 | assert(control, error) | ||
13 | -- control:setoption("nodelay", true) | ||
14 | while 1 do | 9 | while 1 do |
15 | command, error = control:receive() | 10 | command = assert(control:receive()); |
16 | if error then | 11 | assert(control:send(ack)); |
17 | control:close() | 12 | (loadstring(command))(); |
18 | print("server: closing connection...") | ||
19 | break | ||
20 | end | ||
21 | sent, error = control:send(ack) | ||
22 | if error then | ||
23 | control:close() | ||
24 | print("server: closing connection...") | ||
25 | break | ||
26 | end | ||
27 | (loadstring(command))() | ||
28 | end | 13 | end |
29 | end | 14 | end |