关于send(Handle(this),256,9,Long(0,0))的说明

本文解析了send函数中Handle(this),256,9,Long(0,0)的具体含义,详细解释了WM_KEYDOWN消息及其参数的意义,并介绍了如何通过send函数模拟键盘TAB键事件。

关于

send(Handle(this),256,9,Long(0,0))

的说明

 

数据窗口中要将回车将转换成

TAB

键用到了

send(Handle(this),256,9,Long(0,0))

但是很多

人不知道知其然而不知其所以然。这里贴点资料,相信大家看了之后就明白了。

 

其中第二个参数

256

,转换为

16

进制就是

100

,我们在下面的资料中可以找到

 

WM_KEYFIRST = $0100; 

WM_KEYDOWN = $0100; 

 

file://

message#An UnsignedInteger whose value is the system message number of the message you want to 

send 

这其中的

message#

就是楼上说的

WM_COMMAND

其定义可以从微软的

SDK

中的

WINDOWS.H

中找到

 

WM_NULL            = $0000; 

WM_CREATE          = $0001; 

应用程序创建一个窗口

 

WM_DESTROY          = $0002; 

一个窗口被销毁

 

WM_MOVE            = $0003; 

移动一个窗口

 

WM_SIZE            = $0005; 

改变一个窗口的大小

 

WM_ACTIVATE        = $0006; 

一个窗口被激活或失去激活状态;

 

WM_SETFOCUS        = $0007; 

获得焦点后

 

WM_KILLFOCUS        = $0008; 

失去焦点

 

WM_ENABLE          = $000A; 

改变

enable

状态

 

WM_SETREDRAW        = $000B; 

设置窗口是否能重画

   

WM_SETTEXT          = $000C; 

应用程序发送此消息来设置一个窗口的文本

 

WM_GETTEXT          = $000D; 

应用程序发送此消息来复制对应窗口的文本到缓冲区

 

WM_GETTEXTLENGTH    = $000E; 

得到与一个窗口有关的文本的长度(不包含空字符)

 

WM_PAINT            = $000F; 

要求一个窗口重画自己

 

WM_CLOSE            = $0010; 

当一个窗口或应用程序要关闭时发送一个信号

 

WM_QUERYENDSESSION  = $0011; 

当用户选择结束对话框或程序自己调用

ExitWindows

函数

 

WM_QUIT            = $0012; 

用来结束程序运行或当程序调用

postquitmessage

函数

 

 

WM_QUERYOPEN        = $0013; 

当用户窗口恢复以前的大小位置时,把此消息发送给某个图标

 

WM_ERASEBKGND      = $0014; 

当窗口背景必须被擦除时(例在窗口改变大小时)

 

WM_SYSCOLORCHANGE  = $0015; 

当系统颜色改变时,发送此消息给所有顶级窗口

 

WM_ENDSESSION      = $0016; 

当系统进程发出

WM_QUERYENDSESSION

消息后,此消息发送给应用程序,

 

通知它对话是否结束

 

WM_SYSTEMERROR      = $0017; 

WM_SHOWWINDOW      = $0018; 

当隐藏或显示窗口是发送此消息给这个窗口

 

_ACTIVATEAPP      = $001C; 

发此消息给应用程序哪个窗口是激活的,哪个是非激活的;

 

WM_FONTCHANGE      = $001D; 

当系统的字体资源库变化时发送此消息给所有顶级窗口

 

WM_TIMECHANGE      = $001E; 

当系统的时间变化时发送此消息给所有顶级窗口

 

WM_CANCELMODE      = $001F; 

发送此消息来取消某种正在进行的摸态(操作)

 

WM_SETCURSOR        = $0020; 

如果鼠标引起光标在某个窗口中移动且鼠标输入没有被捕获时,就发消息给某个窗口

 

WM_MOUSEACTIVATE    = $0021; 

当光标在某个非激活的窗口中而用户正按着鼠标的某个键发送此消息给当前窗口

 

WM_CHILDACTIVATE    = $0022; 

发送此消息给

MDI

子窗口当用户点击此窗口的标题栏,或当窗口被激活,移动,改变大小

 

WM_QUEUESYNC        = $0023; 

此消息由基于计算机的训练程序发送,通过

WH_JOURNALPALYBACK

hook

程序

 

分离出用户输入消息

 

WM_GETMINMAXINFO    = $0024; 

此消息发送给窗口当它将要改变大小或位置;

 

 

WM_PAINTICON        = $0026; 

发送给最小化窗口当它图标将要被重画

 

WM_ICONERASEBKGND  = $0027; 

此消息发送给某个最小化窗口,仅当它在画图标前它的背景必须被重画

 

WM_NEXTDLGCTL      = $0028; 

发送此消息给一个对话框程序去更改焦点位置

 

WM_SPOOLERSTATUS    = $002A; 

每当打印管理列队增加或减少一条作业时发出此消息

 

 

WM_DRAWITEM        = $002B; 

button

combobox

listbox

menu

的可视外观改变时发送

 

此消息给这些空件的所有者

 

WM_MEASUREITEM      = $002C; 

button, combo box, list box, list view control, or menu item 

被创建时

 

发送此消息给控件的所有者

 

WM_DELETEITEM      = $002D; 

the 

list 

box 

 

combo 

box 

 

 

 

LB_DELETESTRING, 

LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 

消息

 

WM_VKEYTOITEM      = $002E; 

此消息有一个

LBS_WANTKEYBOARDINPUT

风格的发出给它的所有者来响应

WM_KEYDOWN

消息

   

WM_CHARTOITEM      = $002F; 

此消息由一个

LBS_WANTKEYBOARDINPUT

风格的列表框发送给他的所有者来响应

WM_CHAR

消息

   

WM_SETFONT          = $0030; 

当绘制文本时程序发送此消息得到控件要用的颜色

 

 

WM_GETFONT          = $0031; 

应用程序发送此消息得到当前控件绘制文本的字体

 

WM_SETHOTKEY        = $0032; 

应用程序发送此消息让一个窗口与一个热键相关连

 

WM_GETHOTKEY        = $0033; 

应用程序发送此消息来判断热键与某个窗口是否有关联

 

WM_QUERYDRAGICON    = $0037; 

此消息发送给最小化窗口,当此窗口将要被拖放而它的类中没有定义图标,应用程序能

 

返回一个图标或光标的句柄,当用户拖放图标时系统显示这个图标或光标

 

WM_COMPAREITEM      = $0039; 

发送此消息来判定

combobox

listbox

新增加的项的相对位置

 

WM_GETOBJECT        = $003D; 

WM_COMPACTING      = $0041; 

显示内存已经很少了

 

WM_WINDOWPOSCHANGING = $0046; 

发送此消息给那个窗口的大小和位置将要被改变时,来调用

setwindowpos

函数或其它窗口管理函数

 

WM_WINDOWPOSCHANGED = $0047; 

发送此消息给那个窗口的大小和位置已经被改变时,来调用

setwindowpos

函数或其它窗口管理函数

 

WM_POWER            = $0048;

(适用于

16

位的

windows

 

当系统将要进入暂停状态时发送此消息

 

WM_COPYDATA        = $004A; 

当一个应用程序传递数据给另一个应用程序时发送此消息

 

WM_CANCELJOURNAL    = $004B; 

当某个用户取消程序日志激活状态,提交此消息给程序

 

WM_NOTIFY          = $004E; 

当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口

 

WM_INPUTLANGCHANGEREQUEST = $0050; 

当用户选择某种输入语言,或输入语言的热键改变

 

WM_INPUTLANGCHANGE  = $0051; 

当平台现场已经被改变后发送此消息给受影响的最顶级窗口

 

WM_TCARD            = $0052; 

当程序已经初始化

windows

帮助例程时发送此消息给应用程序

 

WM_HELP            = $0053; 

此消息显示用户按下了

F1

,如果某个菜单是激活的,就发送此消息个此窗口关联的菜单,否则就

 

发送给有焦点的窗口,如果当前都没有焦点,就把此消息发送给当前激活的窗口

 

WM_USERCHANGED      = $0054; 

当用户已经登入或退出后发送此消息给所有的窗口,当用户登入或退出时系统更新用户的具体

 

设置信息,在用户更新设置时系统马上发送此消息;

 

WM_NOTIFYformAT    = $0055; 

公用控件,自定义控件和他们的父窗口通过此消息来判断控件是使用

ANSI

还是

UNICODE

结构

 

WM_NOTIFY

消息,使用此控件能使某个控件与它的父控件之间进行相互通信

 

WM_CONTEXTMENU      = $007B; 

WM_styleCHANGING    = $007C; 

当调用

SETWINDOWLONG

函数将要改变一个或多个

 

窗口的风格时发送此消息给那个窗口

 

WM_styleCHANGED    = $007D; 

当调用

SETWINDOWLONG

函数一个或多个

 

窗口的风格后发送此消息给那个窗口

 

WM_DISPLAYCHANGE    = $007E; 

当显示器的分辨率改变后发送此消息给所有的窗口

 

WM_GETICON          = $007F; 

此消息发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄;

 

WM_SETICON          = $0080; 

程序发送此消息让一个新的大图标或小图标与某个窗口关联;

 

WM_NCCREATE        = $0081; 

当某个窗口第一次被创建时,此消息在

WM_CREATE

消息发送前发送;

 

WM_NCDESTROY        = $0082; 

此消息通知某个窗口,非客户区正在销毁

 

WM_NCCALCSIZE      = $0083; 

当某个窗口的客户区域必须被核算时发送此消息

 

WM_NCHITTEST        = $0084;//

移动鼠标,按住或释放鼠标时发生

 

WM_NCPAINT          = $0085; 

程序发送此消息给某个窗口当它(窗口)的框架必须被绘制时;

 

WM_NCACTIVATE      = $0086; 

此消息发送给某个窗口

 

仅当它的非客户区需要被改变来显示是激活还是非激活状态;

 

WM_GETDLGCODE      = $0087; 

发送此消息给某个与对话框程序关联的控件,

widdows

控制方位键和

TAB

键使输入进入此控件

 

通过响应

WM_GETDLGCODE

消息,应用程序可以把他当成一个特殊的输入控件并能处理它

 

WM_NCMOUSEMOVE      = $00A0; 

当光标在一个窗口的非客户区内移动时发送此消息给这个窗口

      file://

/

客户区为:窗体的标题栏及

                                                                     

                                                             

的边框体

 

WM_NCLBUTTONDOWN    = $00A1; 

当光标在一个窗口的非客户区同时按下鼠标左键时提交此消息

 

WM_NCLBUTTONUP      = $00A2; 

当用户释放鼠标左键同时光标某个窗口在非客户区十发送此消息;

 

WM_NCLBUTTONDBLCLK  = $00A3; 

当用户双击鼠标左键同时光标某个窗口在非客户区十发送此消息

 

WM_NCRBUTTONDOWN    = $00A4; 

当用户按下鼠标右键同时光标又在窗口的非客户区时发送此消息

 

WM_NCRBUTTONUP      = $00A5; 

当用户释放鼠标右键同时光标又在窗口的非客户区时发送此消息

 

WM_NCRBUTTONDBLCLK  = $00A6; 

当用户双击鼠标右键同时光标某个窗口在非客户区十发送此消息

 

WM_NCMBUTTONDOWN    = $00A7; 

当用户按下鼠标中键同时光标又在窗口的非客户区时发送此消息

 

WM_NCMBUTTONUP      = $00A8; 

当用户释放鼠标中键同时光标又在窗口的非客户区时发送此消息

 

WM_NCMBUTTONDBLCLK  = $00A9; 

当用户双击鼠标中键同时光标又在窗口的非客户区时发送此消息

 

WM_KEYFIRST        = $0100; 

WM_KEYDOWN          = $0100; 

 

WM_MOUSEFIRST      = $0200; 

WM_MOUSEMOVE        = $0200;   

                 //  

移动鼠标

 

WM_LBUTTONDOWN      = $0201; 

 

                   file://

/

下鼠标左键

 

WM_LBUTTONUP        = $0202; 

 

                 file://

/

放鼠标左键

下一个键

 

 

第三参数:

9

的说明

 

我们在下面键和键码对照表中可以找到

tab

的键码是

9

 

键码对照表

 

 

其他触发键的功能

:

 

除了

send

以外,我们还可以使用一个

api

 

keybd_event

 

其声明格式为:

 

Function long keybd_event(INTEGER bVk ,INTEGER bScan , Long dwFlags ,Long dwExtraInfo ) 

Library "user32"

 

按下一个键:

 

keybd_event(

键码

,0,0,0)

 

弹起一个键

 

keybd_event(

键码

,0,2,0) 

如要实现大小写切换,我们可以用

keybd_event

按下

caps lock

,然后在弹起

caps lock 

代码如下:

 


int pr_data_xfer(char *cl_buf, size_t cl_size) { int len = 0; int total = 0; int res = 0; pool *tmp_pool = NULL; if (cl_buf == NULL || cl_size == 0) { errno = EINVAL; return -1; } /* Poll the control channel for any commands we should handle, like * QUIT or ABOR. */ poll_ctrl(); /* If we don&#39;t have a data connection here (e.g. might have been closed * by an ABOR), then return zero (no data transferred). */ if (session.d == NULL) { int xerrno; #if defined(ECONNABORTED) xerrno = ECONNABORTED; #elif defined(ENOTCONN) xerrno = ENOTCONN; #else xerrno = EIO; #endif pr_trace_msg(trace_channel, 1, "data connection is null prior to data transfer (possibly from " "aborted transfer), returning &#39;%s&#39; error", strerror(xerrno)); pr_log_debug(DEBUG5, "data connection is null prior to data transfer (possibly from " "aborted transfer), returning &#39;%s&#39; error", strerror(xerrno)); errno = xerrno; return -1; } if (session.xfer.direction == PR_NETIO_IO_RD) { char *buf; buf = session.xfer.buf; /* We use ASCII translation if: * * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set */ if (((session.sf_flags & SF_ASCII) && !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) { int adjlen, buflen; do { buflen = session.xfer.buflen; /* how much remains in buf */ adjlen = 0; pr_signals_handle(); len = pr_netio_read(session.d->instrm, buf + buflen, session.xfer.bufsize - buflen, 1); while (len < 0) { int xerrno = errno; if (xerrno == EAGAIN || xerrno == EINTR) { /* Since our socket is in non-blocking mode, read(2) can return * EAGAIN if there is no data yet for us. Handle this by * delaying temporarily, then trying again. */ errno = EINTR; pr_signals_handle(); len = pr_netio_read(session.d->instrm, buf + buflen, session.xfer.bufsize - buflen, 1); continue; } destroy_pool(tmp_pool); errno = xerrno; return -1; } if (len > 0 && data_first_byte_read == FALSE) { if (pr_trace_get_level(timing_channel)) { unsigned long elapsed_ms; uint64_t read_ms; pr_gettimeofday_millis(&read_ms); elapsed_ms = (unsigned long) (read_ms - data_start_ms); pr_trace_msg(timing_channel, 7, "Time for first data byte read: %lu ms", elapsed_ms); } data_first_byte_read = TRUE; } if (len > 0) { pr_trace_msg(trace_channel, 19, "read %d %s from network", len, len != 1 ? "bytes" : "byte"); buflen += len; if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } } /* If buflen > 0, data remains in the buffer to be copied. */ if (len >= 0 && buflen > 0) { /* Perform ASCII translation: * * buflen: is returned as the modified buffer length after * translation * res: is returned as the number of characters unprocessed in * the buffer (to be dealt with later) * * We skip the call to pr_ascii_ftp_from_crlf() in one case: * when we have one character in the buffer and have reached * end of data, this is so that pr_ascii_ftp_from_crlf() won&#39;t sit * forever waiting for the next character after a final &#39;\r&#39;. */ if (len > 0 || buflen > 1) { size_t outlen = 0; if (tmp_pool == NULL) { tmp_pool = make_sub_pool(session.xfer.p); pr_pool_tag(tmp_pool, "ASCII upload"); } res = pr_ascii_ftp_from_crlf(tmp_pool, buf, buflen, &buf, &outlen); if (res < 0) { pr_trace_msg(trace_channel, 3, "error reading ASCII data: %s", strerror(errno)); } else { adjlen += res; buflen = (int) outlen; } } /* Now copy everything we can into cl_buf */ if ((size_t) buflen > cl_size) { /* Because we have to cut our buffer short, make sure this * is made up for later by increasing adjlen. */ adjlen += (buflen - cl_size); buflen = cl_size; } memcpy(cl_buf, buf, buflen); /* Copy whatever remains at the end of session.xfer.buf to the * head of the buffer and adjust buf accordingly. * * adjlen is now the total bytes still waiting in buf, if * anything remains, copy it to the start of the buffer. */ if (adjlen > 0) { memcpy(buf, buf + buflen, adjlen); } /* Store everything back in session.xfer. */ session.xfer.buflen = adjlen; total += buflen; } /* Restart if data was returned by pr_netio_read() (len > 0) but no * data was copied to the client buffer (buflen = 0). This indicates * that pr_ascii_ftp_from_crlf() needs more data in order to * translate, so we need to call pr_netio_read() again. */ } while (len > 0 && buflen == 0); /* Return how much data we actually copied into the client buffer. */ len = buflen; } else { len = pr_netio_read(session.d->instrm, cl_buf, cl_size, 1); while (len < 0) { int xerrno = errno; if (xerrno == EAGAIN || xerrno == EINTR) { /* Since our socket is in non-blocking mode, read(2) can return * EAGAIN if there is no data yet for us. Handle this by * delaying temporarily, then trying again. */ errno = EINTR; pr_signals_handle(); len = pr_netio_read(session.d->instrm, cl_buf, cl_size, 1); continue; } break; } if (len > 0) { pr_trace_msg(trace_channel, 19, "read %d %s from network", len, len != 1 ? "bytes" : "byte"); if (data_first_byte_read == FALSE) { if (pr_trace_get_level(timing_channel)) { unsigned long elapsed_ms; uint64_t read_ms; pr_gettimeofday_millis(&read_ms); elapsed_ms = (unsigned long) (read_ms - data_start_ms); pr_trace_msg(timing_channel, 7, "Time for first data byte read: %lu ms", elapsed_ms); } data_first_byte_read = TRUE; } /* Non-ASCII mode doesn&#39;t need to use session.xfer.buf */ if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } total += len; } } } else { /* PR_NETIO_IO_WR */ while (cl_size) { int bwrote = 0; int buflen = cl_size; unsigned int xferbuflen; char *xfer_buf = NULL; pr_signals_handle(); if (buflen > pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR)) { buflen = pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR); } xferbuflen = buflen; /* Fill up our internal buffer. */ memcpy(session.xfer.buf, cl_buf, buflen); /* We use ASCII translation if: * * - SF_ASCII_OVERRIDE session flag is set (e.g. for LIST/NLST) * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set */ if ((session.sf_flags & SF_ASCII_OVERRIDE) || ((session.sf_flags & SF_ASCII) && !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) { char *out = NULL; size_t outlen = 0; if (tmp_pool == NULL) { tmp_pool = make_sub_pool(session.xfer.p); pr_pool_tag(tmp_pool, "ASCII download"); } /* Scan the internal buffer, looking for LFs with no preceding CRs. * Add CRs (and expand the internal buffer) as necessary. xferbuflen * will be adjusted so that it contains the length of data in * the internal buffer, including any added CRs. */ res = pr_ascii_ftp_to_crlf(tmp_pool, session.xfer.buf, xferbuflen, &out, &outlen); if (res < 0) { pr_trace_msg(trace_channel, 1, "error writing ASCII data: %s", strerror(errno)); } else { xfer_buf = session.xfer.buf; session.xfer.buf = out; session.xfer.buflen = xferbuflen = outlen; } } bwrote = pr_netio_write(session.d->outstrm, session.xfer.buf, xferbuflen); while (bwrote < 0) { int xerrno = errno; if (xerrno == EAGAIN || xerrno == EINTR) { /* Since our socket is in non-blocking mode, write(2) can return * EAGAIN if there is not enough from for our data yet. Handle * this by delaying temporarily, then trying again. */ errno = EINTR; pr_signals_handle(); bwrote = pr_netio_write(session.d->outstrm, session.xfer.buf, xferbuflen); continue; } destroy_pool(tmp_pool); if (xfer_buf != NULL) { /* Free up the malloc&#39;d memory. */ free(session.xfer.buf); session.xfer.buf = xfer_buf; } errno = xerrno; return -1; } if (bwrote > 0) { pr_trace_msg(trace_channel, 19, "wrote %d %s to network", bwrote, bwrote != 1 ? "bytes" : "byte"); if (data_first_byte_written == FALSE) { if (pr_trace_get_level(timing_channel)) { unsigned long elapsed_ms; uint64_t write_ms; pr_gettimeofday_millis(&write_ms); elapsed_ms = (unsigned long) (write_ms - data_start_ms); pr_trace_msg(timing_channel, 7, "Time for first data byte written: %lu ms", elapsed_ms); } data_first_byte_written = TRUE; } if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } cl_size -= buflen; cl_buf += buflen; total += buflen; } if (xfer_buf != NULL) { /* Yes, we are using malloc et al here, rather than the memory pools. * See Bug#4352 for details. */ free(session.xfer.buf); session.xfer.buf = xfer_buf; } } len = total; } if (total && timeout_idle) { pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); } session.xfer.total_bytes += total; session.total_bytes += total; if (session.xfer.direction == PR_NETIO_IO_RD) { session.total_bytes_in += total; } else { session.total_bytes_out += total; } destroy_pool(tmp_pool); return (len < 0 ? -1 : len); } #if defined(HAVE_SENDFILE) /* pr_data_sendfile() actually transfers the data on the data connection. * ASCII translation is not performed. * return 0 if reading and data connection closes, or -1 if error */ pr_sendfile_t pr_data_sendfile(int retr_fd, off_t *offset, off_t count) { int flags, error; pr_sendfile_t len = 0, total = 0; # if defined(HAVE_AIX_SENDFILE) struct sf_parms parms; int rc; # endif /* HAVE_AIX_SENDFILE */ if (offset == NULL || count == 0) { errno = EINVAL; return -1; } if (session.xfer.direction == PR_NETIO_IO_RD) { errno = EPERM; return -1; } if (session.d == NULL) { errno = EPERM; return -1; } flags = fcntl(PR_NETIO_FD(session.d->outstrm), F_GETFL); if (flags < 0) { return -1; } /* Set fd to blocking-mode for sendfile() */ if (flags & O_NONBLOCK) { if (fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags^O_NONBLOCK) < 0) { return -1; } } for (;;) { # if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_SOLARIS_SENDFILE) off_t orig_offset = *offset; /* Linux semantics are fairly straightforward in a glibc 2.x world: * * #include <sys/sendfile.h> * * ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count) * * Unfortunately, this API does not allow for an off_t number of bytes * to be sent, only a size_t. This means we need to make sure that * the given count does not exceed the maximum value for a size_t. Even * worse, the return value is a ssize_t, not a size_t, which means * the maximum value used can only be of the maximum _signed_ value, * not the maximum unsigned value. This means calling sendfile() more * times. How annoying. */ # if defined(HAVE_LINUX_SENDFILE) if (count > INT_MAX) { count = INT_MAX; } # elif defined(HAVE_SOLARIS_SENDFILE) # if SIZEOF_SIZE_T == SIZEOF_INT if (count > INT_MAX) { count = INT_MAX; } # elif SIZEOF_SIZE_T == SIZEOF_LONG if (count > LONG_MAX) { count = LONG_MAX; } # elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG if (count > LLONG_MAX) { count = LLONG_MAX; } # endif # endif /* !HAVE_SOLARIS_SENDFILE */ errno = 0; len = sendfile(PR_NETIO_FD(session.d->outstrm), retr_fd, offset, count); /* If no data could be written (e.g. the file was truncated), we&#39;re * done (Bug#4318). */ if (len == 0) { if (errno != EINTR && errno != EAGAIN) { break; } /* Handle our interrupting signal, and continue. */ pr_signals_handle(); } if (len != -1 && len < count) { /* Under Linux semantics, this occurs when a signal has interrupted * sendfile(). */ if (XFER_ABORTED) { errno = EINTR; session.xfer.total_bytes += len; session.total_bytes += len; session.total_bytes_out += len; session.total_raw_out += len; return -1; } count -= len; /* Only reset the timers if data have actually been written out. */ if (len > 0) { if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } if (timeout_idle) { pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); } } session.xfer.total_bytes += len; session.total_bytes += len; session.total_bytes_out += len; session.total_raw_out += len; total += len; pr_signals_handle(); continue; } if (len == -1) { /* Linux updates offset on error, not len like BSD, fix up so * BSD-based code works. */ len = *offset - orig_offset; *offset = orig_offset; # elif defined(HAVE_BSD_SENDFILE) /* BSD semantics for sendfile are flexible...it&#39;d be nice if we could * standardize on something like it. The semantics are: * * #include <sys/types.h> * #include <sys/socket.h> * #include <sys/uio.h> * * int sendfile(int in_fd, int out_fd, off_t offset, size_t count, * struct sf_hdtr *hdtr, off_t *len, int flags) * * The comments above, about size_t versus off_t, apply here as * well. Except that BSD&#39;s sendfile() uses an off_t * for returning * the number of bytes sent, so we can use the maximum unsigned * value. */ # if SIZEOF_SIZE_T == SIZEOF_INT if (count > UINT_MAX) { count = UINT_MAX; } # elif SIZEOF_SIZE_T == SIZEOF_LONG if (count > ULONG_MAX) { count = ULONG_MAX; } # elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG if (count > ULLONG_MAX) { count = ULLONG_MAX; } # endif if (sendfile(retr_fd, PR_NETIO_FD(session.d->outstrm), *offset, count, NULL, &len, 0) == -1) { # elif defined(HAVE_MACOSX_SENDFILE) off_t orig_len = count; int res; /* Since Mac OSX uses the fourth argument as a value-return parameter, * success or failure, we need to put the result into len after the * call. */ res = sendfile(retr_fd, PR_NETIO_FD(session.d->outstrm), *offset, &orig_len, NULL, 0); len = orig_len; if (res < 0) { # elif defined(HAVE_AIX_SENDFILE) memset(&parms, 0, sizeof(parms)); parms.file_descriptor = retr_fd; parms.file_offset = (uint64_t) *offset; parms.file_bytes = (int64_t) count; rc = send_file(&(PR_NETIO_FD(session.d->outstrm)), &(parms), (uint_t)0); len = (int) parms.bytes_sent; if (rc < -1 || rc == 1) { # else if (FALSE) { # endif /* HAVE_AIX_SENDFILE */ /* IMO, BSD&#39;s semantics are warped. Apparently, since we have our * alarms tagged SA_INTERRUPT (allowing system calls to be * interrupted - primarily for select), BSD will interrupt a * sendfile operation as well, so we have to catch and handle this * case specially. It should also be noted that the sendfile(2) man * page doesn&#39;t state any of this. * * HP/UX has the same semantics, however, EINTR is well documented * as a side effect in the sendfile(2) man page. HP/UX, however, * is implemented horribly wrong. If a signal would result in * -1 being returned and EINTR being set, what ACTUALLY happens is * that errno is cleared and the number of bytes written is returned. * * For obvious reasons, HP/UX sendfile is not supported yet. */ if (errno == EINTR) { if (XFER_ABORTED) { session.xfer.total_bytes += len; session.total_bytes += len; session.total_bytes_out += len; session.total_raw_out += len; return -1; } pr_signals_handle(); /* If we got everything in this transaction, we&#39;re done. */ if (len >= count) { break; } count -= len; *offset += len; if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } if (timeout_idle) { pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); } session.xfer.total_bytes += len; session.total_bytes += len; session.total_bytes_out += len; session.total_raw_out += len; total += len; continue; } error = errno; (void) fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags); errno = error; return -1; } break; } if (flags & O_NONBLOCK) { (void) fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags); } if (timeout_stalled) { pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); } if (timeout_idle) { pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); } session.xfer.total_bytes += len; session.total_bytes += len; session.total_bytes_out += len; session.total_raw_out += len; total += len; return total; } #else pr_sendfile_t pr_data_sendfile(int retr_fd, off_t *offset, off_t count) { errno = ENOSYS; return -1; } #endif /* HAVE_SENDFILE */
最新发布
10-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值