How are transactions and blocks relayed? What is the protocol for relaying transactions and/or blocks in bitcoin? I realize that nodes never relay a transactions and blocks with a variety of properties (e.g., invalid transactions). This question is concerned more with the specific broadcast/relay protocol. In particular, are there any issues with broadcast loops and if so, how are they solved? Is it as simple as each node remembering which txs and blocks it has already transferred and never relaying twice? Thanks.
The Bitcoin protocol specification can be found on the Bitcoin Wiki. The Network wiki page has information on how information is relayed using the protocol.

Clients exchange messages over TCP/IP. With this messages, they can express their state of the blockchain and request others to send them parts they do not yet own. When you want to broadcast a new block or transaction, the inv message type is used to let people know you have the new data. Since no other client has that data already, it will request the data element using getdata. You will reply with a block or transaction message.

So basically, to reduce bandwidth usage, only an inv is truly relayed. Each node will then request the new data from one of the other nodes that broadcasted the inv.