Subversion Repositories Kolibri OS

Rev

Rev 4052 | Rev 4366 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
9
;;                                                                 ;;
10
;;    Based on the code of 4.4BSD                                  ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
17
$Revision: 3289 $
18
 
19
;-----------------------------------------------------------------
20
;
21
; TCP_output
22
;
23
; IN:  eax = socket pointer
24
;
25
; OUT: /
26
;
27
;-----------------------------------------------------------------
28
align 4
4347 hidnplayr 29
proc TCP_output
3545 hidnplayr 30
 
4347 hidnplayr 31
locals
32
        temp_bits       db ?
33
endl
34
 
3556 hidnplayr 35
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: socket=%x\n", eax
3545 hidnplayr 36
 
37
        push    eax
38
        lea     ecx, [eax + SOCKET.mutex]
39
        call    mutex_lock
40
        pop     eax
41
 
3652 hidnplayr 42
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: socket locked\n"
43
 
3545 hidnplayr 44
; We'll detect the length of the data to be transmitted, and flags to be used
45
; If there is some data, or any critical controls to send (SYN / RST), then transmit
46
; Otherwise, investigate further
47
 
48
        mov     ebx, [eax + TCP_SOCKET.SND_MAX]
49
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
50
        jbe     .not_idle
51
 
52
        mov     ebx, [eax + TCP_SOCKET.t_idle]
53
        cmp     ebx, [eax + TCP_SOCKET.t_rxtcur]
54
        jbe     .not_idle
55
 
56
; We have been idle for a while and no ACKS are expected to clock out any data we send..
57
; Slow start to get ack "clock" running again.
58
 
59
        mov     ebx, [eax + TCP_SOCKET.t_maxseg]
60
        mov     [eax + TCP_SOCKET.SND_CWND], ebx
61
 
62
  .not_idle:
63
  .again:
4347 hidnplayr 64
        mov     [temp_bits], 0
3545 hidnplayr 65
 
66
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]         ; calculate offset (71)
67
        sub     ebx, [eax + TCP_SOCKET.SND_UNA]         ;
68
 
69
        mov     ecx, [eax + TCP_SOCKET.SND_WND]         ; determine window
70
        cmp     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
71
        jb      @f                                      ;
72
        mov     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
73
       @@:                                              ;
74
 
75
        call    TCP_outflags                            ; flags in dl
76
 
77
;------------------------
78
; data being forced out ?
79
 
80
; If in persist timeout with window of 0, send 1 byte.
81
; Otherwise, if window is small but nonzero, and timer expired,
82
; we will send what we can and go to transmit state
83
 
84
        cmp     [eax + TCP_SOCKET.t_force], 0
85
        je      .no_force
86
 
3556 hidnplayr 87
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: forcing data out\n"
3545 hidnplayr 88
 
89
        test    ecx, ecx
90
        jnz     .no_zero_window
91
 
92
        cmp     ebx, [eax + STREAM_SOCKET.snd.size]
93
        jae     @f
94
 
95
        and     dl, not (TH_FIN)
96
 
97
       @@:
98
        inc     ecx
99
        jmp     .no_force
100
 
101
  .no_zero_window:
3603 hidnplayr 102
        and     [eax + TCP_SOCKET.timer_flags], not timer_flag_persist
3545 hidnplayr 103
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
104
 
105
  .no_force:
106
 
107
;--------------------------------
108
; Calculate how much data to send (106)
109
 
110
        mov     esi, [eax + STREAM_SOCKET.snd.size]
111
        cmp     esi, ecx
112
        jb      @f
113
        mov     esi, ecx
114
       @@:
115
        sub     esi, ebx
116
 
117
 
118
;------------------------
119
; check for window shrink (107)
120
 
121
; If FIN has been set, but not ACKed, but we havent been called to retransmit, esi will be -1
122
; Otherwise, window shrank after we sent into it.
123
 
124
        jae     .not_persist
125
 
126
; enter persist state
127
        xor     esi, esi
128
 
129
; If window shrank to 0
130
        test    ecx, ecx
131
        jnz     @f
132
 
133
; cancel pending retransmit
3603 hidnplayr 134
        and     [eax + TCP_SOCKET.timer_flags], not timer_flag_retransmission
3545 hidnplayr 135
 
136
; pull SND_NXT back to (closed) window, We will enter persist state below.
137
        push    [eax + TCP_SOCKET.SND_UNA]
138
        pop     [eax + TCP_SOCKET.SND_NXT]
139
       @@:
140
 
141
; If window didn't close completely, just wait for an ACK
142
 
143
  .not_persist:
144
 
145
;---------------------------
146
; Send one segment at a time (124)
147
 
148
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
149
        jbe     @f
150
 
151
        mov     esi, [eax + TCP_SOCKET.t_maxseg]
4347 hidnplayr 152
        or      [temp_bits], TCP_BIT_SENDALOT
3545 hidnplayr 153
       @@:
154
 
155
;--------------------------------------------
156
; Turn of FIN flag if send buffer not emptied (128)
157
 
158
        mov     edi, [eax + TCP_SOCKET.SND_NXT]
159
        add     edi, esi
160
        sub     edi, [eax + TCP_SOCKET.SND_UNA]
161
        cmp     edi, [eax + STREAM_SOCKET.snd.size]
162
        jae     @f
163
        and     dl, not (TH_FIN)
164
 
165
       @@:
166
 
167
;-------------------------------
168
; calculate window advertisement (130)
169
 
170
        mov     ecx, SOCKET_MAXDATA
171
        sub     ecx, [eax + STREAM_SOCKET.rcv.size]
172
 
173
;------------------------------
174
; Sender silly window avoidance (131)
175
 
176
        test    esi, esi
177
        jz      .len_zero
178
 
179
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
180
        je      TCP_send
181
 
182
        add     ebx, esi                                ; offset + length
183
        cmp     ebx, [eax + STREAM_SOCKET.snd.size]
184
        jb      @f
185
 
186
        test    [eax + TCP_SOCKET.t_flags], TF_NODELAY
187
        jnz     TCP_send
188
 
189
        mov     ebx, [eax + TCP_SOCKET.SND_MAX]
190
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
191
        je      TCP_send
192
       @@:
193
 
194
        test    [eax + TCP_SOCKET.t_force], -1  ;;;
195
        jnz     TCP_send
196
 
197
        mov     ebx, [eax + TCP_SOCKET.max_sndwnd]
198
        shr     ebx, 1
199
        cmp     esi, ebx
200
        jae     TCP_send
201
 
202
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]
203
        cmp     ebx, [eax + TCP_SOCKET.SND_MAX]
204
        jb      TCP_send
205
 
206
  .len_zero:
207
 
208
;----------------------------------------
209
; Check if a window update should be sent (154)
210
 
3556 hidnplayr 211
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: window=%d\n", ecx
3545 hidnplayr 212
 
213
; Compare available window to amount of window known to peer (as advertised window less next expected input)
214
; If the difference is at least two max size segments, or at least 50% of the maximum possible window,
215
; Then we want to send a window update to the peer.
216
 
217
        test    ecx, ecx
218
        jz      .no_window
219
 
220
        push    ecx
221
        mov     cl, [eax + TCP_SOCKET.RCV_SCALE]
222
        mov     ebx, TCP_max_win
223
        shl     ebx, cl
224
        pop     ecx
3652 hidnplayr 225
 
3545 hidnplayr 226
        cmp     ebx, ecx
227
        jb      @f
228
        mov     ebx, ecx
229
       @@:
230
        sub     ebx, [eax + TCP_SOCKET.RCV_ADV]
231
        add     ebx, [eax + TCP_SOCKET.RCV_NXT]
232
 
233
        mov     edi, [eax + TCP_SOCKET.t_maxseg]
234
        shl     edi, 1
235
 
236
;        cmp     ebx, edi
237
;        jae     TCP_send
238
 
239
;        cmp     ebx, [eax + TCP_SOCKET.]    ;;; TODO: check with receive buffer high water mark
240
;        jae     TCP_send
241
 
242
  .no_window:
243
 
244
;--------------------------
245
; Should a segment be sent? (174)
246
 
3556 hidnplayr 247
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: 174\n"
3545 hidnplayr 248
 
249
        test    [eax + TCP_SOCKET.t_flags], TF_ACKNOW   ; we need to ACK
250
        jnz     TCP_send
251
 
252
        test    dl, TH_SYN + TH_RST                     ; we need to send a SYN or RST
253
        jnz     TCP_send
254
 
255
        mov     ebx, [eax + TCP_SOCKET.SND_UP]          ; when urgent pointer is beyond start of send bufer
256
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
257
        ja      TCP_send
258
 
259
        test    dl, TH_FIN
260
        jz      .enter_persist  ; no reason to send, enter persist state
261
 
262
; FIN was set, only send if not already sent, or on retransmit
263
 
264
        test    [eax + TCP_SOCKET.t_flags], TF_SENTFIN
265
        jz      TCP_send
266
 
267
        mov     ebx, [eax + TCP_SOCKET.SND_NXT]
268
        cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
269
        je      TCP_send
270
 
271
;--------------------
272
; Enter persist state (191)
273
 
274
  .enter_persist:
275
 
3600 hidnplayr 276
        cmp     [eax + STREAM_SOCKET.snd.size], 0                       ; Data ready to send?
3545 hidnplayr 277
        jne     @f
3603 hidnplayr 278
        and     [eax + TCP_SOCKET.timer_flags], not timer_flag_retransmission
3545 hidnplayr 279
        jne     @f
280
 
3603 hidnplayr 281
        test    [eax + TCP_SOCKET.timer_flags], timer_flag_persist      ; Persist timer already expired?
3600 hidnplayr 282
        jnz     @f
283
 
3556 hidnplayr 284
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: Entering persist state\n"
3545 hidnplayr 285
 
286
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
287
        call    TCP_set_persist
288
       @@:
289
 
290
;----------------------------
291
; No reason to send a segment (219)
292
 
3556 hidnplayr 293
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: No reason to send a segment\n"
3545 hidnplayr 294
 
295
        pusha
296
        lea     ecx, [eax + SOCKET.mutex]
297
        call    mutex_unlock
298
        popa
299
 
300
; Fixme: returnvalue?
301
 
302
        ret
303
 
304
 
305
 
306
 
307
 
308
 
309
 
310
 
311
 
312
;-----------------------------------------------
313
;
314
; Send a segment (222)
315
;
316
; eax = socket pointer
317
; esi = data len
318
;  dl = flags
319
;
320
;-----------------------------------------------
321
align 4
322
TCP_send:
323
 
3556 hidnplayr 324
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl
3545 hidnplayr 325
 
326
        push    eax                     ; save socket ptr
327
        push    esi                     ; and data length too
328
        mov     edi, sizeof.TCP_header  ; edi will contain headersize
329
 
330
;------------------------------------
331
; Send options with first SYN segment
332
 
333
        test    dl, TH_SYN
334
        jz      .options_done
335
 
336
        push    [eax + TCP_SOCKET.ISS]
337
        pop     [eax + TCP_SOCKET.SND_NXT]
338
 
339
        test    [eax + TCP_SOCKET.t_flags], TF_NOOPT
340
        jnz     .options_done
341
 
342
        mov     ecx, 1460                              ;;;; FIXME: use routing blablabla to determine MSS
343
        or      ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
344
        bswap   ecx
345
        push    ecx
346
        add     di, 4
347
 
3556 hidnplayr 348
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: added maxseg option\n"
3545 hidnplayr 349
 
350
        test    [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
351
        jz      .no_scale
352
 
353
        test    dl, TH_ACK
354
        jz      .scale_opt
355
 
356
        test    [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
357
        jz      .no_scale
358
 
359
  .scale_opt:
360
        mov     cl, [eax + TCP_SOCKET.request_r_scale]
361
        mov     ch, TCP_OPT_NOP
362
        pushw   cx
363
        pushw   TCP_OPT_WINDOW + 3 shl 8
364
        add     di, 4
365
 
3556 hidnplayr 366
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: added scale option\n"
3545 hidnplayr 367
 
368
  .no_scale:
369
  .no_syn:
370
 
371
;------------------------------------
372
; Make the timestamp option if needed
373
 
374
        test    [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
375
        jz      .no_timestamp
376
 
377
        test    dl, TH_RST
378
        jnz     .no_timestamp
379
 
380
        test    dl, TH_ACK
381
        jz      .timestamp
382
 
383
        test    [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
384
        jz      .no_timestamp
385
 
386
  .timestamp:
387
        pushd   0
388
        pushd   [timer_ticks]
389
        pushd   TCP_OPT_NOP + TCP_OPT_NOP shl 8 + TCP_OPT_TIMESTAMP shl 16 + 10 shl 24
390
        add     di, 12
391
 
3556 hidnplayr 392
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: added timestamp\n"
3545 hidnplayr 393
 
394
  .no_timestamp:
395
 
396
        ; 
397
 
398
  .options_done:
399
 
400
; eax = socket ptr
401
; edx = flags
402
; edi = header size
403
; esi = data len
404
 
405
;---------------------------------------------
406
; check if we dont exceed the max segment size (270)
407
 
408
        add     esi, edi                        ; total TCP segment size
409
        cmp     esi, [eax + TCP_SOCKET.t_maxseg]
410
        jbe     .no_overflow
411
 
412
        mov     esi, [eax + TCP_SOCKET.t_maxseg]
4347 hidnplayr 413
        or      [temp_bits], TCP_BIT_SENDALOT
3545 hidnplayr 414
  .no_overflow:
415
 
4347 hidnplayr 416
;----------------------------------------------------
417
; Calculate the receive window.
418
; Dont shrink window, but avoid silly window syndrome
419
 
420
        mov     ebx, SOCKET_MAXDATA
421
        sub     ebx, [eax + STREAM_SOCKET.rcv.size]
422
 
423
        cmp     ebx, SOCKET_MAXDATA/4
424
        jae     @f
425
        cmp     ebx, [eax + TCP_SOCKET.t_maxseg]
426
        jae     @f
427
        xor     ebx, ebx
428
  @@:
429
 
430
        cmp     ebx, TCP_max_win
431
        jbe     @f
432
        mov     ebx, TCP_max_win
433
  @@:
434
 
435
        mov     ecx, [eax + TCP_SOCKET.RCV_ADV]
436
        sub     ecx, [eax + TCP_SOCKET.RCV_NXT]
437
        cmp     ebx, ecx
438
        ja      @f
439
        mov     ebx, ecx
440
  @@:
441
 
442
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: window = %u\n", ebx
443
 
444
        mov     cl, [eax + TCP_SOCKET.RCV_SCALE]
445
        shr     ebx, cl
446
        xchg    bl, bh
447
 
3545 hidnplayr 448
;-----------------------------------------------------------------
449
; Start by pushing all TCP header values in reverse order on stack
450
; (essentially, creating the tcp header on the stack!)
451
 
452
        pushw   0       ;        .UrgentPointer          dw ?
453
        pushw   0       ;        .Checksum               dw ?
4347 hidnplayr 454
        pushw   bx      ;        .Window                 dw ?
3545 hidnplayr 455
        shl     edi, 2  ;        .DataOffset             db ?  only 4 left-most bits
456
        shl     dx, 8
457
        or      dx, di  ;        .Flags                  db ?
458
        pushw   dx
459
        shr     edi, 2  ;        .DataOffset             db ?
460
 
461
        push    [eax + TCP_SOCKET.RCV_NXT]      ;        .AckNumber              dd ?
462
        ntohd   [esp]
463
 
464
        push    [eax + TCP_SOCKET.SND_NXT]      ;        .SequenceNumber         dd ?
465
        ntohd   [esp]
466
 
467
        push    [eax + TCP_SOCKET.RemotePort]   ;        .DestinationPort        dw ?
468
        push    [eax + TCP_SOCKET.LocalPort]    ;        .SourcePort             dw ?
469
 
470
        push    edi                     ; header size
471
 
472
;---------------------
473
; Create the IP packet
474
 
475
        mov     ecx, esi
476
        mov     edx, [eax + IP_SOCKET.LocalIP]  ; source ip
477
        mov     eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
478
        mov     di, IP_PROTO_TCP shl 8 + 128
479
        call    IPv4_output
480
        jz      .ip_error
481
 
482
;-----------------------------------------
483
; Move TCP header from stack to TCP packet
484
 
485
        push    ecx
486
        mov     ecx, [esp + 4]
487
        lea     esi, [esp + 8]
488
        shr     ecx, 2                  ; count is in bytes, we will work with dwords
3711 clevermous 489
        rep movsd
3545 hidnplayr 490
        pop     ecx                     ; full TCP packet size
491
 
492
        pop     esi                     ; headersize
493
        add     esp, esi                ; remove it from stack
494
 
495
        push    edx                     ; packet size for send proc
496
        push    eax                     ; packet ptr for send proc
497
 
498
        mov     edx, edi                ; begin of data
499
        sub     edx, esi                ; begin of packet (edi = begin of data)
500
        push    ecx
501
        sub     ecx, esi                ; data size
502
 
503
;--------------
504
; Copy the data
505
 
506
; eax = ptr to ring struct
507
; ecx = buffer size
508
; edi = ptr to buffer
509
 
510
        mov     eax, [esp + 16]                 ; get socket ptr
511
 
512
        push    edx
513
        push    [eax + TCP_SOCKET.SND_NXT]      ; we'll need this for timing the transmission
514
        test    ecx, ecx
515
        jz      .nodata
516
        mov     edx, [eax + TCP_SOCKET.SND_NXT]
517
        add     [eax + TCP_SOCKET.SND_NXT], ecx ; update sequence number <<< CHECKME
518
        sub     edx, [eax + TCP_SOCKET.SND_UNA] ; offset
519
        add     eax, STREAM_SOCKET.snd
520
        call    SOCKET_ring_read
521
  .nodata:
522
        pop     edi
523
        pop     esi                             ; begin of data
524
        pop     ecx                             ; full packet size
525
        mov     eax, [esp + 12]                 ; socket ptr
526
 
527
;----------------------------------
528
; initialize retransmit timer (400)
529
 
530
;TODO: check t_force and persist
531
 
532
        test    [esi + TCP_header.Flags], TH_SYN + TH_FIN       ; syn and fin take a sequence number
533
        jz      @f
534
        inc     [eax + TCP_SOCKET.SND_NXT]
535
        test    [esi + TCP_header.Flags], TH_FIN
536
        jz      @f
537
        or      [eax + TCP_SOCKET.t_flags], TF_SENTFIN          ; if we sent a fin, set the sentfin flag
538
       @@:
539
 
540
        mov     edx, [eax + TCP_SOCKET.SND_NXT]
541
        cmp     edx, [eax + TCP_SOCKET.SND_MAX]                 ; is this a retransmission?
542
        jbe     @f
543
        mov     [eax + TCP_SOCKET.SND_MAX], edx                 ; [eax + TCP_SOCKET.SND_NXT] from before we updated it
544
 
545
        cmp     [eax + TCP_SOCKET.t_rtt], 0                     ; are we currently timing anything?
546
        je      @f
547
        mov     [eax + TCP_SOCKET.t_rtt], 1                     ; nope, start transmission timer
548
        mov     [eax + TCP_SOCKET.t_rtseq], edi
549
;TODO: update stats
550
       @@:
551
 
552
; set retransmission timer if not already set, and not doing an ACK or keepalive probe
3600 hidnplayr 553
        test    [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
554
        jnz     .retransmit_set
3545 hidnplayr 555
 
556
        cmp     edx, [eax + TCP_SOCKET.SND_UNA]                 ; edx is still [eax + TCP_SOCKET.SND_NXT]
557
        je      .retransmit_set
558
 
559
        mov     edx, [eax + TCP_SOCKET.t_rxtcur]
560
        mov     [eax + TCP_SOCKET.timer_retransmission], edx
3603 hidnplayr 561
        or      [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
3545 hidnplayr 562
 
3600 hidnplayr 563
        test    [eax + TCP_SOCKET.timer_flags], timer_flag_persist
564
        jz      .retransmit_set
3603 hidnplayr 565
        and     [eax + TCP_SOCKET.timer_flags], not timer_flag_persist
3545 hidnplayr 566
        mov     [eax + TCP_SOCKET.t_rxtshift], 0
567
 
568
  .retransmit_set:
569
 
570
;--------------------
571
; Create the checksum
572
 
573
        TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
574
        mov     [esi + TCP_header.Checksum], dx
575
 
576
;----------------
577
; Send the packet
578
 
3556 hidnplayr 579
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: Sending with device %x\n", ebx
3545 hidnplayr 580
        call    [ebx + NET_DEVICE.transmit]
581
        jnz     .send_error
582
 
583
;---------------
584
; Ok, data sent!
585
 
586
        pop     ecx
587
        pop     eax
588
 
3644 hidnplayr 589
        call    NET_ptr_to_num4
590
        inc     [TCP_segments_tx + edi]
3545 hidnplayr 591
 
592
; update advertised receive window
593
        test    ecx, ecx
594
        jz      @f
595
        add     ecx, [eax + TCP_SOCKET.RCV_NXT]
596
        cmp     ecx, [eax + TCP_SOCKET.RCV_ADV]
597
        jbe     @f
598
        mov     [eax + TCP_SOCKET.RCV_ADV], ecx
599
       @@:
600
 
601
; update last ack sent
602
        push    [eax + TCP_SOCKET.RCV_NXT]
603
        pop     [eax + TCP_SOCKET.last_ack_sent]
604
 
4347 hidnplayr 605
; clear the ACK flags
3545 hidnplayr 606
        and     [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK)
607
 
608
;--------------
609
; unlock socket
610
 
3652 hidnplayr 611
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: unlocking socket 0x%x\n", eax
612
 
3545 hidnplayr 613
        push    eax
614
        lea     ecx, [eax + SOCKET.mutex]
615
        call    mutex_unlock
616
        pop     eax
617
 
618
;-----------------------------
619
; Check if we need more output
620
 
4347 hidnplayr 621
        test    [temp_bits], TCP_BIT_SENDALOT
3545 hidnplayr 622
        jnz     TCP_output.again
623
 
3556 hidnplayr 624
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: success!\n"
3545 hidnplayr 625
 
626
        xor     eax, eax
627
        ret
628
 
629
 
630
  .ip_error:
631
        pop     ecx
632
        add     esp, ecx
633
        add     esp, 4
634
        pop     eax
635
 
636
        mov     [eax + TCP_SOCKET.timer_retransmission], TCP_time_re_min
3602 hidnplayr 637
        or      [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
3545 hidnplayr 638
 
639
        lea     ecx, [eax + SOCKET.mutex]
640
        call    mutex_unlock
641
 
3602 hidnplayr 642
        DEBUGF  DEBUG_NETWORK_ERROR, "TCP_send: IP error\n"
3545 hidnplayr 643
 
644
        or      eax, -1
645
        ret
646
 
647
 
648
  .send_error:
3652 hidnplayr 649
        add     esp, 4
650
        pop     eax
3545 hidnplayr 651
 
652
        lea     ecx, [eax + SOCKET.mutex]
653
        call    mutex_unlock
654
 
3602 hidnplayr 655
        DEBUGF  DEBUG_NETWORK_ERROR, "TCP_send: sending failed\n"
3545 hidnplayr 656
 
657
        or      eax, -2
658
        ret
659
 
660
 
4347 hidnplayr 661
endp