• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lextudio / sharpsnmplib / 19051900654

03 Nov 2025 10:45PM UTC coverage: 53.074% (+0.09%) from 52.986%
19051900654

push

github

lextm
Replace OperationException with ErrorException for response error handling in SNMP message extensions

874 of 1881 branches covered (46.46%)

Branch coverage included in aggregate %.

0 of 6 new or added lines in 2 files covered. (0.0%)

3 existing lines in 1 file now uncovered.

2389 of 4267 relevant lines covered (55.99%)

0.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.51
/SharpSnmpLib/Messaging/SnmpMessageExtension.cs
1
// SNMP message extension class.
2
// Copyright (C) 2008-2010 Malcolm Crowe, Lex Li, and other contributors.
3
// 
4
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
5
// software and associated documentation files (the "Software"), to deal in the Software
6
// without restriction, including without limitation the rights to use, copy, modify, merge,
7
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
8
// to whom the Software is furnished to do so, subject to the following conditions:
9
// 
10
// The above copyright notice and this permission notice shall be included in all copies or
11
// substantial portions of the Software.
12
// 
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
15
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
16
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
// DEALINGS IN THE SOFTWARE.
19

20
using System;
21
using System.Collections.Generic;
22
using System.Diagnostics.CodeAnalysis;
23
using System.Globalization;
24
using System.Net;
25
using System.Net.Sockets;
26
using System.Runtime.InteropServices;
27
using System.Threading.Tasks;
28
using Lextm.SharpSnmpLib.Security;
29

30
namespace Lextm.SharpSnmpLib.Messaging
31
{
32
    /// <summary>
33
    /// Extension methods for <see cref="ISnmpMessage"/>.
34
    /// </summary>
35
    public static partial class SnmpMessageExtension
36
    {
37
        /// <summary>
38
        /// Gets the <see cref="SnmpType"/>.
39
        /// </summary>
40
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
41
        /// <returns></returns>
42
        public static SnmpType TypeCode(this ISnmpMessage message)
43
        {
44
            if (message == null)
1!
45
            {
46
                throw new ArgumentNullException(nameof(message));
×
47
            }
48

49
            return message.Pdu().TypeCode;
1✔
50
        }
51

52
        /// <summary>
53
        /// Variables.
54
        /// </summary>
55
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
56
        public static IList<Variable> Variables(this ISnmpMessage message)
57
        {
58
            if (message == null)
1!
59
            {
60
                throw new ArgumentNullException(nameof(message));
×
61
            }
62

63
            var code = message.TypeCode();
1✔
64
            return code == SnmpType.Unknown ? new List<Variable>(0) : message.Scope.Pdu.Variables;
1!
65
        }
66

67
        /// <summary>
68
        /// Request ID.
69
        /// </summary>
70
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
71
        public static int RequestId(this ISnmpMessage message)
72
        {
73
            if (message == null)
1!
74
            {
75
                throw new ArgumentNullException(nameof(message));
×
76
            }
77

78
            return message.Scope.Pdu.RequestId.ToInt32();
1✔
79
        }
80

81
        /// <summary>
82
        /// Gets the message ID.
83
        /// </summary>
84
        /// <value>The message ID.</value>
85
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
86
        /// <remarks>For v3, message ID is different from request ID. For v1 and v2c, they are the same.</remarks>
87
        public static int MessageId(this ISnmpMessage message)
88
        {
89
            if (message == null)
1!
90
            {
91
                throw new ArgumentNullException(nameof(message));
×
92
            }
93

94
            return message.Header == Header.Empty ? message.RequestId() : message.Header.MessageId;
1!
95
        }
96

97
        /// <summary>
98
        /// PDU.
99
        /// </summary>
100
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
101
        public static ISnmpPdu Pdu(this ISnmpMessage message)
102
        {
103
            if (message == null)
1!
104
            {
105
                throw new ArgumentNullException(nameof(message));
×
106
            }
107

108
            return message.Scope.Pdu;
1✔
109
        }
110

111
        /// <summary>
112
        /// Community name.
113
        /// </summary>
114
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
115
        public static OctetString Community(this ISnmpMessage message)
116
        {
117
            if (message == null)
1!
118
            {
119
                throw new ArgumentNullException(nameof(message));
×
120
            }
121

122
            return message.Parameters.UserName;
1✔
123
        }
124

125
        #region sync methods
126

127
        /// <summary>
128
        /// Sends an <see cref="ISnmpMessage"/>.
129
        /// </summary>
130
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
131
        /// <param name="manager">Manager</param>
132
        public static void Send(this ISnmpMessage message, EndPoint manager)
133
        {
134
            if (message == null)
×
135
            {
136
                throw new ArgumentNullException(nameof(message));
×
137
            }
138

139
            if (manager == null)
×
140
            {
141
                throw new ArgumentNullException(nameof(manager));
×
142
            }
143

144
            var code = message.TypeCode();
×
145
            if ((code != SnmpType.TrapV1Pdu && code != SnmpType.TrapV2Pdu) && code != SnmpType.ReportPdu)
×
146
            {
147
                throw new InvalidOperationException(string.Format(
×
148
                    CultureInfo.InvariantCulture,
×
149
                    "not a trap message: {0}",
×
150
                    code));
×
151
            }
152

153
            using var socket = manager.GetSocket();
×
154
            message.Send(manager, socket);
×
155
        }
×
156

157
        /// <summary>
158
        /// Sends an <see cref="ISnmpMessage"/>.
159
        /// </summary>
160
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
161
        /// <param name="manager">Manager</param>
162
        /// <param name="socket">The socket.</param>
163
        public static void Send(this ISnmpMessage message, EndPoint manager, Socket socket)
164
        {
165
            if (message == null)
×
166
            {
167
                throw new ArgumentNullException(nameof(message));
×
168
            }
169

170
            if (socket == null)
×
171
            {
172
                throw new ArgumentNullException(nameof(socket));
×
173
            }
174

175
            if (manager == null)
×
176
            {
177
                throw new ArgumentNullException(nameof(manager));
×
178
            }
179

180
            var code = message.TypeCode();
×
181
            if ((code != SnmpType.TrapV1Pdu && code != SnmpType.TrapV2Pdu) && code != SnmpType.ReportPdu)
×
182
            {
183
                throw new InvalidOperationException(string.Format(
×
184
                    CultureInfo.InvariantCulture,
×
185
                    "not a trap message: {0}",
×
186
                    code));
×
187
            }
188

189
            var bytes = message.ToBytes();
×
190
            socket.SendTo(bytes, 0, bytes.Length, SocketFlags.None, manager);
×
191
        }
×
192

193
        /// <summary>
194
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
195
        /// </summary>
196
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
197
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
198
        /// <param name="receiver">Port number.</param>
199
        /// <param name="registry">User registry.</param>
200
        /// <returns></returns>
201
#if NET6_0_OR_GREATER
202
        [RequiresUnreferencedCode("GetResponse is incompatible with trimming.")]
203
#endif
204
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver, UserRegistry registry)
205
        {
206
            // TODO: make more usage of UserRegistry.
207
            if (request == null)
×
208
            {
209
                throw new ArgumentNullException(nameof(request));
×
210
            }
211

212
            if (receiver == null)
×
213
            {
214
                throw new ArgumentNullException(nameof(receiver));
×
215
            }
216

217
            var code = request.TypeCode();
×
218
            if (code == SnmpType.TrapV1Pdu || code == SnmpType.TrapV2Pdu || code == SnmpType.ReportPdu)
×
219
            {
220
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", code));
×
221
            }
222

223
            using var socket = receiver.GetSocket();
×
224
            return request.GetResponse(timeout, receiver, registry, socket);
×
225
        }
×
226

227
        /// <summary>
228
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
229
        /// </summary>
230
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
231
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
232
        /// <param name="receiver">Port number.</param>
233
        /// <returns></returns>
234
#if NET6_0_OR_GREATER
235
        [RequiresUnreferencedCode("GetResponse is incompatible with trimming.")]
236
#endif
237
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver)
238
        {
239
            if (request == null)
×
240
            {
241
                throw new ArgumentNullException(nameof(request));
×
242
            }
243

244
            if (receiver == null)
×
245
            {
246
                throw new ArgumentNullException(nameof(receiver));
×
247
            }
248

249
            var code = request.TypeCode();
×
250
            if (code == SnmpType.TrapV1Pdu || code == SnmpType.TrapV2Pdu || code == SnmpType.ReportPdu)
×
251
            {
252
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", code));
×
253
            }
254

255
            using var socket = receiver.GetSocket();
×
256
            return request.GetResponse(timeout, receiver, socket);
×
257
        }
×
258

259
        /// <summary>
260
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
261
        /// </summary>
262
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
263
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
264
        /// <param name="receiver">Agent.</param>
265
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
266
        /// <returns></returns>
267
#if NET6_0_OR_GREATER
268
        [RequiresUnreferencedCode("GetResponse is incompatible with trimming.")]
269
#endif
270
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver, Socket udpSocket)
271
        {
272
            if (request == null)
×
273
            {
274
                throw new ArgumentNullException(nameof(request));
×
275
            }
276

277
            if (receiver == null)
×
278
            {
279
                throw new ArgumentNullException(nameof(receiver));
×
280
            }
281

282
            if (udpSocket == null)
×
283
            {
284
                throw new ArgumentNullException(nameof(udpSocket));
×
285
            }
286

287
            var registry = new UserRegistry();
×
288
            if (request.Version == VersionCode.V3)
×
289
            {
290
                registry.Add(request.Parameters.UserName, request.Privacy);
×
291
            }
292

293
            return request.GetResponse(timeout, receiver, registry, udpSocket);
×
294
        }
295

296
        /// <summary>
297
        /// Sends an  <see cref="ISnmpMessage"/> and handles the response from agent.
298
        /// </summary>
299
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
300
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
301
        /// <param name="receiver">Agent.</param>
302
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
303
        /// <param name="registry">The user registry.</param>
304
        /// <returns></returns>
305
#if NET6_0_OR_GREATER
306
        [RequiresUnreferencedCode("GetResponse is incompatible with trimming.")]
307
#endif
308
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver, UserRegistry registry, Socket udpSocket)
309
        {
310
            if (request == null)
×
311
            {
312
                throw new ArgumentNullException(nameof(request));
×
313
            }
314

315
            if (udpSocket == null)
×
316
            {
317
                throw new ArgumentNullException(nameof(udpSocket));
×
318
            }
319

320
            if (receiver == null)
×
321
            {
322
                throw new ArgumentNullException(nameof(receiver));
×
323
            }
324

325
            if (registry == null)
×
326
            {
327
                throw new ArgumentNullException(nameof(registry));
×
328
            }
329

330
            var requestCode = request.TypeCode();
×
331
            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
×
332
            {
333
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
×
334
            }
335

336
            var bytes = request.ToBytes();
×
337
            var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;
×
338
            var reply = new byte[bufSize];
×
339

340
            // Whatever you change, try to keep the Send and the Receive close to each other.
341
            udpSocket.SendTo(bytes, receiver);
×
342
            udpSocket.ReceiveTimeout = timeout;
×
343
            int count;
344
            try
345
            {
346
                count = udpSocket.Receive(reply, 0, bufSize, SocketFlags.None);
×
347
            }
×
348
            catch (SocketException ex)
×
349
            {
350
                // IMPORTANT: Mono behavior.
351
                if (IsRunningOnMono() && ex.SocketErrorCode == SocketError.WouldBlock)
×
352
                {
353
                    throw TimeoutException.Create(receiver.Address, timeout);
×
354
                }
355

356

357
                if (ex.SocketErrorCode == SocketError.TimedOut)
×
358
                {
359
                    throw TimeoutException.Create(receiver.Address, timeout);
×
360
                }
361

362
                throw;
×
363
            }
364

365
            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
366
            var response = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
×
367
            var responseCode = response.TypeCode();
×
368
            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
×
369
            {
370
                var requestId = request.MessageId();
×
371
                var responseId = response.MessageId();
×
372
                if (responseId != requestId)
×
373
                {
NEW
374
                    throw ErrorException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address, response);
×
375
                }
376

377
                return response;
×
378
            }
379

NEW
380
            throw ErrorException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address, response);
×
381
        }
382

383
        #endregion
384

385
        #region async methods
386

387
        /// <summary>
388
        /// Sends an <see cref="ISnmpMessage"/>.
389
        /// </summary>
390
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
391
        /// <param name="manager">Manager</param>
392
        public static async Task SendAsync(this ISnmpMessage message, EndPoint manager)
393
        {
394
            if (message == null)
×
395
            {
396
                throw new ArgumentNullException(nameof(message));
×
397
            }
398

399
            if (manager == null)
×
400
            {
401
                throw new ArgumentNullException(nameof(manager));
×
402
            }
403

404
            var code = message.TypeCode();
×
405
            if ((code != SnmpType.TrapV1Pdu && code != SnmpType.TrapV2Pdu) && code != SnmpType.ReportPdu)
×
406
            {
407
                throw new InvalidOperationException(string.Format(
×
408
                    CultureInfo.InvariantCulture,
×
409
                    "not a trap message: {0}",
×
410
                    code));
×
411
            }
412

413
            using var socket = manager.GetSocket();
×
414
            await message.SendAsync(manager, socket).ConfigureAwait(false);
×
415
        }
×
416

417
        /// <summary>
418
        /// Sends an <see cref="ISnmpMessage"/>.
419
        /// </summary>
420
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
421
        /// <param name="manager">Manager</param>
422
        /// <param name="socket">The socket.</param>
423
        public static async Task SendAsync(this ISnmpMessage message, EndPoint manager, Socket socket)
424
        {
425
            if (message == null)
×
426
            {
427
                throw new ArgumentNullException(nameof(message));
×
428
            }
429

430
            if (socket == null)
×
431
            {
432
                throw new ArgumentNullException(nameof(socket));
×
433
            }
434

435
            if (manager == null)
×
436
            {
437
                throw new ArgumentNullException(nameof(manager));
×
438
            }
439

440
            var code = message.TypeCode();
×
441
            if ((code != SnmpType.TrapV1Pdu && code != SnmpType.TrapV2Pdu) && code != SnmpType.ReportPdu)
×
442
            {
443
                throw new InvalidOperationException(string.Format(
×
444
                    CultureInfo.InvariantCulture,
×
445
                    "not a trap message: {0}",
×
446
                    code));
×
447
            }
448

449
            var buffer = new ArraySegment<byte>(message.ToBytes());
×
450
            await socket.SendToAsync(buffer, SocketFlags.None, manager);
×
451
        }
×
452

453
        /// <summary>
454
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
455
        /// </summary>
456
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
457
        /// <param name="receiver">Port number.</param>
458
        /// <param name="registry">User registry.</param>
459
        /// <returns></returns>
460
#if NET6_0_OR_GREATER
461
        [RequiresUnreferencedCode("GetResponseAsync is incompatible with trimming.")]
462
#endif
463
        public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, UserRegistry registry)
464
        {
465
            // TODO: make more usage of UserRegistry.
466
            if (request == null)
×
467
            {
468
                throw new ArgumentNullException(nameof(request));
×
469
            }
470

471
            if (receiver == null)
×
472
            {
473
                throw new ArgumentNullException(nameof(receiver));
×
474
            }
475

476
            var code = request.TypeCode();
×
477
            if (code == SnmpType.TrapV1Pdu || code == SnmpType.TrapV2Pdu || code == SnmpType.ReportPdu)
×
478
            {
479
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", code));
×
480
            }
481

482
            using var socket = receiver.GetSocket();
×
483
            return await request.GetResponseAsync(receiver, registry, socket).ConfigureAwait(false);
×
484
        }
×
485

486
        /// <summary>
487
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
488
        /// </summary>
489
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
490
        /// <param name="receiver">Port number.</param>
491
        /// <returns></returns>
492
#if NET6_0_OR_GREATER
493
        [RequiresUnreferencedCode("GetResponseAsync is incompatible with trimming.")]
494
#endif
495
        public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver)
496
        {
497
            if (request == null)
×
498
            {
499
                throw new ArgumentNullException(nameof(request));
×
500
            }
501

502
            if (receiver == null)
×
503
            {
504
                throw new ArgumentNullException(nameof(receiver));
×
505
            }
506

507
            var code = request.TypeCode();
×
508
            if (code == SnmpType.TrapV1Pdu || code == SnmpType.TrapV2Pdu || code == SnmpType.ReportPdu)
×
509
            {
510
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", code));
×
511
            }
512

513
            using var socket = receiver.GetSocket();
×
514
            return await request.GetResponseAsync(receiver, socket).ConfigureAwait(false);
×
515
        }
×
516

517
        /// <summary>
518
        /// Sends this <see cref="ISnmpMessage"/> and handles the response from agent.
519
        /// </summary>
520
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
521
        /// <param name="receiver">Agent.</param>
522
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
523
        /// <returns></returns>
524
#if NET6_0_OR_GREATER
525
        [RequiresUnreferencedCode("GetResponseAsync is incompatible with trimming.")]
526
#endif
527
        public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, Socket udpSocket)
528
        {
529
            if (request == null)
×
530
            {
531
                throw new ArgumentNullException(nameof(request));
×
532
            }
533

534
            if (receiver == null)
×
535
            {
536
                throw new ArgumentNullException(nameof(receiver));
×
537
            }
538

539
            if (udpSocket == null)
×
540
            {
541
                throw new ArgumentNullException(nameof(udpSocket));
×
542
            }
543

544
            var registry = new UserRegistry();
×
545
            if (request.Version == VersionCode.V3)
×
546
            {
547
                registry.Add(request.Parameters.UserName, request.Privacy);
×
548
            }
549

550
            return await request.GetResponseAsync(receiver, registry, udpSocket).ConfigureAwait(false);
×
551
        }
×
552

553
        /// <summary>
554
        /// Sends an <see cref="ISnmpMessage"/> and handles the response from agent.
555
        /// </summary>
556
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
557
        /// <param name="receiver">Agent.</param>
558
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
559
        /// <param name="registry">The user registry.</param>
560
        /// <returns></returns>
561
#if NET6_0_OR_GREATER
562
        [RequiresUnreferencedCode("GetResponseAsync is incompatible with trimming.")]
563
#endif
564
        public static async Task<ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, UserRegistry registry, Socket udpSocket)
565
        {
566
            if (request == null)
×
567
            {
568
                throw new ArgumentNullException(nameof(request));
×
569
            }
570

571
            if (udpSocket == null)
×
572
            {
573
                throw new ArgumentNullException(nameof(udpSocket));
×
574
            }
575

576
            if (registry == null)
×
577
            {
578
                throw new ArgumentNullException(nameof(registry));
×
579
            }
580

581
            var requestCode = request.TypeCode();
×
582
            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
×
583
            {
584
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
×
585
            }
586

587
            var bytes = request.ToBytes();
×
588
            var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;
×
589

590
            // Whatever you change, try to keep the Send and the Receive close to each other.
591
            var buffer = new ArraySegment<byte>(bytes);
×
592
            await udpSocket.SendToAsync(buffer, SocketFlags.None, receiver ?? throw new ArgumentNullException(nameof(receiver)));
×
593

594
            int count;
595
            byte[] reply = new byte[bufSize];
×
596

597
            // IMPORTANT: follow http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
598
            var remoteAddress = udpSocket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any;
×
599
            EndPoint remote = new IPEndPoint(remoteAddress, 0);
×
600

601
            try
602
            {
603
                var result = await udpSocket.ReceiveMessageFromAsync(new ArraySegment<byte>(reply), SocketFlags.None, remote);
×
604
                count = result.ReceivedBytes;
×
605
            }
×
606
            catch (SocketException ex)
×
607
            {
608
                // IMPORTANT: Mono behavior (https://bugzilla.novell.com/show_bug.cgi?id=599488)
609
                if (IsRunningOnMono() && ex.SocketErrorCode == SocketError.WouldBlock)
×
610
                {
611
                    throw TimeoutException.Create(receiver.Address, 0);
×
612
                }
613

614
                if (ex.SocketErrorCode == SocketError.TimedOut)
×
615
                {
616
                    throw TimeoutException.Create(receiver.Address, 0);
×
617
                }
618

619
                throw;
×
620
            }
621

622
            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
623
            var response = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
×
624
            var responseCode = response.TypeCode();
×
625
            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
×
626
            {
627
                var requestId = request.MessageId();
×
628
                var responseId = response.MessageId();
×
629
                if (responseId != requestId)
×
630
                {
NEW
631
                    throw ErrorException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address, response);
×
632
                }
633

634
                return response;
×
635
            }
636

NEW
637
            throw ErrorException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address, response);
×
638
        }
×
639

640
        #endregion
641

642
        /// <summary>
643
        /// Tests if running on Mono.
644
        /// </summary>
645
        /// <returns></returns>
646
#if NET6_0_OR_GREATER
647

648
        [RequiresUnreferencedCode("IsRunningOnMono is incompatible with trimming.")]
649
#endif
650
        public static bool IsRunningOnMono()
651
        {
652
            return Type.GetType("Mono.Runtime") != null;
×
653
        }
654

655
        /// <summary>
656
        /// Gets a value indicating whether it is
657
        /// running on Windows.
658
        /// </summary>
659
        /// <value><c>true</c> if is running on Windows; otherwise, <c>false</c>.</value>
660
        public static bool IsRunningOnWindows
661
        {
662
            get
663
            {
664
#if NET471
665
                return !IsRunningOnMono();
666
#elif NET6_0_OR_GREATER
667
                return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
×
668
#else
669
                return false;
670
#endif
671
            }
672
        }
673

674
        /// <summary>
675
        /// Gets a value indicating whether it is running on macOS.
676
        /// </summary>
677
        /// <value><c>true</c> if is running on macOS; otherwise, <c>false</c>.</value>
678
        public static bool IsRunningOnMac
679
        {
680
            get
681
            {
682
#if NET471
683
                return IsRunningOnMono();
684
#elif NET6_0_OR_GREATER
685
                return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
×
686
#else
687
                return false;
688
#endif
689
            }
690
        }
691

692
        /// <summary>
693
        /// Gets a value indicating whether it is running on iOS.
694
        /// </summary>
695
        /// <value><c>true</c> if is running on iOS; otherwise, <c>false</c>.</value>
696

697
        public static bool IsRunningOnIOS
698
        {
699
            get
700
            {
701
#if NET471
702
                return false;
703
#elif NET6_0_OR_GREATER
704
                return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
×
705
#else
706
                return false;
707
#endif
708
            }
709
        }
710

711
        /// <summary>
712
        /// Packs up the <see cref="ISnmpMessage"/>.
713
        /// </summary>
714
        /// <param name="message">The <see cref="ISnmpMessage"/>.</param>
715
        /// <param name="length">The length bytes.</param>
716
        /// <returns></returns>
717
        internal static Sequence PackMessage(this ISnmpMessage message, byte[]? length)
718
        {
719
            if (message == null)
1!
720
            {
721
                throw new ArgumentNullException(nameof(message));
×
722
            }
723

724
            return ByteTool.PackMessage(
1✔
725
                length,
1✔
726
                message.Version,
1✔
727
                message.Header,
1✔
728
                message.Parameters,
1✔
729
                message.Privacy.GetScopeData(message.Header, message.Parameters, message.Scope.GetData(message.Version)));
1✔
730
        }
731
    }
732
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc