diff --git a/documentation/history.doc b/documentation/history.doc index 90642eb..4f74afd 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -2725,3 +2725,50 @@ smbfs 2.5 (16.12.2018) - This version fixes the instant crash in the fully optimized 68k/020+ builds, which was cased by a missing __saveds keyword. + + +smbfs 2.6 (16.12.2018) + +- Added the WRITETHRESHOLD parameter which can be used to disable the + separate transmission of the SMB message header and its payload if + the combined sizes of both are smaller than or equal to the + threshold value. This is intended to improve write performance for + small amounts of data which would otherwise linger in the + transmission queue. + + +smbfs 2.7 (17.12.2018) + +- Added the READTHRESHOLD counterpart to WRITETHRESHOLD which affects + the read operations. + +- The smb_receive_raw() function in "sock.c" no longer copies the NetBIOS + header into the receive buffer separately, but makes sure that the + initial receive operation takes care of it. + +- The allocate_path_name() function in "smb_abstraction.c" failed to put + the path separator character where it should be, resulting in the path + name and the file/directory name to get lumped together. This affected + creation of files and directories both. + + +smbfs 2.8 (19.12.2018) + +- The default values for READTHRESHOLD and WRITETHRESHOLD now have the + effect of transmitting the SMB header and the payload separately, + just like it was introduces in version 2.1. + + Use something like READTHRESHOLD=1500 and WRITETHRESHOLD=1500 to + send packets smaller than or equal to 1500 bytes as a combined + lump of data, and data larger than 1500 bytes as separate SMB + header and payload. + +- When processing the share name the limitations on the individual + components (server name, share, port number/IP service name) are + no longer verified using hard-coded lengths, but use the respective + buffer limits instead. The port number/IP service name length + check is new. + +- Added more debug log output to the code which now performs the + file and lock name/address lookups instead of walking through + the entire file/lock lists. diff --git a/source_code/include/smb/smb_fs_sb.h b/source_code/include/smb/smb_fs_sb.h index 0b5c5bb..0aa8fe9 100644 --- a/source_code/include/smb/smb_fs_sb.h +++ b/source_code/include/smb/smb_fs_sb.h @@ -28,6 +28,11 @@ struct smb_server data blocks */ dword max_raw_size; /* Maximum SMB_COM_WRITE_RAW and SMB_COM_READ_RAW data. */ + dword smb_write_threshold; /* If SMB header + payload size is smaller + than or equal to this threshold, send + both in a single combined send() operation + rather than separately. */ + dword smb_read_threshold; /* Same as above, but for recv() operations. */ int max_recv; /* added by CS */ word server_uid; word tid; diff --git a/source_code/main.c b/source_code/main.c index 4706a07..1ae20a9 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -261,7 +261,7 @@ static ULONG stack_usage_exit(const struct StackSwapStruct * stk); static LONG CVSPrintf(const TEXT * format_string, APTR args); static int LocalVSNPrintf(STRPTR buffer, int limit, const TEXT * formatString, APTR args); static void cleanup(void); -static BOOL setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, STRPTR username, STRPTR opt_password, BOOL opt_change_username_case, BOOL opt_change_password_case, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, BOOL opt_prefer_core_protocol, BOOL opt_session_setup_delay_unicode, BOOL opt_write_behind, const TEXT * device_name, const TEXT * volume_name, BOOL add_volume, const TEXT * translation_file); +static BOOL setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, STRPTR username, STRPTR opt_password, BOOL opt_change_username_case, BOOL opt_change_password_case, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, BOOL opt_prefer_core_protocol, BOOL opt_session_setup_delay_unicode, BOOL opt_write_behind, int opt_smb_request_write_threshold, int opt_smb_request_read_threshold, const TEXT * device_name, const TEXT * volume_name, BOOL add_volume, const TEXT * translation_file); static void file_system_handler(BOOL raise_priority, const TEXT * device_name, const TEXT * volume_name, const TEXT * service_name); /****************************************************************************/ @@ -758,6 +758,8 @@ main(void) KEY Protocol; SWITCH NetBIOSTransport; SWITCH WriteBehind; + NUMBER WriteThreshold; + NUMBER ReadThreshold; KEY SessionSetup; KEY Unicode; SWITCH CP437; @@ -798,6 +800,8 @@ main(void) "PROTOCOL/K," "NETBIOS/S," "WRITEBEHIND/S," + "WRITETHRESHOLD/N/K," + "READTHRESHOLD/N/K," "SESSIONSETUP/K," "UNICODE/K," "CP437/S," @@ -817,6 +821,8 @@ main(void) LONG tz_number, dst_number, debug_number; LONG cache_size = 0; LONG max_transmit = -1; + LONG smb_write_threshold = 0; + LONG smb_read_threshold = 0; LONG timeout = 0; TEXT env_protocol[8]; TEXT env_workgroup_name[17]; @@ -1015,6 +1021,30 @@ main(void) args.MaxNameLen = &MaxNameLen; } + str = get_icon_tool_type_value("WRITETHRESHOLD", NULL); + if(str != NULL) + { + if(StrToLong(str,&smb_write_threshold) == -1) + { + report_error("Invalid number '%s' for 'WRITETHRESHOLD' parameter.",str); + goto out; + } + + args.WriteThreshold = &smb_write_threshold; + } + + str = get_icon_tool_type_value("READTHRESHOLD", NULL); + if(str != NULL) + { + if(StrToLong(str,&smb_read_threshold) == -1) + { + report_error("Invalid number '%s' for 'READTHRESHOLD' parameter.",str); + goto out; + } + + args.ReadThreshold = &smb_read_threshold; + } + str = get_icon_tool_type_value("TZ","TIMEZONEOFFSET"); if(str != NULL) { @@ -1326,8 +1356,8 @@ main(void) { SHOWMSG("using code page 437 translation"); - memmove(map_amiga_to_smb_name,unicode_to_cp437,sizeof(unicode_to_cp437)); - memmove(map_smb_to_amiga_name,cp437_to_unicode,sizeof(cp437_to_unicode)); + memcpy(map_amiga_to_smb_name,unicode_to_cp437,sizeof(unicode_to_cp437)); + memcpy(map_smb_to_amiga_name,cp437_to_unicode,sizeof(cp437_to_unicode)); TranslateNames = TRUE; } @@ -1335,8 +1365,8 @@ main(void) { SHOWMSG("using code page 850 translation"); - memmove(map_amiga_to_smb_name,unicode_to_cp850,sizeof(unicode_to_cp850)); - memmove(map_smb_to_amiga_name,cp850_to_unicode,sizeof(cp850_to_unicode)); + memcpy(map_amiga_to_smb_name,unicode_to_cp850,sizeof(unicode_to_cp850)); + memcpy(map_smb_to_amiga_name,cp850_to_unicode,sizeof(cp850_to_unicode)); TranslateNames = TRUE; } @@ -1381,6 +1411,16 @@ main(void) } } + if(args.WriteThreshold == NULL) + args.WriteThreshold = &smb_write_threshold; + + D(("write threshold = %ld", (*args.WriteThreshold))); + + if(args.ReadThreshold == NULL) + args.ReadThreshold = &smb_read_threshold; + + D(("read threshold = %ld", (*args.ReadThreshold))); + DisableExAll = (BOOL)(args.DisableExAll != 0); CaseSensitive = (BOOL)(args.CaseSensitive != 0); OmitHidden = (BOOL)(args.OmitHidden != 0); @@ -1492,6 +1532,8 @@ main(void) Stricmp(args.Protocol,"CORE") == SAME, Stricmp(args.SessionSetup,"DELAY") == SAME, args.WriteBehind, + (*args.WriteThreshold), + (*args.ReadThreshold), args.DeviceName, args.VolumeName, get_switch_status(args.AddVolume, TRUE), @@ -2910,41 +2952,71 @@ find_file_node_by_name(const TEXT * name,const struct FileNode * skip) struct FileNode * result = NULL; struct FileNode * fn; - #ifndef USE_SPLAY_TREE + ASSERT( name != NULL ); - for(fn = (struct FileNode *)FileList.mlh_Head ; - fn->fn_MinNode.mln_Succ != NULL ; - fn = (struct FileNode *)fn->fn_MinNode.mln_Succ) + #ifndef USE_SPLAY_TREE { - if(fn != skip && compare_names(name,fn->fn_FullName) == SAME) + D(("searching for file with name '%s'", name)); + + for(fn = (struct FileNode *)FileList.mlh_Head ; + fn->fn_MinNode.mln_Succ != NULL ; + fn = (struct FileNode *)fn->fn_MinNode.mln_Succ) { - result = fn; - break; + if(fn != skip && compare_names(name,fn->fn_FullName) == SAME) + { + result = fn; + break; + } + } + + if(result != NULL) + D(("found it (= 0x%08lx)", result)); + else + D(("didn't find it")); + } + #else + { + struct splay_node * sn; + + D(("looking up file with name '%s'", name)); + + /* Find the list of all files which match the given name. */ + sn = splay_tree_find(&FileNameTree, (splay_key_t)name); + if(sn != NULL) + { + fn = (struct FileNode *)sn->sn_userdata; + + ASSERT( fn != NULL ); + + /* Use this entry, unless it's the one which we + * wanted to skip. + */ + if (fn != skip) + { + result = fn; + + D(("found it (= 0x%08lx)", result)); + } + /* Use the next entry in the list, if possible. */ + else if (sn->sn_next != NULL) + { + result = (struct FileNode *)sn->sn_next->sn_userdata; + + D(("found it, but can't use it, so using the next best entry (= 0x%08lx)", result)); + + if(result == NULL) + D(("...but didn't actually find it")); + } + else + { + D(("didn't find it")); + } + } + else + { + D(("didn't find it")); } } - - #else - - struct splay_node * sn; - - /* Find the list of all files which match the given name. */ - sn = splay_tree_find(&FileNameTree, (splay_key_t)name); - if(sn != NULL) - { - fn = (struct FileNode *)sn->sn_userdata; - - ASSERT( fn != NULL ); - - /* Use this entry, unless it's the one which we - * wanted to skip. - */ - if (fn != skip) - result = fn; - /* Use the next entry in the list, if possible. */ - else if (sn->sn_next != NULL) - result = (struct FileNode *)sn->sn_next->sn_userdata; - } - #endif /* USE_SPLAY_TREE */ return(result); @@ -2960,35 +3032,63 @@ find_lock_node_by_name(const TEXT * name,const struct LockNode * skip) struct LockNode * ln; #ifndef USE_SPLAY_TREE - - for(ln = (struct LockNode *)LockList.mlh_Head ; - ln->ln_MinNode.mln_Succ != NULL ; - ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - if(ln != skip && compare_names(name,ln->ln_FullName) == SAME) + D(("searching for lock with name '%s'", name)); + + for(ln = (struct LockNode *)LockList.mlh_Head ; + ln->ln_MinNode.mln_Succ != NULL ; + ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - result = ln; - break; + if(ln != skip && compare_names(name,ln->ln_FullName) == SAME) + { + result = ln; + break; + } + } + + if(result != NULL) + D(("found it (= 0x%08lx)", result)); + else + D(("didn't find it")); + } + #else + { + struct splay_node * sn; + + D(("looking up lock with name '%s'", name)); + + sn = splay_tree_find(&LockNameTree, (splay_key_t)name); + if(sn != NULL) + { + ln = (struct LockNode *)sn->sn_userdata; + + ASSERT( ln != NULL ); + + if (ln != skip) + { + result = ln; + + D(("found it (= 0x%08lx)", result)); + } + else if (sn->sn_next != NULL) + { + result = (struct LockNode *)sn->sn_next->sn_userdata; + + D(("found it, but can't use it, so using the next best entry (= 0x%08lx)", result)); + + if(result == NULL) + D(("...but didn't actually find it")); + } + else + { + D(("didn't find it")); + } + } + else + { + D(("didn't find it")); } } - - #else - - struct splay_node * sn; - - sn = splay_tree_find(&LockNameTree, (splay_key_t)name); - if(sn != NULL) - { - ln = (struct LockNode *)sn->sn_userdata; - - ASSERT( ln != NULL ); - - if (ln != skip) - result = ln; - else if (sn->sn_next != NULL) - result = (struct LockNode *)sn->sn_next->sn_userdata; - } - #endif /* USE_SPLAY_TREE */ return(result); @@ -3659,6 +3759,8 @@ setup( BOOL opt_prefer_core_protocol, BOOL opt_session_setup_delay_unicode, BOOL opt_write_behind, + int opt_smb_request_write_threshold, + int opt_smb_request_read_threshold, const TEXT * device_name, const TEXT * volume_name, BOOL opt_add_volume, @@ -3681,19 +3783,19 @@ setup( NewList((struct List *)&LockList); #ifdef USE_SPLAY_TREE + { + /* File names may not be unique. */ + splay_tree_init(&FileNameTree, (splay_key_compare_t)compare_names); + FileNameTree.st_allow_duplicates = TRUE; - /* File names may not be unique. */ - splay_tree_init(&FileNameTree, (splay_key_compare_t)compare_names); - FileNameTree.st_allow_duplicates = TRUE; + splay_tree_init(&FileAddressTree, compare_file_or_lock_by_address); - splay_tree_init(&FileAddressTree, compare_file_or_lock_by_address); - - /* Lock names may not be unique. */ - splay_tree_init(&LockNameTree, (splay_key_compare_t)compare_names); - LockNameTree.st_allow_duplicates = TRUE; - - splay_tree_init(&LockAddressTree, compare_file_or_lock_by_address); + /* Lock names may not be unique. */ + splay_tree_init(&LockNameTree, (splay_key_compare_t)compare_names); + LockNameTree.st_allow_duplicates = TRUE; + splay_tree_init(&LockAddressTree, compare_file_or_lock_by_address); + } #endif /* USE_SPLAY_TREE */ MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC, 4096, 4096); @@ -3898,6 +4000,8 @@ setup( CaseSensitive, opt_session_setup_delay_unicode, opt_write_behind, + opt_smb_request_write_threshold, + opt_smb_request_read_threshold, &error, &smb_error_class, &smb_error, @@ -4082,15 +4186,15 @@ add_file_node(struct FileNode * fn) AddTail((struct List *)&FileList,(struct Node *)fn); #ifdef USE_SPLAY_TREE + { + fn->fn_SplayNameNode.sn_key = (splay_key_t)fn->fn_FullName; + fn->fn_SplayNameNode.sn_userdata = fn; + splay_tree_add(&FileNameTree, &fn->fn_SplayNameNode); - fn->fn_SplayNameNode.sn_key = (splay_key_t)fn->fn_FullName; - fn->fn_SplayNameNode.sn_userdata = fn; - splay_tree_add(&FileNameTree, &fn->fn_SplayNameNode); - - fn->fn_SplayAddressNode.sn_key = (splay_key_t)fn; - fn->fn_SplayAddressNode.sn_userdata = fn; - splay_tree_add(&FileAddressTree, &fn->fn_SplayAddressNode); - + fn->fn_SplayAddressNode.sn_key = (splay_key_t)fn; + fn->fn_SplayAddressNode.sn_userdata = fn; + splay_tree_add(&FileAddressTree, &fn->fn_SplayAddressNode); + } #endif /* USE_SPLAY_TREE */ } @@ -4104,10 +4208,17 @@ remove_file_node(struct FileNode * fn) Remove((struct Node *)fn); #ifdef USE_SPLAY_TREE + { + APTR found; - splay_tree_remove(&FileNameTree, &fn->fn_SplayNameNode, (splay_key_t)fn->fn_FullName); - splay_tree_remove(&FileAddressTree, NULL, (splay_key_t)fn); + found = splay_tree_remove(&FileNameTree, &fn->fn_SplayNameNode, (splay_key_t)fn->fn_FullName); + D(("file name node removal %s", found != NULL ? "succeeded" : "failed")); + + found = splay_tree_remove(&FileAddressTree, NULL, (splay_key_t)fn); + + D(("file address node removal %s", found != NULL ? "succeeded" : "failed")); + } #endif /* USE_SPLAY_TREE */ } @@ -4121,15 +4232,15 @@ add_lock_node(struct LockNode * ln) AddTail((struct List *)&LockList,(struct Node *)ln); #ifdef USE_SPLAY_TREE + { + ln->ln_SplayNameNode.sn_key = (splay_key_t)ln->ln_FullName; + ln->ln_SplayNameNode.sn_userdata = ln; + splay_tree_add(&LockNameTree, &ln->ln_SplayNameNode); - ln->ln_SplayNameNode.sn_key = (splay_key_t)ln->ln_FullName; - ln->ln_SplayNameNode.sn_userdata = ln; - splay_tree_add(&LockNameTree, &ln->ln_SplayNameNode); - - ln->ln_SplayAddressNode.sn_key = (splay_key_t)ln; - ln->ln_SplayAddressNode.sn_userdata = ln; - splay_tree_add(&LockAddressTree, &ln->ln_SplayAddressNode); - + ln->ln_SplayAddressNode.sn_key = (splay_key_t)ln; + ln->ln_SplayAddressNode.sn_userdata = ln; + splay_tree_add(&LockAddressTree, &ln->ln_SplayAddressNode); + } #endif /* USE_SPLAY_TREE */ } @@ -4143,10 +4254,17 @@ remove_lock_node(struct LockNode * ln) Remove((struct Node *)ln); #ifdef USE_SPLAY_TREE + { + APTR found; - splay_tree_remove(&LockNameTree, &ln->ln_SplayNameNode, ln->ln_SplayNameNode.sn_key); - splay_tree_remove(&LockAddressTree, NULL, (splay_key_t)ln); + found = splay_tree_remove(&LockNameTree, &ln->ln_SplayNameNode, ln->ln_SplayNameNode.sn_key); + D(("lock name node removal %s", found != NULL ? "succeeded" : "failed")); + + found = splay_tree_remove(&LockAddressTree, NULL, (splay_key_t)ln); + + D(("lock address node removal %s", found != NULL ? "succeeded" : "failed")); + } #endif /* USE_SPLAY_TREE */ /* This will make the lock_is_invalid() tests return @@ -5151,41 +5269,18 @@ restart_directory_scanning(const struct MsgPort * user,const TEXT * parent_dir_n SHOWSTRING(parent_dir_name); #ifndef USE_SPLAY_TREE - - for(ln = (struct LockNode *)LockList.mlh_Head ; - ln->ln_MinNode.mln_Succ != NULL ; - ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - /* Try not to self-disrupt directory scanning while - * deleting the contents of the directory. - */ - if(ln->ln_LastUser == user) - continue; - - if(compare_names(parent_dir_name,ln->ln_FullName) == SAME) + for(ln = (struct LockNode *)LockList.mlh_Head ; + ln->ln_MinNode.mln_Succ != NULL ; + ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - D(("restart scanning for '%s'", escape_name(ln->ln_FullName))); + /* Try not to self-disrupt directory scanning while + * deleting the contents of the directory. + */ + if(ln->ln_LastUser == user) + continue; - ln->ln_RestartExamine = TRUE; - } - } - - #else - - /* Find all the locks which share the same directory name. */ - sn = splay_tree_find(&LockNameTree, (splay_key_t)parent_dir_name); - if(sn != NULL) - { - /* Check each lock in turn, restarting the directory - * scanning process unless the same program which - * requires the restart is the one currently - * doing the scanning. - */ - for((void)NULL ; sn != NULL ; sn = sn->sn_next) - { - ln = sn->sn_userdata; - - if(ln->ln_LastUser != user) + if(compare_names(parent_dir_name,ln->ln_FullName) == SAME) { D(("restart scanning for '%s'", escape_name(ln->ln_FullName))); @@ -5193,7 +5288,30 @@ restart_directory_scanning(const struct MsgPort * user,const TEXT * parent_dir_n } } } + #else + { + /* Find all the locks which share the same directory name. */ + sn = splay_tree_find(&LockNameTree, (splay_key_t)parent_dir_name); + if(sn != NULL) + { + /* Check each lock in turn, restarting the directory + * scanning process unless the same program which + * requires the restart is the one currently + * doing the scanning. + */ + for((void)NULL ; sn != NULL ; sn = sn->sn_next) + { + ln = sn->sn_userdata; + if(ln->ln_LastUser != user) + { + D(("restart scanning for '%s'", escape_name(ln->ln_FullName))); + + ln->ln_RestartExamine = TRUE; + } + } + } + } #endif /* USE_SPLAY_TREE */ LEAVE(); @@ -6087,24 +6205,34 @@ Action_FreeLock( D(("lock on '%s'", escape_name(key->ln_FullName))); #ifndef USE_SPLAY_TREE - - for(ln = (struct LockNode *)LockList.mlh_Head ; - ln->ln_MinNode.mln_Succ != NULL ; - ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - if(ln == key) + for(ln = (struct LockNode *)LockList.mlh_Head ; + ln->ln_MinNode.mln_Succ != NULL ; + ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) { - found = ln; - break; + if(ln == key) + { + found = ln; + break; + } } } - #else + { + D(("looking up the lock address (what happened to trust?)")); - sn = splay_tree_find(&LockAddressTree, (splay_key_t)key); - if(sn != NULL) - found = (struct LockNode *)sn->sn_userdata; + sn = splay_tree_find(&LockAddressTree, (splay_key_t)key); + if(sn != NULL) + { + D(("found it")); + found = (struct LockNode *)sn->sn_userdata; + } + else + { + D(("didn't find it (this should never happen)")); + } + } #endif /* USE_SPLAY_TREE */ /* This should never happen. */ @@ -8340,24 +8468,34 @@ Action_End( found = NULL; #ifndef USE_SPLAY_TREE - - for(fn = (struct FileNode *)FileList.mlh_Head ; - fn->fn_MinNode.mln_Succ != NULL ; - fn = (struct FileNode *)fn->fn_MinNode.mln_Succ) { - if(fn == which_fn) + for(fn = (struct FileNode *)FileList.mlh_Head ; + fn->fn_MinNode.mln_Succ != NULL ; + fn = (struct FileNode *)fn->fn_MinNode.mln_Succ) { - found = fn; - break; + if(fn == which_fn) + { + found = fn; + break; + } } } - #else + { + D(("looking up the file address (what happened to trust?)")); - sn = splay_tree_find(&FileAddressTree, (splay_key_t)which_fn); - if(sn != NULL) - found = (struct FileNode *)sn->sn_userdata; + sn = splay_tree_find(&FileAddressTree, (splay_key_t)which_fn); + if(sn != NULL) + { + D(("found it")); + found = (struct FileNode *)sn->sn_userdata; + } + else + { + D(("didn't find it (this should never happen)")); + } + } #endif /* USE_SPLAY_TREE */ if(found == NULL) diff --git a/source_code/proc.c b/source_code/proc.c index dcc54a5..115eb69 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -483,16 +483,18 @@ smb_encode_smb_length (byte * p, int len) /* 0x00 = NetBIOS session message */ p[0] = 0; - /* 0 = reserved */ - p[1] = 0; + /* Length is a 17 bit integer, the most significant + * bit of which goes into bit #0. The other 7 bits + * are reserved. + */ + p[1] = (len >> 16) & 1; - /* Payload length in network byte order. */ + /* Payload length in network byte order + * (least significant 16 bits). + */ p[2] = (len & 0xFF00) >> 8; p[3] = (len & 0xFF); - /* Length is actually a 17 bit integer. */ - p[1] |= (len >> 16) & 1; - return &p[4]; } @@ -1593,7 +1595,13 @@ smb_proc_close (struct smb_server *server, word fileid, dword wtime, int * error * the file-id to be valid again after a reconnection. */ int -smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data, int * error_ptr) +smb_proc_read ( + struct smb_server *server, + struct smb_dirent *finfo, + off_t offset, + long count, + char *data, + int * error_ptr) { char *buf = server->transmit_buffer; int result; @@ -1643,7 +1651,13 @@ smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset * call. */ int -smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, char *data, int * error_ptr) +smb_proc_read_raw ( + struct smb_server *server, + struct smb_dirent *finfo, + const QUAD * const offset_quad, + long count, + char *data, + int * error_ptr) { char *buf = server->transmit_buffer; int result; @@ -1678,7 +1692,13 @@ smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, const QU } int -smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data, int * error_ptr) +smb_proc_write ( + struct smb_server *server, + struct smb_dirent *finfo, + off_t offset, + long count, + const char *data, + int * error_ptr) { int result; char *buf = server->transmit_buffer; @@ -1717,7 +1737,13 @@ smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offse } int -smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, const char *data, int * error_ptr) +smb_proc_write_raw ( + struct smb_server *server, + struct smb_dirent *finfo, + const QUAD * const offset_quad, + long count, + const char *data, + int * error_ptr) { char *buf = server->transmit_buffer; int num_bytes_written = 0; @@ -1893,7 +1919,13 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, const Q } int -smb_proc_writex (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, const char *data, int * error_ptr) +smb_proc_writex ( + struct smb_server *server, + struct smb_dirent *finfo, + const QUAD * const offset_quad, + long count, + const char *data, + int * error_ptr) { char *buf = server->transmit_buffer; int result; @@ -1961,7 +1993,13 @@ smb_proc_writex (struct smb_server *server, struct smb_dirent *finfo, const QUAD } int -smb_proc_readx (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, char *data, int * error_ptr) +smb_proc_readx ( + struct smb_server *server, + struct smb_dirent *finfo, + const QUAD * const offset_quad, + long count, + char *data, + int * error_ptr) { char *buf = server->transmit_buffer; int result; @@ -2021,7 +2059,14 @@ smb_proc_readx (struct smb_server *server, struct smb_dirent *finfo, const QUAD /* smb_proc_lockingX: We don't chain any further packets to the initial one */ int -smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, const struct smb_lkrng *locks, int num_entries, int mode, long timeout, int * error_ptr) +smb_proc_lockingX ( + struct smb_server *server, + struct smb_dirent *finfo, + const struct smb_lkrng *locks, + int num_entries, + int mode, + long timeout, + int * error_ptr) { int result; int num_locks, num_unlocks; @@ -2073,7 +2118,7 @@ smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, const st return result; } -/* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */ +/* smb_proc_do_create: We expect entry->attry and entry->ctime to be set. */ int smb_proc_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry, int * error_ptr) { @@ -2153,7 +2198,13 @@ smb_proc_create (struct smb_server *server, const char *path, int len, struct sm } int -smb_proc_mv (struct smb_server *server, const char *old_path, const int old_path_len, const char *new_path, const int new_path_len, int * error_ptr) +smb_proc_mv ( + struct smb_server *server, + const char *old_path, + const int old_path_len, + const char *new_path, + const int new_path_len, + int * error_ptr) { char *p; char *buf = server->transmit_buffer; @@ -2373,12 +2424,10 @@ smb_decode_dirent (const char *p, struct smb_dirent *entry) entry->size_low = DVAL (p, 5); entry->size_high = 0; - /* The name is given in 8.3 MS-DOS style format, - * including the "." delimiter. This is a NUL- - * terminated OEM string, with one byte per - * character. If the name is shorter than 12 - * characters, it is padded with " " (space) - * characters. + /* The name is given in 8.3 MS-DOS style format, including the "." + * delimiter. This is a NUL-terminated OEM string, with one byte per + * character. If the name is shorter than 12 characters, it is + * padded with " " (space) characters. */ name_len = 12; @@ -2423,7 +2472,13 @@ smb_decode_dirent (const char *p, struct smb_dirent *entry) * Note that it is for short directory name seeks, i.e.: protocol < PROTOCOL_LANMAN2 */ static int -smb_proc_readdir_short (struct smb_server *server, const char *path, int fpos, int cache_size, struct smb_dirent *entry, int * error_ptr) +smb_proc_readdir_short ( + struct smb_server *server, + const char *path, + int fpos, + int cache_size, + struct smb_dirent *entry, + int * error_ptr) { char *p; char *buf; @@ -2712,7 +2767,12 @@ smb_get_dirent_name(char *p,int level,char ** name_ptr,int * len_ptr) /* interpret a long filename structure */ static int -smb_decode_long_dirent (const struct smb_server *server, const char *p, struct smb_dirent *finfo, int level, int * entry_length_ptr) +smb_decode_long_dirent ( + const struct smb_server *server, + const char *p, + struct smb_dirent *finfo, + int level, + int * entry_length_ptr) { int success = TRUE; @@ -2948,7 +3008,13 @@ smb_decode_long_dirent (const struct smb_server *server, const char *p, struct s } static int -smb_proc_readdir_long (struct smb_server *server, const char *path, int fpos, int cache_size, struct smb_dirent *entry, int * error_ptr) +smb_proc_readdir_long ( + struct smb_server *server, + const char *path, + int fpos, + int cache_size, + struct smb_dirent *entry, + int * error_ptr) { int max_matches = 512; /* this should actually be based on the max_recv value */ @@ -3317,7 +3383,13 @@ smb_proc_readdir_long (struct smb_server *server, const char *path, int fpos, in } int -smb_proc_readdir (struct smb_server *server, const char *path, int fpos, int cache_size, struct smb_dirent *entry, int * error_ptr) +smb_proc_readdir ( + struct smb_server *server, + const char *path, + int fpos, + int cache_size, + struct smb_dirent *entry, + int * error_ptr) { int result; @@ -3410,7 +3482,13 @@ smb_proc_getattr_core (struct smb_server *server, const char *path, int len, str } int -smb_query_path_information(struct smb_server *server, const char *path, int len, int fid, struct smb_dirent *entry, int * error_ptr) +smb_query_path_information( + struct smb_server *server, + const char *path, + int len, + int fid, + struct smb_dirent *entry, + int * error_ptr) { unsigned char *outbuf = server->transmit_buffer; dword ext_file_attributes; diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index ba98585..b0279f4 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -95,6 +95,8 @@ smba_connect ( int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, + int opt_smb_request_write_threshold, + int opt_smb_request_read_threshold, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, @@ -152,6 +154,22 @@ smba_connect ( LOG(("delay use of unicode during session setup = %s\n",opt_session_setup_delay_unicode ? "yes" : "no")); + /* Do not send SMB header and payload for write operations separately, + * but in a single chunk if their combined size is smaller than + * or equal to this threshold value. + */ + res->server.smb_write_threshold = opt_smb_request_write_threshold; + + LOG(("SMB write request threshold size = %ld bytes\n", res->server.smb_write_threshold)); + + /* Do not receive SMB header and payload for read operations separately, + * but in a single chunk if their combined size is smaller than + * or equal to this threshold value. + */ + res->server.smb_read_threshold = opt_smb_request_read_threshold; + + LOG(("SMB read request threshold size = %ld bytes\n", res->server.smb_read_threshold)); + /* Enable asynchronous SMB_COM_WRITE_RAW operations? */ res->server.write_behind = opt_write_behind; @@ -198,6 +216,8 @@ smba_connect ( if(servent != NULL) { data.addr.sin_port = servent->s_port; + + LOG(("using port number %ld\n",ntohs(data.addr.sin_port))); } else { @@ -214,6 +234,8 @@ smba_connect ( if(0 < n && n < 65536) { data.addr.sin_port = htons (n); + + LOG(("using port number %ld\n",n)); } else { @@ -234,19 +256,31 @@ smba_connect ( } else if (res->server.raw_smb) { + int port; + servent = getservbyname("microsoft-ds","tcp"); if(servent != NULL) - data.addr.sin_port = servent->s_port; + port = servent->s_port; else - data.addr.sin_port = htons (445); + port = htons (445); + + LOG(("using port number %ld\n",ntohs(port))); + + data.addr.sin_port = port; } else { + int port; + servent = getservbyname("netbios-ssn","tcp"); if(servent != NULL) - data.addr.sin_port = servent->s_port; + port = servent->s_port; else - data.addr.sin_port = htons (139); + port = htons (139); + + LOG(("using port number %ld\n",ntohs(port))); + + data.addr.sin_port = port; } data.fd = socket (AF_INET, SOCK_STREAM, 0); @@ -592,7 +626,7 @@ write_attr (smba_file_t * f, int * error_ptr) f->dirent.mtime = mtime; f->dirent.attr = attr; - /* If the attributes need to be updated, we cannot used smb_proc_setattrE(), + /* If the attributes need to be updated, we cannot use smb_proc_setattrE(), * because that only updates the "time of last write access", but not the * attributes. */ @@ -1376,7 +1410,8 @@ smba_readdir (smba_file_t * f, int offs, void *callback_data, smba_callback_t ca f->dircache->len = 0; f->dircache->base = cache_index; - num_entries = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, f->dircache->cache, error_ptr); + num_entries = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, + f->dircache->cache, error_ptr); /* We stop on error, or if the directory is empty. */ if (num_entries <= 0) @@ -1475,12 +1510,12 @@ allocate_path_name(const smba_file_t * dir, const char *name, size_t * path_name if(path != NULL) { memcpy (path, dir->dirent.complete_path, dir_len); - path[dir_len] = DOS_PATHSEP; + path[dir_len++] = DOS_PATHSEP; memcpy(&path[dir_len], name, len+1); /* length includes terminating NUL character */ ASSERT( path_name_len_ptr != NULL ); - (*path_name_len_ptr) = dir_len + 1 + len; + (*path_name_len_ptr) = dir_len + len; } return(path); @@ -1846,10 +1881,28 @@ extract_service ( char * share_start; char * root_start; char * complete_service; - char * service_copy; + char * service_copy = NULL; char * service_name; int result = -1; + if (strlen (service) < 4) + { + report_error("Service name '%s' is too short.",service); + + (*error_ptr) = EINVAL; + + goto out; + } + + if (service[0] != '/') + { + report_error("Service name '%s' must begin with '/'.",service); + + (*error_ptr) = EINVAL; + + goto out; + } + service_copy = malloc(strlen(service)+1); if(service_copy == NULL) { @@ -1861,28 +1914,11 @@ extract_service ( } strcpy (service_copy, service); + complete_service = service_copy; - if (strlen (complete_service) < 4) - { - report_error("Service name '%s' is too short.",complete_service); - - (*error_ptr) = EINVAL; - - goto out; - } - - if (complete_service[0] != '/') - { - report_error("Service name '%s' must begin with '/'.",complete_service); - - (*error_ptr) = EINVAL; - - goto out; - } - while (complete_service[0] == '/') - complete_service += 1; + complete_service++; share_start = strchr (complete_service, '/'); if (share_start == NULL) @@ -1920,20 +1956,29 @@ extract_service ( len--; service_name[len] = '\0'; + + if(len > tcp_service_name_size) + { + report_error("TCP service name/port number is too long in '%s' (%ld characters are possible).",service_name,tcp_service_name_size); + + (*error_ptr) = EINVAL; + + goto out; + } } - if (strlen (complete_service) > 63) + if (strlen (complete_service) > server_size) { - report_error("Server name is too long in '%s' (%ld characters are possible).",service,63); + report_error("Server name is too long in '%s' (%ld characters are possible).",service,server_size); (*error_ptr) = ENAMETOOLONG; goto out; } - if (strlen (share_start) > 255) + if (strlen (share_start) > share_size) { - report_error("Share name is too long in '%s' (%ld characters are possible).",service,255); + report_error("Share name is too long in '%s' (%ld characters are possible).",service,share_size); (*error_ptr) = ENAMETOOLONG; @@ -1971,6 +2016,8 @@ smba_start( int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, + int opt_smb_request_write_threshold, + int opt_smb_request_read_threshold, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, @@ -2133,7 +2180,7 @@ smba_start( /* Make sure the hostname is 16 characters or less (for NetBIOS) */ if (!opt_raw_smb && strlen (host_name) > 16) { - report_error("Server name '%s' is too long (max %ld characters).", host_name, 16); + report_error("Server name '%s' is too long (%ld characters are possible).", host_name, 16); (*error_ptr) = ENAMETOOLONG; goto out; @@ -2222,6 +2269,8 @@ smba_start( opt_case_sensitive, opt_session_setup_delay_unicode, opt_write_behind, + opt_smb_request_write_threshold, + opt_smb_request_read_threshold, error_ptr, smb_error_class_ptr, smb_error_ptr, diff --git a/source_code/smb_abstraction.h b/source_code/smb_abstraction.h index c523fb8..c8cf7f7 100644 --- a/source_code/smb_abstraction.h +++ b/source_code/smb_abstraction.h @@ -162,7 +162,7 @@ int smba_rmdir(smba_server_t *s, const char *path, int *error_ptr); int smba_rename(smba_server_t *s, const char *from, const char *to, int *error_ptr); int smba_statfs(smba_server_t *s, long *bsize, long *blocks, long *bfree, int *error_ptr); void smb_invalidate_all_inodes(struct smb_server *server); -int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int opt_prefer_core_protocol, int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, int *error_ptr, int *smb_error_class_ptr, int *smb_error_ptr, smba_connect_parameters_t *smba_connect_par, smba_server_t **smba_server_ptr); +int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int opt_prefer_core_protocol, int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, int opt_smb_request_write_threshold, int opt_smb_request_read_threshold, int *error_ptr, int *smb_error_class_ptr, int *smb_error_ptr, smba_connect_parameters_t *smba_connect_par, smba_server_t **smba_server_ptr); int smba_get_dircache_size(struct smba_server *server); int smba_change_dircache_size(struct smba_server *server, int cache_size); diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 33a12f6..7e94b91 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 2 -#define REVISION 5 -#define DATE "16.12.2018" -#define VERS "smbfs 2.5" -#define VSTRING "smbfs 2.5 (16.12.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 2.5 (16.12.2018)" +#define REVISION 8 +#define DATE "19.12.2018" +#define VERS "smbfs 2.8" +#define VSTRING "smbfs 2.8 (19.12.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 2.8 (19.12.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 7ed6ff8..45a4fb7 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -5 +8 diff --git a/source_code/sock.c b/source_code/sock.c index 2003918..f710aad 100644 --- a/source_code/sock.c +++ b/source_code/sock.c @@ -203,6 +203,7 @@ smb_receive_raw ( int * error_ptr) { unsigned char netbios_session_buf[256]; + unsigned char * netbios_session_data; int netbios_session_payload_size; int len, result; @@ -211,10 +212,27 @@ smb_receive_raw ( server->rcls = 0; server->err = 0; + /* If the NetBIOS header needs to be returned, receive it along + * with the SMB message and whatever follows. + */ + if (want_header) + { + LOG(("NetBIOS header will be returned as part of the buffer\n")); + + netbios_session_data = target; + } + /* Otherwise store the NetBIOS header in a separate buffer. */ + else + { + LOG(("NetBIOS header will be processed separately\n")); + + netbios_session_data = netbios_session_buf; + } + re_recv: /* Read the NetBIOS session header (rfc-1002, section 4.3.1) */ - result = receive_all (sock_fd, netbios_session_buf, NETBIOS_HEADER_SIZE, error_ptr); + result = receive_all (sock_fd, netbios_session_data, NETBIOS_HEADER_SIZE, error_ptr); if (result < 0) { LOG (("recv error = %ld\n", (*error_ptr))); @@ -231,12 +249,12 @@ smb_receive_raw ( goto out; } - netbios_session_payload_size = (int)smb_len(netbios_session_buf); + netbios_session_payload_size = (int)smb_len(netbios_session_data); SHOWVALUE(netbios_session_payload_size); #if defined(DUMP_SMB) { - if(command != 0 && netbios_session_buf[0] != 0x00 && netbios_session_payload_size > 0) + if(command != 0 && netbios_session_data[0] != 0x00 && netbios_session_payload_size > 0) { /* We only want to show what's in the first few * bytes of a session packet. Since we only support @@ -248,7 +266,7 @@ smb_receive_raw ( if(netbios_session_payload_size > 256 - NETBIOS_HEADER_SIZE) netbios_session_payload_size = 256 - NETBIOS_HEADER_SIZE; - result = receive_all (sock_fd, &netbios_session_buf[NETBIOS_HEADER_SIZE], netbios_session_payload_size - NETBIOS_HEADER_SIZE, error_ptr); + result = receive_all (sock_fd, &netbios_session_data[NETBIOS_HEADER_SIZE], netbios_session_payload_size - NETBIOS_HEADER_SIZE, error_ptr); if (result < 0) { LOG (("recv error = %ld\n", (*error_ptr))); @@ -265,17 +283,17 @@ smb_receive_raw ( goto out; } - dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,&netbios_session_buf[NETBIOS_HEADER_SIZE],netbios_session_payload_size); + dump_netbios_header(__FILE__,__LINE__,netbios_session_data,&netbios_session_data[NETBIOS_HEADER_SIZE],netbios_session_payload_size); } else { - dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,NULL,0); + dump_netbios_header(__FILE__,__LINE__,netbios_session_data,NULL,0); } } #endif /* defined(DUMP_SMB) */ /* Check the session type. */ - switch (netbios_session_buf[0]) + switch (netbios_session_data[0]) { /* 0x00 == session message */ case 0x00: @@ -300,7 +318,7 @@ smb_receive_raw ( */ if(command != 0) { - LOG (("Invalid session header type 0x%02lx\n", netbios_session_buf[0])); + LOG (("Invalid session header type 0x%02lx\n", netbios_session_data[0])); (*error_ptr) = error_invalid_netbios_session; @@ -323,12 +341,11 @@ smb_receive_raw ( goto out; } - /* Prepend the NetBIOS header to what is read? */ + /* Did we read the NetBIOS header already? Make sure that + * the data to follow goes into the right receive buffer. + */ if (want_header) - { - memcpy (target, netbios_session_buf, NETBIOS_HEADER_SIZE); target += NETBIOS_HEADER_SIZE; - } /* This is an optimization for the SMB_COM_READ and SMB_COM_READ_ANDX * commands, which tries to avoid copying the received data twice. To @@ -337,129 +354,248 @@ smb_receive_raw ( * begins. Then we read the data, storing it directly in the * receive buffer rather than in the packet buffer, from which * it would otherwise have to be retrieved later. + * + * Note that this optimization may still not take effect because the + * amount of data expected to be received can be so small that it + * may make little sense to break up reception into two separate + * recv() calls. */ if(input_payload != NULL) { - int num_bytes_received = 0; - - LOG(("input_payload=0x%08lx, payload_size=%ld\n", input_payload, input_payload_size)); - - if(command == SMBreadX) + /* Receive SMB message header and payload separately? */ + if(len > server->smb_read_threshold) { - int data_length; - int data_offset; + int num_bytes_received = 0; - /* We need to read the following data: - * - * 0: 32 bytes of SMB message header - * 32: 1 byte of word count - * 33: 1 byte of andxcommand - * 34: 1 byte of andxreserved - * 35: 2 bytes of andxoffset - * 37: 2 bytes of available - * 39: 2 bytes of datacompactionmode - * 41: 2 bytes of reserved - * 43: 2 bytes of datalength - * 45: 2 bytes of dataoffset - * 47: 10 bytes of reserved - * 57: 2 bytes of bytecount - * - * This adds up to 59 bytes. - */ + LOG(("receiving SMB message and payload separately\n")); - LOG(("SMBreadX: reading the first %ld bytes\n", 59)); + LOG(("input_payload=0x%08lx, payload_size=%ld\n", input_payload, input_payload_size)); - result = receive_all (sock_fd, target, 59, error_ptr); - if (result < 0) + if(command == SMBreadX) { - LOG (("recv error = %ld\n", (*error_ptr))); - goto out; - } + int data_length; + int data_offset; - num_bytes_received += result; + /* We need to read the following data: + * + * 0: 32 bytes of SMB message header + * 32: 1 byte of word count + * 33: 1 byte of andxcommand + * 34: 1 byte of andxreserved + * 35: 2 bytes of andxoffset + * 37: 2 bytes of available + * 39: 2 bytes of datacompactionmode + * 41: 2 bytes of reserved + * 43: 2 bytes of datalength + * 45: 2 bytes of dataoffset + * 47: 10 bytes of reserved + * 57: 2 bytes of bytecount + * + * This adds up to 59 bytes. + */ - ASSERT( num_bytes_received == 59 ); + LOG(("SMBreadX: reading the first %ld bytes\n", 59)); - /* End of file reached? */ - if(num_bytes_received < 59) - { - /* End of file */ - LOG (("EOF\n")); - - (*error_ptr) = error_end_of_file; - - result = -1; - goto out; - } - - data_offset = WVAL(target, 45); - - SHOWVALUE(data_offset); - - /* Skip the padding bytes, if any. */ - if(data_offset > 59) - { - result = receive_all (sock_fd, target + 59, data_offset - 59, error_ptr); + result = receive_all (sock_fd, target, 59, error_ptr); if (result < 0) { LOG (("recv error = %ld\n", (*error_ptr))); goto out; } + num_bytes_received += result; + + ASSERT( num_bytes_received == 59 ); + /* End of file reached? */ - if(result < data_offset - 59) + if(num_bytes_received < 59) { /* End of file */ LOG (("EOF\n")); (*error_ptr) = error_end_of_file; - + + result = -1; + goto out; + } + + data_offset = WVAL(target, 45); + + SHOWVALUE(data_offset); + + /* Skip the padding bytes, if any. */ + if(data_offset > 59) + { + LOG (("skipping %ld padding bytes\n", data_offset - 59)); + + result = receive_all (sock_fd, target + 59, data_offset - 59, error_ptr); + if (result < 0) + { + LOG (("recv error = %ld\n", (*error_ptr))); + goto out; + } + + /* End of file reached? */ + if(result < data_offset - 59) + { + /* End of file */ + LOG (("EOF\n")); + + (*error_ptr) = error_end_of_file; + + result = -1; + goto out; + } + + num_bytes_received += result; + } + + data_length = WVAL(target, 43); + + SHOWVALUE(data_length); + + ASSERT( data_length <= input_payload_size ); + + result = receive_all (sock_fd, input_payload, data_length, error_ptr); + if (result < 0) + { + LOG (("recv error = %ld\n", (*error_ptr))); + goto out; + } + + if(result < data_length) + { + /* End of file */ + LOG (("EOF\n")); + + (*error_ptr) = error_end_of_file; + result = -1; goto out; } num_bytes_received += result; + + /* This should never happen, but then we better make sure to + * read the entire message. + */ + if(num_bytes_received < len) + { + LOG(("reading the remaining %ld bytes; this should never happen\n", len - num_bytes_received )); + + result = receive_all (sock_fd, &target[num_bytes_received], len - num_bytes_received, error_ptr); + if (result < 0) + { + LOG (("recv error = %ld\n", (*error_ptr))); + goto out; + } + + if(result < len - num_bytes_received) + { + /* End of file */ + LOG (("EOF\n")); + + (*error_ptr) = error_end_of_file; + + result = -1; + goto out; + } + } } - - data_length = WVAL(target, 43); - - SHOWVALUE(data_length); - - result = receive_all (sock_fd, input_payload, data_length, error_ptr); - if (result < 0) + else { - LOG (("recv error = %ld\n", (*error_ptr))); - goto out; - } + int count_of_bytes_returned; + int count_of_bytes_to_read; + int buffer_format; - if(result < data_length) - { - /* End of file */ - LOG (("EOF\n")); + ASSERT( command == SMBread ); - (*error_ptr) = error_end_of_file; + /* We need to read the following data: + * + * 0: 32 bytes of SMB message header + * 32: 1 byte of word count + * 33: 2 bytes of 'count of bytes returned' (1 word) + * 35: 8 bytes of reserved data (4 words) + * 43: 2 bytes of 'byte count' (1 word) + * 45: 1 byte of 'buffer format' + * 46: 2 bytes of 'count of bytes to read' (1 word). + * + * This adds up to 48 bytes. + */ - result = -1; - goto out; - } + LOG(("SMBread: reading the first %ld bytes\n", 48)); - num_bytes_received += result; - - /* This should never happen, but then we better make sure to - * read the entire message. - */ - if(num_bytes_received < len) - { - LOG(("reading the remaining %ld bytes; this should never happen\n", len - num_bytes_received )); - - result = receive_all (sock_fd, &target[num_bytes_received], len - num_bytes_received, error_ptr); + result = receive_all (sock_fd, target, 48, error_ptr); if (result < 0) { LOG (("recv error = %ld\n", (*error_ptr))); goto out; } - if(result < len - num_bytes_received) + num_bytes_received += result; + + ASSERT( num_bytes_received == 48 ); + + /* End of file reached? */ + if(num_bytes_received < 48) + { + /* End of file */ + LOG (("EOF\n")); + + (*error_ptr) = error_end_of_file; + + result = -1; + goto out; + } + + /* So we read the header. Now we need to figure out if the + * data is in the expected format, and how many bytes are + * waiting to be read. + */ + + /* The buffer format must be 1. */ + buffer_format = BVAL(target, 45); + + LOG(("buffer format = %ld, should be %ld\n", buffer_format, 1)); + + if(buffer_format != 1) + { + LOG(("buffer format %ld not supported\n", buffer_format)); + + (*error_ptr) = error_invalid_buffer_format; + + result = -1; + goto out; + } + + count_of_bytes_returned = WVAL(target, 33); + count_of_bytes_to_read = WVAL(target, 46); + + /* That should never be more data than the read buffer may hold. */ + ASSERT( count_of_bytes_to_read <= input_payload_size ); + ASSERT( count_of_bytes_to_read <= count_of_bytes_returned ); + ASSERT( count_of_bytes_returned <= input_payload_size ); + + LOG(("count of bytes to read = %ld, should be <= %ld\n", count_of_bytes_to_read, input_payload_size)); + + if(count_of_bytes_returned > input_payload_size) + { + LOG(("this is too much data\n")); + + (*error_ptr) = error_message_exceeds_buffer_size; + + result = -1; + goto out; + } + + result = receive_all (sock_fd, input_payload, count_of_bytes_to_read, error_ptr); + if (result < 0) + { + LOG (("recv error = %ld\n", (*error_ptr))); + goto out; + } + + if(result < count_of_bytes_to_read) { /* End of file */ LOG (("EOF\n")); @@ -469,100 +605,78 @@ smb_receive_raw ( result = -1; goto out; } + + num_bytes_received += result; + + ASSERT( count_of_bytes_to_read == count_of_bytes_returned ); + + if(count_of_bytes_to_read < count_of_bytes_returned) + { + LOG(("fewer data available than should be delivered; setting the remainder (%ld bytes) to 0.\n", count_of_bytes_returned - count_of_bytes_to_read)); + + memset(&input_payload[count_of_bytes_to_read],0,count_of_bytes_returned - count_of_bytes_to_read); + } + + /* This should never happen, but then we better make sure to + * read the entire message. + */ + if(num_bytes_received < len) + { + LOG(("reading the remaining %ld bytes; this should never happen\n", len - num_bytes_received )); + + result = receive_all (sock_fd, &target[num_bytes_received], len - num_bytes_received, error_ptr); + if (result < 0) + { + LOG (("recv error = %ld\n", (*error_ptr))); + goto out; + } + + if(result < len - num_bytes_received) + { + /* End of file */ + LOG (("EOF\n")); + + (*error_ptr) = error_end_of_file; + + result = -1; + goto out; + } + } + + #if defined(DUMP_SMB) + { + /* If want_header==0 then this is the data returned by SMB_COM_READ_RAW. */ + dump_smb(__FILE__,__LINE__,!want_header,target,48,smb_packet_to_consumer,server->max_recv); + + if(buffer_format == 1) + dump_smb(__FILE__,__LINE__,!want_header,input_payload,num_bytes_received - 48,smb_packet_to_consumer,server->max_recv); + + if(num_bytes_received < len && result > 0) + dump_smb(__FILE__,__LINE__,!want_header,&target[num_bytes_received],result,smb_packet_to_consumer,server->max_recv); + } + #endif /* defined(DUMP_SMB) */ } + + result = num_bytes_received; } + /* No, read both as a single chunk through recv() and pick + * the SMB message header and its payload apart later. This + * is intended to improve small read operation performance + * for which two separate recv() operations may introduce + * additional delays in processing. + */ else { - int count_of_bytes_returned; - int count_of_bytes_to_read; - int buffer_format; + LOG(("receiving SMB message and payload in one chunk\n")); - ASSERT( command == SMBread ); - - /* We need to read the following data: - * - * 0: 32 bytes of SMB message header - * 32: 1 byte of word count - * 33: 2 bytes of 'count of bytes returned' (1 word) - * 35: 8 bytes of reserved data (4 words) - * 43: 2 bytes of 'byte count' (1 word) - * 45: 1 byte of 'buffer format' - * 46: 2 bytes of 'count of bytes to read' (1 word). - * - * This adds up to 48 bytes. - */ - - LOG(("SMBread: reading the first %ld bytes\n", 48)); - - result = receive_all (sock_fd, target, 48, error_ptr); + result = receive_all (sock_fd, target, len, error_ptr); if (result < 0) { LOG (("recv error = %ld\n", (*error_ptr))); goto out; } - num_bytes_received += result; - - ASSERT( num_bytes_received == 48 ); - - /* End of file reached? */ - if(num_bytes_received < 48) - { - /* End of file */ - LOG (("EOF\n")); - - (*error_ptr) = error_end_of_file; - - result = -1; - goto out; - } - - /* So we read the header. Now we need to figure out if the - * data is in the expected format, and how many bytes are - * waiting to be read. - */ - - /* The buffer format must be 1. */ - buffer_format = BVAL(target, 45); - - LOG(("buffer format = %ld, should be %ld\n", buffer_format, 1)); - - if(buffer_format != 1) - { - LOG(("buffer format %ld not supported\n", buffer_format)); - - (*error_ptr) = error_invalid_buffer_format; - - result = -1; - goto out; - } - - count_of_bytes_returned = WVAL(target, 33); - count_of_bytes_to_read = WVAL(target, 46); - - /* That should never be more data than the read buffer may hold. */ - ASSERT( count_of_bytes_to_read <= input_payload_size ); - ASSERT( count_of_bytes_to_read <= count_of_bytes_returned ); - ASSERT( count_of_bytes_returned <= input_payload_size ); - - LOG(("count of bytes to read = %ld, should be <= %ld\n", count_of_bytes_to_read, input_payload_size)); - - if(count_of_bytes_returned > input_payload_size) - { - (*error_ptr) = error_message_exceeds_buffer_size; - - result = -1; - goto out; - } - - result = receive_all (sock_fd, input_payload, count_of_bytes_to_read, error_ptr); - if (result < 0) - { - LOG (("recv error = %ld\n", (*error_ptr))); - goto out; - } - - if(result < count_of_bytes_to_read) + if(result < len) { /* End of file */ LOG (("EOF\n")); @@ -573,58 +687,85 @@ smb_receive_raw ( goto out; } - num_bytes_received += result; - - ASSERT( count_of_bytes_to_read == count_of_bytes_returned ); - - if(count_of_bytes_to_read < count_of_bytes_returned) - { - LOG(("fewer data available than should be delivered; setting the remainder (%ld bytes) to 0.\n", count_of_bytes_returned - count_of_bytes_to_read)); - - memset(&input_payload[count_of_bytes_to_read],0,count_of_bytes_returned - count_of_bytes_to_read); - } - - /* This should never happen, but then we better make sure to - * read the entire message. - */ - if(num_bytes_received < len) - { - LOG(("reading the remaining %ld bytes; this should never happen\n", len - num_bytes_received )); - - result = receive_all (sock_fd, &target[num_bytes_received], len - num_bytes_received, error_ptr); - if (result < 0) - { - LOG (("recv error = %ld\n", (*error_ptr))); - goto out; - } - - if(result < len - num_bytes_received) - { - /* End of file */ - LOG (("EOF\n")); - - (*error_ptr) = error_end_of_file; - - result = -1; - goto out; - } - } - #if defined(DUMP_SMB) { /* If want_header==0 then this is the data returned by SMB_COM_READ_RAW. */ - dump_smb(__FILE__,__LINE__,!want_header,target,48,smb_packet_to_consumer,server->max_recv); - - if(buffer_format == 1) - dump_smb(__FILE__,__LINE__,!want_header,input_payload,num_bytes_received - 48,smb_packet_to_consumer,server->max_recv); - - if(num_bytes_received < len && result > 0) - dump_smb(__FILE__,__LINE__,!want_header,&target[num_bytes_received],result,smb_packet_to_consumer,server->max_recv); + dump_smb(__FILE__,__LINE__,!want_header,target,result,smb_packet_to_consumer,server->max_recv); } #endif /* defined(DUMP_SMB) */ - } - result = num_bytes_received; + if(command == SMBreadX) + { + int data_length; + int data_offset; + + data_offset = WVAL(target, 45); + SHOWVALUE(data_offset); + + data_length = WVAL(target, 43); + SHOWVALUE(data_length); + + ASSERT( data_offset < len ); + ASSERT( data_offset + data_length <= len ); + ASSERT( data_length <= input_payload_size ); + + memcpy(input_payload, &target[data_offset], data_length); + } + else + { + int count_of_bytes_returned; + int count_of_bytes_to_read; + int buffer_format; + + ASSERT( command == SMBread ); + + /* The buffer format must be 1. */ + buffer_format = BVAL(target, 45); + + LOG(("buffer format = %ld, should be %ld\n", buffer_format, 1)); + + if(buffer_format != 1) + { + LOG(("buffer format %ld not supported\n", buffer_format)); + + (*error_ptr) = error_invalid_buffer_format; + + result = -1; + goto out; + } + + count_of_bytes_returned = WVAL(target, 33); + count_of_bytes_to_read = WVAL(target, 46); + + /* That should never be more data than the read buffer may hold. */ + ASSERT( count_of_bytes_to_read <= input_payload_size ); + ASSERT( count_of_bytes_to_read <= count_of_bytes_returned ); + ASSERT( count_of_bytes_returned <= input_payload_size ); + + LOG(("count of bytes to read = %ld, should be <= %ld\n", count_of_bytes_to_read, input_payload_size)); + + if(count_of_bytes_returned > input_payload_size) + { + LOG(("this is too much data\n")); + + (*error_ptr) = error_message_exceeds_buffer_size; + + result = -1; + goto out; + } + + memcpy(input_payload, &target[48], count_of_bytes_to_read); + + ASSERT( count_of_bytes_to_read == count_of_bytes_returned ); + + if(count_of_bytes_to_read < count_of_bytes_returned) + { + LOG(("fewer data available than should be delivered; setting the remainder (%ld bytes) to 0.\n", count_of_bytes_returned - count_of_bytes_to_read)); + + memset(&input_payload[count_of_bytes_to_read],0,count_of_bytes_returned - count_of_bytes_to_read); + } + } + } } else { @@ -660,7 +801,13 @@ smb_receive_raw ( } static int -smb_receive (struct smb_server *server, int command, int sock_fd, void * input_payload, int payload_size, int * error_ptr) +smb_receive ( + struct smb_server *server, + int command, + int sock_fd, + void * input_payload, + int payload_size, + int * error_ptr) { byte * packet = server->transmit_buffer; int result; @@ -953,7 +1100,7 @@ smb_connect (struct smb_server *server, int * error_ptr) server->mount_data.fd = result; } - LOG(("connecting to server %s with socket %ld\n", Inet_NtoA(server->mount_data.addr.sin_addr.s_addr), server->mount_data.fd)); + LOG(("connecting to server %s:%ld with socket %ld\n", Inet_NtoA(server->mount_data.addr.sin_addr.s_addr), ntohs(server->mount_data.addr.sin_port), server->mount_data.fd)); /* Wait a certain time period for the connection attempt to succeed? */ if(server->timeout > 0) @@ -1162,7 +1309,13 @@ smb_check_server_connection(struct smb_server *server, int error) * case of error. */ int -smb_request (struct smb_server *server, int command, void * input_payload, const void * output_payload, int payload_size, int * error_ptr) +smb_request ( + struct smb_server *server, + int command, + void * input_payload, + const void * output_payload, + int payload_size, + int * error_ptr) { unsigned char *buffer = server->transmit_buffer; int sock_fd = server->mount_data.fd; @@ -1203,7 +1356,29 @@ smb_request (struct smb_server *server, int command, void * input_payload, const ASSERT( payload_size < smb_len(buffer) ); ASSERT( len > payload_size ); - len -= payload_size; + /* Send SMB message header and payload separately? */ + if(len > server->smb_write_threshold) + { + LOG(("sending SMB message and payload separately\n")); + + len -= payload_size; + } + /* No, combine both into a single chunk which will be + * transmitted with a single send(). This is intended + * to improve small write operation performance for + * which two separate send() operations may not succeed + * in nudging the TCP/IP stack to transmit the data just + * yet (Nagle algorithm, etc.). + */ + else + { + LOG(("sending SMB message and payload in one chunk\n")); + + memcpy(&buffer[len - payload_size], output_payload, payload_size); + + output_payload = NULL; + payload_size = 0; + } } LOG (("len = %ld, cmd = 0x%lx, input_payload=0x%08lx, output_payload=0x%08lx, payload_size=%ld\n", len, buffer[8], input_payload, output_payload, payload_size)); @@ -1252,7 +1427,14 @@ smb_request (struct smb_server *server, int command, void * input_payload, const * one packet to send. */ int -smb_trans2_request (struct smb_server *server, int command, int *data_len, int *param_len, char **data, char **param, int * error_ptr) +smb_trans2_request ( + struct smb_server *server, + int command, + int *data_len, + int *param_len, + char **data, + char **param, + int * error_ptr) { unsigned char *buffer = server->transmit_buffer; int sock_fd = server->mount_data.fd; diff --git a/source_code/system_headers.h b/source_code/system_headers.h index 93806c0..97f7603 100644 --- a/source_code/system_headers.h +++ b/source_code/system_headers.h @@ -42,9 +42,9 @@ /*****************************************************************************/ -/* The network header files (e.g. AmiTCP, Miami) define this type, - * which clashes with how AmigaOS uses it. This moves it out of the - * way. +/* The header file declares this, and it may be redefined + * in the TCP/IP stack header files. We try to avoid trouble by moving + * the type declaration out of the way... */ #define byte IGNORE_THIS