A Discrete-Event Network Simulator
API
packet-socket.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2007 Emmanuelle Laprise, INRIA
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
19 * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20 */
21
22#include "packet-socket.h"
24#include "ns3/log.h"
25#include "ns3/node.h"
26#include "ns3/packet.h"
27#include "ns3/uinteger.h"
28#include "ns3/trace-source-accessor.h"
29
30#include <algorithm>
31
32namespace ns3 {
33
34NS_LOG_COMPONENT_DEFINE ("PacketSocket");
35
36NS_OBJECT_ENSURE_REGISTERED (PacketSocket);
37
38TypeId
40{
41 static TypeId tid = TypeId ("ns3::PacketSocket")
42 .SetParent<Socket> ()
43 .SetGroupName("Network")
44 .AddConstructor<PacketSocket> ()
45 .AddTraceSource ("Drop", "Drop packet due to receive buffer overflow",
47 "ns3::Packet::TracedCallback")
48 .AddAttribute ("RcvBufSize",
49 "PacketSocket maximum receive buffer size (bytes)",
50 UintegerValue (131072),
52 MakeUintegerChecker<uint32_t> ())
53 ;
54 return tid;
55}
56
57PacketSocket::PacketSocket () : m_rxAvailable (0)
58{
59 NS_LOG_FUNCTION (this);
61 m_shutdownSend = false;
62 m_shutdownRecv = false;
64 m_isSingleDevice = false;
65 m_device = 0;
66}
67
68void
70{
71 NS_LOG_FUNCTION (this << node);
72 m_node = node;
73}
74
76{
77 NS_LOG_FUNCTION (this);
78}
79
80void
82{
83 NS_LOG_FUNCTION (this);
84 m_device = 0;
85}
86
89{
90 NS_LOG_FUNCTION (this);
91 return m_errno;
92}
93
96{
97 NS_LOG_FUNCTION (this);
98 return NS3_SOCK_RAW;
99}
100
103{
104 NS_LOG_FUNCTION (this);
105 return m_node;
106}
107
108int
110{
111 NS_LOG_FUNCTION (this);
113 address.SetProtocol (0);
114 address.SetAllDevices ();
115 return DoBind (address);
116}
117
118int
120{
121 NS_LOG_FUNCTION (this);
122 return(Bind());
123}
124
125int
127{
128 NS_LOG_FUNCTION (this << address);
130 {
132 return -1;
133 }
135 return DoBind (ad);
136}
137
138int
140{
141 NS_LOG_FUNCTION (this << address);
142 if (m_state == STATE_BOUND ||
144 {
146 return -1;
147 }
148 if (m_state == STATE_CLOSED)
149 {
151 return -1;
152 }
153 Ptr<NetDevice> dev;
154 if (address.IsSingleDevice ())
155 {
156 dev = m_node->GetDevice (address.GetSingleDevice ());
157 }
158 else
159 {
160 dev = 0;
161 }
163 address.GetProtocol (), dev);
165 m_protocol = address.GetProtocol ();
166 m_isSingleDevice = address.IsSingleDevice ();
167 m_device = address.GetSingleDevice ();
168 m_boundnetdevice = dev;
169 return 0;
170}
171
172int
174{
175 NS_LOG_FUNCTION (this);
176 if (m_state == STATE_CLOSED)
177 {
179 return -1;
180 }
181 m_shutdownSend = true;
182 return 0;
183}
184
185int
187{
188 NS_LOG_FUNCTION (this);
189 if (m_state == STATE_CLOSED)
190 {
192 return -1;
193 }
194 m_shutdownRecv = true;
195 return 0;
196}
197
198int
200{
201 NS_LOG_FUNCTION (this);
202 if (m_state == STATE_CLOSED)
203 {
205 return -1;
206 }
207 else if (m_state == STATE_BOUND || m_state == STATE_CONNECTED)
208 {
210 }
212 m_shutdownSend = true;
213 m_shutdownRecv = true;
214 return 0;
215}
216
217int
219{
220 NS_LOG_FUNCTION (this << ad);
222 if (m_state == STATE_CLOSED)
223 {
225 goto error;
226 }
227 if (m_state == STATE_OPEN)
228 {
229 // connect should happen _after_ bind.
230 m_errno = ERROR_INVAL; // generic error condition.
231 goto error;
232 }
234 {
236 goto error;
237 }
239 {
241 goto error;
242 }
243 m_destAddr = ad;
246 return 0;
247error:
249 return -1;
250}
251int
253{
254 NS_LOG_FUNCTION (this);
256 return -1;
257}
258
259int
261{
262 NS_LOG_FUNCTION (this << p << flags);
263 if (m_state == STATE_OPEN ||
265 {
267 return -1;
268 }
269 return SendTo (p, flags, m_destAddr);
270}
271
274{
275 NS_LOG_FUNCTION (this << ad);
276 if (ad.IsSingleDevice ())
277 {
279 return device->GetMtu ();
280 }
281 else
282 {
283 uint32_t minMtu = 0xffff;
284 for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
285 {
286 Ptr<NetDevice> device = m_node->GetDevice (i);
287 minMtu = std::min (minMtu, (uint32_t)device->GetMtu ());
288 }
289 return minMtu;
290 }
291}
292
295{
296 NS_LOG_FUNCTION (this);
298 {
300 return GetMinMtu (ad);
301 }
302 // If we are not connected, we return a 'safe' value by default.
303 return 0xffff;
304}
305
306int
308{
309 NS_LOG_FUNCTION (this << p << flags << address);
311 if (m_state == STATE_CLOSED)
312 {
313 NS_LOG_LOGIC ("ERROR_BADF");
315 return -1;
316 }
317 if (m_shutdownSend)
318 {
319 NS_LOG_LOGIC ("ERROR_SHUTDOWN");
321 return -1;
322 }
324 {
325 NS_LOG_LOGIC ("ERROR_AFNOSUPPORT");
327 return -1;
328 }
330 if (p->GetSize () > GetMinMtu (ad))
331 {
333 return -1;
334 }
335
336 uint8_t priority = GetPriority ();
337 if (priority)
338 {
339 SocketPriorityTag priorityTag;
340 priorityTag.SetPriority (priority);
341 p->ReplacePacketTag (priorityTag);
342 }
343
344 bool error = false;
345 Address dest = ad.GetPhysicalAddress ();
346 uint32_t pktSize = p->GetSize (); // device->Send() may modify the packet
347 if (ad.IsSingleDevice ())
348 {
350 if (!device->Send (p, dest, ad.GetProtocol ()))
351 {
352 NS_LOG_LOGIC ("error: NetDevice::Send error");
353 error = true;
354 }
355 }
356 else
357 {
358 for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
359 {
360 Ptr<NetDevice> device = m_node->GetDevice (i);
361 if (!device->Send (p, dest, ad.GetProtocol ()))
362 {
363 NS_LOG_LOGIC ("error: NetDevice::Send error");
364 error = true;
365 }
366 }
367 }
368 if (!error)
369 {
372 }
373
374 if (error)
375 {
376 NS_LOG_LOGIC ("ERROR_INVAL 2");
378 return -1;
379 }
380 else
381 {
382 return pktSize;
383 }
384}
385
386void
388 uint16_t protocol, const Address &from,
389 const Address &to, NetDevice::PacketType packetType)
390{
391 NS_LOG_FUNCTION (this << device << packet << protocol << from << to << packetType);
392 if (m_shutdownRecv)
393 {
394 return;
395 }
397 address.SetPhysicalAddress (from);
398 address.SetSingleDevice (device->GetIfIndex ());
399 address.SetProtocol (protocol);
400
401 if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
402 {
403 Ptr<Packet> copy = packet->Copy ();
404 DeviceNameTag dnt;
405 dnt.SetDeviceName (device->GetTypeId ().GetName ());
406 PacketSocketTag pst;
407 pst.SetPacketType (packetType);
408 pst.SetDestAddress (to);
409 copy->AddPacketTag (pst); // Attach Packet Type and Dest Address
410 copy->AddPacketTag (dnt); // Attach device source name
411 // in case the packet still has a priority tag, remove it
412 SocketPriorityTag priorityTag;
413 copy->RemovePacketTag (priorityTag);
414 m_deliveryQueue.push (std::make_pair (copy, address));
415 m_rxAvailable += packet->GetSize ();
416 NS_LOG_LOGIC ("UID is " << packet->GetUid () << " PacketSocket " << this);
418 }
419 else
420 {
421 // In general, this case should not occur unless the
422 // receiving application reads data from this socket slowly
423 // in comparison to the arrival rate
424 //
425 // drop and trace packet
426 NS_LOG_WARN ("No receive buffer space available. Drop.");
427 m_dropTrace (packet);
428 }
429}
430
433{
434 NS_LOG_FUNCTION (this);
435 // We separately maintain this state to avoid walking the queue
436 // every time this might be called
437 return m_rxAvailable;
438}
439
442{
443 NS_LOG_FUNCTION (this << maxSize << flags);
444
445 Address fromAddress;
446 Ptr<Packet> packet = RecvFrom (maxSize, flags, fromAddress);
447 return packet;
448}
449
451PacketSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
452{
453 NS_LOG_FUNCTION (this << maxSize << flags);
454
455 if (m_deliveryQueue.empty () )
456 {
457 return 0;
458 }
459 Ptr<Packet> p = m_deliveryQueue.front ().first;
460 fromAddress = m_deliveryQueue.front ().second;
461
462 if (p->GetSize () <= maxSize)
463 {
464 m_deliveryQueue.pop ();
465 m_rxAvailable -= p->GetSize ();
466 }
467 else
468 {
469 p = 0;
470 }
471 return p;
472}
473
474int
476{
477 NS_LOG_FUNCTION (this << address);
479
482 {
484 ad.SetPhysicalAddress (device->GetAddress ());
486 }
487 else
488 {
490 ad.SetAllDevices ();
491 }
492 address = ad;
493
494 return 0;
495}
496
497int
499{
500 NS_LOG_FUNCTION (this << address);
501
503 {
505 return -1;
506 }
507
509
510 return 0;
511}
512
513bool
515{
516 NS_LOG_FUNCTION (this << allowBroadcast);
517 if (allowBroadcast)
518 {
519 return false;
520 }
521 return true;
522}
523
524bool
526{
527 NS_LOG_FUNCTION (this);
528 return false;
529}
530
531/***************************************************************
532 * PacketSocket Tags
533 ***************************************************************/
534
536{
537}
538
539void
541{
542 m_packetType = t;
543}
544
547{
548 return m_packetType;
549}
550
551void
553{
554 m_destAddr = a;
555}
556
559{
560 return m_destAddr;
561}
562
564
565TypeId
567{
568 static TypeId tid = TypeId ("ns3::PacketSocketTag")
569 .SetParent<Tag> ()
570 .SetGroupName("Network")
571 .AddConstructor<PacketSocketTag> ()
572 ;
573 return tid;
574}
575TypeId
577{
578 return GetTypeId ();
579}
582{
583 return 1 + m_destAddr.GetSerializedSize();
584}
585void
587{
590}
591void
593{
596}
597void
598PacketSocketTag::Print (std::ostream &os) const
599{
600 os << "packetType=" << m_packetType;
601}
602
603/***************************************************************
604 * DeviceName Tags
605 ***************************************************************/
606
608{
609}
610
611void
613{
614 if ( n.substr(0,5) == "ns3::" )
615 {
616 n = n.substr (5);
617 }
618 m_deviceName = n;
619}
620
621std::string
623{
624 return m_deviceName;
625}
626
628
629TypeId
631{
632 static TypeId tid = TypeId ("ns3::DeviceNameTag")
633 .SetParent<Tag> ()
634 .SetGroupName("Network")
635 .AddConstructor<DeviceNameTag> ();
636 return tid;
637}
638TypeId
640{
641 return GetTypeId ();
642}
645{
646 uint32_t s = 1 + m_deviceName.size(); // +1 for name length field
647 return s;
648}
649void
651{
652 const char *n = m_deviceName.c_str();
653 uint8_t l = (uint8_t) m_deviceName.size ();
654
655 i.WriteU8 (l);
656 i.Write ( (uint8_t*) n , (uint32_t) l);
657}
658void
660{
661 uint8_t l = i.ReadU8();
662 char buf[256];
663
664 i.Read ( (uint8_t* ) buf, (uint32_t) l);
665 m_deviceName = std::string (buf, l);
666}
667void
668DeviceNameTag::Print (std::ostream &os) const
669{
670 os << "DeviceName=" << m_deviceName;
671}
672
673
674} // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
a polymophic address class
Definition: address.h:91
void Serialize(TagBuffer buffer) const
Serialize this address in host byte order to a byte buffer.
Definition: address.cc:154
uint32_t GetSerializedSize(void) const
Get the number of bytes needed to serialize the underlying Address Typically, this is GetLength () + ...
Definition: address.cc:147
void Deserialize(TagBuffer buffer)
Definition: address.cc:163
This class implements a tag that carries the ns3 device name from where a packet is coming.
DeviceNameTag()
Create an empty DeviceNameTag.
virtual uint32_t GetSerializedSize(void) const
virtual void Serialize(TagBuffer i) const
virtual void Deserialize(TagBuffer i)
std::string m_deviceName
Device name.
static TypeId GetTypeId(void)
Get the type ID.
void SetDeviceName(std::string n)
Set the device name.
virtual void Print(std::ostream &os) const
virtual TypeId GetInstanceTypeId(void) const
Get the most derived TypeId for this Object.
std::string GetDeviceName(void) const
Get the device name from where the corresponding packet is coming.
static TypeId GetTypeId(void)
Get the type ID.
Definition: net-device.cc:30
virtual bool Send(Ptr< Packet > packet, const Address &dest, uint16_t protocolNumber)=0
virtual Address GetAddress(void) const =0
virtual uint32_t GetIfIndex(void) const =0
virtual uint16_t GetMtu(void) const =0
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:297
void UnregisterProtocolHandler(ProtocolHandler handler)
Definition: node.cc:263
uint32_t GetNDevices(void) const
Definition: node.cc:152
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:144
void RegisterProtocolHandler(ProtocolHandler handler, uint16_t protocolType, Ptr< NetDevice > device, bool promiscuous=false)
Definition: node.cc:229
bool RemovePacketTag(Tag &tag)
Remove a packet tag.
Definition: packet.cc:963
uint64_t GetUid(void) const
Returns the packet's Uid.
Definition: packet.cc:390
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:970
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
an address for a packet socket
bool IsSingleDevice(void) const
Checks if the address is bound to a specified NetDevice.
uint16_t GetProtocol(void) const
Get the protocol.
void SetProtocol(uint16_t protocol)
Set the protocol.
static bool IsMatchingType(const Address &address)
void SetPhysicalAddress(const Address address)
Set the destination address.
Address GetPhysicalAddress(void) const
Get the destination address.
void SetAllDevices(void)
Set the address to match all the outgoing NetDevice.
static PacketSocketAddress ConvertFrom(const Address &address)
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
uint32_t GetSingleDevice(void) const
Get the device this address is bound to.
A PacketSocket is a link between an application and a net device.
Definition: packet-socket.h:94
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)
Read a single packet from the socket and retrieve the sender address.
virtual int GetSockName(Address &address) const
Get socket address.
virtual bool SetAllowBroadcast(bool allowBroadcast)
Configure whether broadcast datagram transmissions are allowed.
virtual void DoDispose(void)
Destructor implementation.
virtual int Bind(void)
Bind the socket to the NetDevice and register the protocol handler.
Ptr< Node > m_node
the associated node
virtual int Send(Ptr< Packet > p, uint32_t flags)
Send data (or dummy data) to the remote host.
Address m_destAddr
Default destination address.
virtual int Listen(void)
Listen for incoming connections.
virtual int Connect(const Address &address)
Initiate a connection to a remote host.
uint32_t m_rxAvailable
Rx queue size [Bytes].
virtual uint32_t GetTxAvailable(void) const
Returns the number of bytes which can be sent in a single call to Send.
virtual uint32_t GetRxAvailable(void) const
Return number of bytes which can be returned from one or multiple calls to Recv.
std::queue< std::pair< Ptr< Packet >, Address > > m_deliveryQueue
Rx queue.
virtual int ShutdownSend(void)
virtual Ptr< Node > GetNode(void) const
Return the node this socket is associated with.
int DoBind(const PacketSocketAddress &address)
Bind the socket to the NetDevice and register the protocol handler specified in the address.
virtual int ShutdownRecv(void)
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)
Send data to a specified peer.
uint32_t m_rcvBufSize
Rx buffer size [Bytes].
virtual int Bind6(void)
Bind the socket to the NetDevice and register the protocol handler.
void ForwardUp(Ptr< NetDevice > device, Ptr< const Packet > packet, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
Called by the L3 protocol when it received a packet to pass on to TCP.
virtual enum SocketErrno GetErrno(void) const
Get last error number.
bool m_isSingleDevice
Is bound to a single netDevice.
virtual enum SocketType GetSocketType(void) const
virtual bool GetAllowBroadcast() const
Query whether broadcast datagram transmissions are allowed.
uint32_t GetMinMtu(PacketSocketAddress ad) const
Get the minimum MTU supported by the NetDevices bound to a specific address.
static TypeId GetTypeId(void)
Get the type ID.
uint16_t m_protocol
Socket protocol.
enum SocketErrno m_errno
Socket error code.
void SetNode(Ptr< Node > node)
Set the associated node.
virtual ~PacketSocket()
virtual int GetPeerName(Address &address) const
Get the peer address of a connected socket.
virtual int Close(void)
Close a socket.
bool m_shutdownSend
Send no longer allowed.
uint32_t m_device
index of the bound NetDevice
enum State m_state
Socket state.
TracedCallback< Ptr< const Packet > > m_dropTrace
Traced callback: dropped packets.
bool m_shutdownRecv
Receive no longer allowed.
This class implements a tag that carries the dest address of a packet and the packet type.
virtual void Print(std::ostream &os) const
Address m_destAddr
Destination address.
virtual void Serialize(TagBuffer i) const
virtual TypeId GetInstanceTypeId(void) const
Get the most derived TypeId for this Object.
NetDevice::PacketType GetPacketType(void) const
Get the packet type.
NetDevice::PacketType m_packetType
Packet type.
PacketSocketTag()
Create an empty PacketSocketTag.
static TypeId GetTypeId(void)
Get the type ID.
virtual uint32_t GetSerializedSize(void) const
void SetPacketType(NetDevice::PacketType t)
Set the packet type.
Address GetDestAddress(void) const
Get the destination address of the corresponding packet.
virtual void Deserialize(TagBuffer i)
void SetDestAddress(Address a)
Set the destination address of the corresponding packet.
A low-level Socket API based loosely on the BSD Socket API.
Definition: socket.h:67
uint8_t GetPriority(void) const
Query the priority value of this socket.
Definition: socket.cc:396
void NotifyConnectionSucceeded(void)
Notify through the callback (if set) that the connection has been established.
Definition: socket.cc:217
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:295
void NotifyConnectionFailed(void)
Notify through the callback (if set) that the connection has not been established due to an error.
Definition: socket.cc:227
SocketType
Enumeration of the possible socket types.
Definition: socket.h:104
@ NS3_SOCK_RAW
Definition: socket.h:108
void NotifyDataRecv(void)
Notify through the callback (if set) that some data have been received.
Definition: socket.cc:305
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition: socket.h:1077
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition: socket.h:82
@ ERROR_SHUTDOWN
Definition: socket.h:88
@ ERROR_INVAL
Definition: socket.h:91
@ ERROR_OPNOTSUPP
Definition: socket.h:89
@ ERROR_AFNOSUPPORT
Definition: socket.h:90
@ ERROR_BADF
Definition: socket.h:92
@ ERROR_NOTERROR
Definition: socket.h:83
@ ERROR_ISCONN
Definition: socket.h:84
@ ERROR_NOTCONN
Definition: socket.h:85
@ ERROR_MSGSIZE
Definition: socket.h:86
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:285
Ptr< Packet > Recv(void)
Read a single packet from the socket.
Definition: socket.cc:175
indicates whether the socket has a priority set.
Definition: socket.h:1309
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition: socket.cc:842
read and write tag data
Definition: tag-buffer.h:52
void Read(uint8_t *buffer, uint32_t size)
Definition: tag-buffer.cc:176
TAG_BUFFER_INLINE void WriteU8(uint8_t v)
Definition: tag-buffer.h:172
void Write(const uint8_t *buffer, uint32_t size)
Definition: tag-buffer.cc:125
TAG_BUFFER_INLINE uint8_t ReadU8(void)
Definition: tag-buffer.h:195
tag a set of bytes in a packet
Definition: tag.h:37
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
std::string GetName(void) const
Get the name.
Definition: type-id.cc:976
Hold an unsigned integer type.
Definition: uinteger.h:44
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:45
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
address
Definition: first.py:44
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
uint32_t pktSize
packet size used for the simulation (in bytes)
Definition: wifi-bianchi.cc:89