Hi,

I have the following problem,
I would like to send a binary file over smtp, the orginal filesize is 16 K,
it arrive however only 12K, and the file is incomplete.
With normal text file does not give it problems.

Where is the error?

sniffer


invoke CreateFileMapping, hFile,NULL,PAGE_READONLY,0,0,NULL
mov hMapFile,eax
invoke MapViewOfFile,eax, FILE_MAP_READ,0,0,0
mov pMapStart,eax

push ecx
mov ecx,dword ptr
push ecx
mov eax,ml_len
add Fsize, eax
add Fsize,5


invoke GlobalAlloc, GHND, Fsize
mov hMem,eax

invoke GlobalLock, hMem
mov pBody,eax

mov ecx,ml_len

lea esi,
mov edi,pBody
@@:
lodsb
stosb
dec ecx
jnz @B

pop ecx
mov esi,pMapStart
startcpy:
lodsb
stosb
dec ecx
jnz startcpy
pop ecx

mov word ptr ,0a0dh
mov word ptr ,'.'
mov word ptr ,0a0dh

invoke printf, addr pBody
invoke printf, addr BigBuf
invoke UnmapViewOfFile, pMapStart
invoke CloseHandle, hFile
Posted on 2004-02-03 08:17:00 by sniffer
First a couple of generally 'bad' things: use HeapAlloc instead of GlobalAlloc, and generally avoid file mappings unless they makes your life a lot easier, as file mapping is slower than ReadFile. In your case, there seems to be no reason whatsoever to use filemapping - just ReadFile directly to edi after your first copyloop. This will be faster and use less system resources... not that big an improvement, but this is assembly and you should do proper code, right? ;) besides, the source will be shorter and easier to follow.

Your code is pretty ugly and uncommented, and a whole bunch of things are lacking; where does 'BigBuf' come from? Is 'printf' a normal libc printf, or your own function? (In that case, remember that printf stops at a 0 byte, which makes it rather unsuitable for binary data). Are you using some API functions, or are you handling the SMTP protocol yourself? (Remember that not everybody accepts 8-bit mail, so you'll have to use an encoding scheme for binary data), et cetera. Your lodsb/stosb would be much better handled with a rep movsb, or one of the faster equivalents.

Your crlf.crlf message termination could & should be handled with a dword and a byte store...

Apart from that, it's been a while since I've read up on RFCs... but isn't there something about a max (or recommended) line-width? And encoding of special chars? Then again, perhaps 8bit clean servers and clients are widespread now, and some code that you haven't included nor mentioned is enabled 8bit message sending...
Posted on 2004-02-03 09:18:38 by f0dder
Hi F0dder,

the Code is from: http://www.asmcommunity.net/board/index.php?topic=3759&highlight=farrier

I begin with assembler, and cannot it not judge whether the code well, or is bad. Sorry!

invoke printf should with contents show, what is sent.

I try the function ReadFile, many thanks for your help.

sniffer
Posted on 2004-02-03 09:50:35 by sniffer
Hi sniffer, sorry if I was a bit harsh on you :)
printf will work okay for showing normal text messages, but since you're sending a binary file, it's not a very good function - as already mentioned, it will stop at the first 0. Of course it probably does not make too much sense outputting binary data to the console in the first place :)

You'll probably want to talk with farrier, or perhaps bazik - he was working on an email client a while ago.
Posted on 2004-02-03 10:14:19 by f0dder
SMTP does not support binary transfers, it only supports 7 bit charactersets at most, that's why base64 encoding should be used, it encodes the binary 8 bit data in a way that it can certainly be handled by any SMTP server (it converts everything to standard ASCII-characters).
Posted on 2004-02-03 10:47:53 by Henk-Jan
Henk-Jan,

Actually, the specification states that only 7-bits are allowed, but from my experience any modern mail system will allow 8-bit transmisssions. I've been using the basic guts of the m32mail program since I wrote the article almost 2 years ago. Sending a binary report file by email every night from 17 stores to the home office. No problems so far. You are required to specify "application/octet-stream" as the attachment type.

sniffer,

I have to admit that I don't recognize what you are doing in your program--no comments at all--and can't help you. Where in your program are you actually sending your e-mail? I try to help if I can.

Hope the mailer program can help you!

farrier
Posted on 2004-02-03 11:09:31 by farrier
sniffer,

Just a thought:

How are you calculating the size of the DATA segment you are sending? The size must be the total of the data header info after the DATA message, plus the file size, plus the final separator and final 13, 10, ".", 13, 10

One mistake I made--twice--when first working on this program, was calculating the size by scanning the binary file for an ending 0. Of course this was wrong, as within the binary file there were many 0's as part of the data.

I just thought it might be a problem with calculating the size of the DATA.

hth

farrier
Posted on 2004-02-04 07:09:34 by farrier
Hi Farrier,

the file size is different.
It passes of 2.6 Mb file size or with a 16K File size.

my problem is: I can not recognize whether those is not file completely in the memory is loaded and then copies.
I assume, which is file is not completely loaded.

The end of the binary File 13,10, ".",13,10 is correct.

sniffer
Posted on 2004-02-04 07:49:21 by sniffer
Actually, the specification states that only 7-bits are allowed, but from my experience any modern mail system will allow 8-bit transmisssions.


That's my point, 8-bit is out-of-spec, therefore it may or may not work. You should not rely on it.
Posted on 2004-02-04 08:08:45 by Henk-Jan
Henk-Jan,

That's my point, 8-bit is out-of-spec, therefore it may or may not work. You should not rely on it.


I should have expressed myself more clearly! I researched this topic fairly extensively, and the 7-bit specification was in place when most serial communication formats were for 1 start bit, 7 data bits, 1 parity bit and 1 stop bit. That's the only reason to use 7 bits only: if you or your ISP uses only 7 data bits. That doesn't happen anymore!

It has never failed over a wide range of computers, ISP's and even AOL!

sniffer,

I'll look at your code some time today and try to help. In my program, the only thing that changes is the size of the file to attach; how are you calculating the size of the DATA segment of the e-mail?

farrier
Posted on 2004-02-04 12:42:38 by farrier

It has never failed over a wide range of computers, ISP's and even AOL!

Too bad when it fails. Btw, will the smtp server "re-encode" the attachments in, say, base64 or uuencode, or will it just pass the attachment along, as binary data? If the latter is the case, you won't only have to worry about SMTP servers, but mail clients as well.
Posted on 2004-02-04 12:55:05 by f0dder
I use Outlook.

when I send the file over outlook is this not problem, but with smtp_asend.exe

outlook and smtp_asend.exe use the same way, on the protocol layer.

this is not a problem with 7bit or 8bit on smtp protocol.

use packview, ethernal or a other sniffer, and you see, that both programs send the data.

smtp_asend it send fewer data does only why?


sniffer
Posted on 2004-02-04 14:03:12 by sniffer
f0dder,

If you have ever received an attachment which was an exe file, chances are it was in binary mode and not encoded in any way. Apparently, this was not allowed in early specification of SMTP and even now some mail clients will encode the exe with base64 before sending, that is what I have read, I haven't experienced that myself. The only big draw back to sending non-encoded, is that your only option is to "Save As" to a file, and not have an application perform some action on the file. Unless you have Outlook/Outlook Express, they might just execute the file for your conveinience!:eek:

farrier
Posted on 2004-02-04 14:10:45 by farrier
sniffer,

One thing that seems to be missing is the final separator after the binary data. In my source you will see:



body4 db "--M32_mime_sep_230", 13, 10, \
"Content-Type: application/octet-stream;", 13, 10, \
" Name=firsttry.bin", 13, 10, \
"Content-Disposition: attachment;", 13, 10, \
" FileName=firsttry.bin", 13, 10, 13, 10, \
"MASM32 Rules!", \ ;File contents go here
13, 10, \
"--M32_mime_sep_230--", 13, 10, ".", 13, 10, 0

The binary data goes where the text "MASM32 Rules!" appears, followed by the 13, 10 and the final separator "--M32_mime_sep_230--"

You will have to include the final separator size in the total DATA size

This may be where the problem lies!

hth

farrier
Posted on 2004-02-04 15:34:43 by farrier
no, this is not the problem.

with you body4 is file size 2K and the file.bin 86byte.

many thanks for your help.

sniffer
Posted on 2004-02-04 15:47:23 by sniffer
sniffer,

I don't think you understand me, or I don't understand you, or both!:confused:

At line 410 you should be adding a CR, LF and the final serarator "--M32_mime_sep_230--" onto pbody, after copying the the contents of your file from pMapStart. In your program you don't do that!

And at line 433 you are using Fsize as the size of the DATA component of the email, but the size should be everything sent after the cmd2 is sent on line 428 and including the length of the last CR, LF, and the final separator. In your program you don't do that!

Also in the DATA header, mine looks like:



body4 db "--M32_mime_sep_230", 13, 10, \
"Content-Type: application/octet-stream;", 13, 10, \
" Name=firsttry.bin", 13, 10, \
"Content-Disposition: attachment;", 13, 10, \
" FileName=firsttry.bin", 13, 10, 13, 10, \


Yours looks like:

body4	db	"--M32_mime_sep_230", 13, 10, \

"Content-Type: application/octet-stream;", 13, 10, \
" Name=firsttry.bin", 13, 10, \
"Content-Transfer-Encoding: base64", 13, 10, \
" FileName=firsttry.bin", 13, 10


Yours in no longer a pure attachment!

hth

farrier
Posted on 2004-02-04 20:19:39 by farrier
Hi Farrier,

I tried that out this morning, it functioned also not with that new body.
Which is missing, is the end of the file.
If I take a file with 2.6Mb, I get only 43 K.

the e.mail header is okay.

Header
(crlf.crlf) (send)
File send
(crlf.crlf) (send)
quit...

I think, the complete file is loaded, but the copies from memory to socket, is not okay.

hmm... if I could nevertheless only program. :o)
thanks a lot.

sniffer
Posted on 2004-02-05 00:19:01 by sniffer
sniffer, you don't use any strlen/strcpy kinda thing on the binary data to get it's length or copy, do you?

Also, do you just do a single send() and count on it being able to ship 2.6 megs at once? You have to handle errors gracefully, I think even blocking sockets might not send all your data at once (and async sockets definitely won't) - www.madwizard.org.
Posted on 2004-02-05 05:25:12 by f0dder
I agree with f0dder:alright:

Try sending 8K, 16K, or 32K at a time and wait for acknowledgement before continuing! Even if you have a broadband connection. Also, update your posted sourcecode so we can see what you're doing now. I'm not sure if you implemented my suggestions. You weren't calculating the length of the DATA segment correctly:

Total length = ml_len + Fsize + sizeof( CRLF + final separator + CRLF + '.' + CRLF )

(untested algorithm)

farrier
Posted on 2004-02-05 08:19:12 by farrier
even sends of 8k could theoretically fail - check what winsock calls return to you, and handle the situation accordingly. But even when doing this, I would still recommended using a not too big buffer for send - you wouldn't really want risking winsock thinking "okay, I'll try sending it all at once" and locking 2.8 megs of kernel memory - since that's a sparse resource.
Posted on 2004-02-05 08:22:43 by f0dder