~ubuntu-branches/debian/wheezy/couchdb/wheezy

« back to all changes in this revision

Viewing changes to src/couch_inets/tftp_binary.erl

  • Committer: Bazaar Package Importer
  • Author(s): Noah Slater
  • Date: 2008-02-06 17:03:38 UTC
  • Revision ID: james.westby@ubuntu.com-20080206170338-y411anylx3oplqid
Tags: upstream-0.7.3~svn684
ImportĀ upstreamĀ versionĀ 0.7.3~svn684

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%%%-------------------------------------------------------------------
 
2
%%% File    : tft_binary.erl
 
3
%%% Author  : Hakan Mattsson <hakan@erix.ericsson.se>
 
4
%%% Description : 
 
5
%%%
 
6
%%% Created : 24 May 2004 by Hakan Mattsson <hakan@erix.ericsson.se>
 
7
%%%-------------------------------------------------------------------
 
8
 
 
9
-module(tftp_binary).
 
10
 
 
11
%%%-------------------------------------------------------------------
 
12
%%% Interface
 
13
%%%-------------------------------------------------------------------
 
14
 
 
15
-behaviour(tftp).
 
16
 
 
17
-export([prepare/6, open/6, read/1, write/2, abort/3]).
 
18
-export([prepare/5, open/5]).
 
19
 
 
20
-record(read_state,  {options, blksize, bin,  is_network_ascii, count}).
 
21
-record(write_state, {options, blksize, list, is_network_ascii}).
 
22
 
 
23
%%-------------------------------------------------------------------
 
24
%% Prepare
 
25
%%-------------------------------------------------------------------
 
26
 
 
27
prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) ->
 
28
    %% Kept for backwards compatibility 
 
29
    prepare(Access, Filename, Mode, SuggestedOptions, Initial).
 
30
 
 
31
prepare(Access, Bin, Mode, SuggestedOptions, []) ->
 
32
    %% Client side
 
33
    case catch handle_options(Access, Bin, Mode, SuggestedOptions) of
 
34
        {ok, IsNetworkAscii, AcceptedOptions} when Access =:= read, binary(Bin) ->
 
35
            State = #read_state{options          = AcceptedOptions,
 
36
                                blksize          = lookup_blksize(AcceptedOptions),
 
37
                                bin              = Bin,
 
38
                                is_network_ascii = IsNetworkAscii,
 
39
                                count            = size(Bin)},
 
40
            {ok, AcceptedOptions, State};
 
41
        {ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Bin =:= binary ->
 
42
            State = #write_state{options          = AcceptedOptions,
 
43
                                 blksize          = lookup_blksize(AcceptedOptions),
 
44
                                 list             = [],
 
45
                                 is_network_ascii = IsNetworkAscii},
 
46
            {ok, AcceptedOptions, State};
 
47
        {error, {Code, Text}} ->
 
48
            {error, {Code, Text}}
 
49
    end;
 
50
prepare(_Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
 
51
    {error, {undef, "Illegal callback options."}}.
 
52
 
 
53
%%-------------------------------------------------------------------
 
54
%% Open
 
55
%%-------------------------------------------------------------------
 
56
 
 
57
open(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) ->
 
58
    %% Kept for backwards compatibility 
 
59
    open(Access, Filename, Mode, SuggestedOptions, Initial).
 
60
 
 
61
open(Access, Bin, Mode, SuggestedOptions, []) ->
 
62
    %% Server side
 
63
    case prepare(Access, Bin, Mode, SuggestedOptions, []) of
 
64
        {ok, AcceptedOptions, State} ->
 
65
            open(Access, Bin, Mode, AcceptedOptions, State);
 
66
        {error, {Code, Text}} ->
 
67
            {error, {Code, Text}}
 
68
    end;
 
69
open(Access, Bin, Mode, NegotiatedOptions, State) ->
 
70
    %% Both sides
 
71
    IsNetworkAscii =
 
72
        if
 
73
            is_record(State, write_state) -> State#write_state.is_network_ascii;
 
74
            is_record(State, read_state)  -> State#read_state.is_network_ascii
 
75
        end,
 
76
    case catch handle_options(Access, Bin, Mode, NegotiatedOptions) of
 
77
        {ok, IsNetworkAscii2, Options}
 
78
        when Options =:= NegotiatedOptions,
 
79
             IsNetworkAscii =:= IsNetworkAscii2 ->
 
80
            {ok, NegotiatedOptions, State};
 
81
        {error, {Code, Text}} ->
 
82
            {error, {Code, Text}}
 
83
    end.
 
84
 
 
85
%%-------------------------------------------------------------------
 
86
%% Read
 
87
%%-------------------------------------------------------------------
 
88
 
 
89
read(#read_state{bin = Bin} = State) when is_binary(Bin) ->
 
90
    BlkSize = State#read_state.blksize,
 
91
    if
 
92
        size(Bin) >= BlkSize ->
 
93
            <<Block:BlkSize/binary, Bin2/binary>> = Bin,
 
94
            State2 = State#read_state{bin = Bin2},
 
95
            {more, Block, State2};
 
96
        size(Bin) < BlkSize ->
 
97
            {last, Bin, State#read_state.count}
 
98
    end.
 
99
 
 
100
%%-------------------------------------------------------------------
 
101
%% Write
 
102
%%-------------------------------------------------------------------
 
103
 
 
104
write(Bin, #write_state{list = List} = State) when is_binary(Bin), is_list(List) ->
 
105
    Size = size(Bin),
 
106
    BlkSize = State#write_state.blksize,
 
107
    if
 
108
        Size =:= BlkSize ->
 
109
            {more, State#write_state{list = [Bin | List]}};
 
110
        Size < BlkSize ->
 
111
            Bin2 = list_to_binary(lists:reverse([Bin | List])),
 
112
            {last, Bin2}
 
113
    end.
 
114
 
 
115
%%-------------------------------------------------------------------
 
116
%% Abort
 
117
%%-------------------------------------------------------------------
 
118
 
 
119
abort(_Code, _Text, #read_state{bin = Bin} = State) 
 
120
  when record(State, read_state), binary(Bin) ->
 
121
    ok;
 
122
abort(_Code, _Text, #write_state{list = List} = State)
 
123
  when record(State, write_state), list(List) ->
 
124
    ok.
 
125
 
 
126
%%-------------------------------------------------------------------
 
127
%% Process options
 
128
%%-------------------------------------------------------------------
 
129
 
 
130
handle_options(Access, Bin, Mode, Options) ->
 
131
    IsNetworkAscii = handle_mode(Mode),
 
132
    Options2 = do_handle_options(Access, Bin, Options),
 
133
    {ok, IsNetworkAscii, Options2}.
 
134
 
 
135
handle_mode(Mode) ->
 
136
    case Mode of
 
137
        %% "netascii" -> true;
 
138
        "octet"    -> false;
 
139
        _          -> throw({error, {badop, "Illegal mode " ++ Mode}})
 
140
    end.
 
141
 
 
142
do_handle_options(Access, Bin, [{Key, Val} | T]) ->
 
143
    case Key of
 
144
        "tsize" ->
 
145
            case Access of
 
146
                read when Val =:= "0", binary(Bin) ->
 
147
                    Tsize = integer_to_list(size(Bin)),
 
148
                    [{Key, Tsize} | do_handle_options(Access, Bin, T)];
 
149
                _ ->
 
150
                    handle_integer(Access, Bin, Key, Val, T, 0, infinity)
 
151
            end;
 
152
        "blksize" ->
 
153
            handle_integer(Access, Bin, Key, Val, T, 8, 65464);
 
154
        "timeout" ->
 
155
            handle_integer(Access, Bin, Key, Val, T, 1, 255);
 
156
        _ ->
 
157
            do_handle_options(Access, Bin, T)
 
158
    end;
 
159
do_handle_options(_Access, _Bin, []) ->
 
160
    [].
 
161
 
 
162
 
 
163
handle_integer(Access, Bin, Key, Val, Options, Min, Max) ->
 
164
    case catch list_to_integer(Val) of
 
165
        {'EXIT', _} ->
 
166
            do_handle_options(Access, Bin, Options);
 
167
        Int when Int >= Min, Int =< Max ->
 
168
            [{Key, Val} | do_handle_options(Access, Bin, Options)];
 
169
        Int when Int >= Min, Max =:= infinity ->
 
170
            [{Key, Val} | do_handle_options(Access, Bin, Options)];
 
171
        _Int ->
 
172
            throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
 
173
    end.
 
174
 
 
175
lookup_blksize(Options) ->
 
176
    case lists:keysearch("blksize", 1, Options) of
 
177
        {value, {_, Val}} ->
 
178
            list_to_integer(Val);
 
179
        false ->
 
180
            512
 
181
    end.